--- loncom/interface/lonuserutils.pm 2013/08/29 12:35:32 1.154 +++ loncom/interface/lonuserutils.pm 2019/05/04 19:57:29 1.196 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Utility functions for managing LON-CAPA user accounts # -# $Id: lonuserutils.pm,v 1.154 2013/08/29 12:35:32 raeburn Exp $ +# $Id: lonuserutils.pm,v 1.196 2019/05/04 19:57:29 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -30,12 +30,29 @@ package Apache::lonuserutils; +=pod + +=head1 NAME + +Apache::lonuserutils.pm + +=head1 SYNOPSIS + + Utilities for management of users and custom roles + + Provides subroutines called by loncreateuser.pm + +=head1 OVERVIEW + +=cut + use strict; use Apache::lonnet; use Apache::loncommon(); use Apache::lonhtmlcommon; use Apache::lonlocal; use Apache::longroup; +use HTML::Entities; use LONCAPA qw(:DEFAULT :match); ############################################################### @@ -401,7 +418,7 @@ sub javascript_validations { my $showcredits; my %domdefaults = &Apache::lonnet::get_domain_defaults($domain); - if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'}) { + if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'}) { $showcredits = 1; } @@ -421,7 +438,7 @@ sub javascript_validations { } elsif ($context eq 'domain') { $setsection_call = 'setCourse()'; $setsections_js = &dc_setcourse_js($param{'formname'},$mode, - $context,$showcredits); + $context,$showcredits,$domain); } $finish = " var checkSec = $setsection_call\n". " if (checkSec == 'ok') {\n". @@ -450,6 +467,7 @@ sub javascript_validations { if (($mode eq 'upload') && ($context eq 'domain')) { $alert{'inststatus'} = &mt('The optional affiliation field was not specified'); } + &js_escape(\%alert); my $function_name = <<"END"; $setsections_js @@ -513,21 +531,26 @@ END /* regexp here to check for non \d \. in credits */ END } else { + my ($numrules,$intargjs) = + &passwd_validation_js('vf.elements[current.argfield].value',$domain); $auth_checks .= (<<END); foundatype=1; if (current.argfield == null || current.argfield == '') { + // The login radiobutton checked does not have an associated textbox + } else if (vf.elements[current.argfield].value == '') { var alertmsg = ''; switch (current.radiovalue) { case 'krb': alertmsg = '$alert{'krb'}'; break; case 'loc': - case 'fsys': + case 'int': alertmsg = '$alert{'ipass'}'; break; case 'fsys': - alertmsg = ''; + alertmsg = '$alert{'ipass'}'; break; + case 'lti': default: alertmsg = ''; } @@ -535,6 +558,10 @@ END alert(alertmsg); return; } + } else if (current.radiovalue == 'int') { + if ($numrules > 0) { +$intargjs + } } END } @@ -623,6 +650,136 @@ END $section_checks.$authheader; return $result; } + +sub passwd_validation_js { + my ($currpasswdval,$domain) = @_; + my %passwdconf = &Apache::lonnet::get_passwdconf($domain); + my ($min,$max,@chars,$numrules,$intargjs,%alert); + $numrules = 0; + if (ref($passwdconf{'chars'}) eq 'ARRAY') { + if ($passwdconf{'min'} =~ /^\d+$/) { + $min = $passwdconf{'min'}; + $numrules ++; + } + if ($passwdconf{'max'} =~ /^\d+$/) { + $max = $passwdconf{'max'}; + $numrules ++; + } + @chars = @{$passwdconf{'chars'}}; + if (@chars) { + $numrules ++; + } + } else { + $min = 7; + $numrules ++; + } + if (($min ne '') || ($max ne '') || (@chars > 0)) { + my $alertmsg = &mt('Initial password did not satisfy requirement(s):').'\n\n'; + if ($min) { + $alert{'min'} = &mt('minimum [quant,_1,character]',$min).'\n'; + } + if ($max) { + $alert{'max'} = &mt('maximum [quant,_1,character]',$max).'\n'; + } + my (@charalerts,@charrules); + if (@chars) { + if (grep(/^uc$/,@chars)) { + push(@charalerts,&mt('contain at least one upper case letter')); + push(@charrules,'uc'); + } + if (grep(/^lc$/,@chars)) { + push(@charalerts,&mt('contain at least one lower case letter')); + push(@charrules,'lc'); + } + if (grep(/^num$/,@chars)) { + push(@charalerts,&mt('contain at least one number')); + push(@charrules,'num'); + } + if (grep(/^spec$/,@chars)) { + push(@charalerts,&mt('contain at least one non-alphanumeric')); + push(@charrules,'spec'); + } + } + $intargjs = qq| var rulesmsg = '';\n|. + qq| var currpwval = $currpasswdval;\n|; + if ($min) { + $intargjs .= qq| + if (currpwval.length < $min) { + rulesmsg += ' - $alert{min}'; + } +|; + } + if ($max) { + $intargjs .= qq| + if (currpwval.length > $max) { + rulesmsg += ' - $alert{max}'; + } +|; + } + if (@chars > 0) { + my $charrulestr = '"'.join('","',@charrules).'"'; + my $charalertstr = '"'.join('","',@charalerts).'"'; + $intargjs .= qq| var brokerules = new Array();\n|. + qq| var charrules = new Array($charrulestr);\n|. + qq| var charalerts = new Array($charalertstr);\n|; + my %rules; + map { $rules{$_} = 1; } @chars; + if ($rules{'uc'}) { + $intargjs .= qq| + var ucRegExp = /[A-Z]/; + if (!ucRegExp.test(currpwval)) { + brokerules.push('uc'); + } +|; + } + if ($rules{'lc'}) { + $intargjs .= qq| + var lcRegExp = /[a-z]/; + if (!lcRegExp.test(currpwval)) { + brokerules.push('lc'); + } +|; + } + if ($rules{'num'}) { + $intargjs .= qq| + var numRegExp = /[0-9]/; + if (!numRegExp.test(currpwval)) { + brokerules.push('num'); + } +|; + } + if ($rules{'spec'}) { + $intargjs .= q| + var specRegExp = /[!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{\|}~]/; + if (!specRegExp.test(currpwval)) { + brokerules.push('spec'); + } +|; + } + $intargjs .= qq| + if (brokerules.length > 0) { + for (var i=0; i<brokerules.length; i++) { + for (var j=0; j<charrules.length; j++) { + if (brokerules[i] == charrules[j]) { + rulesmsg += ' - '+charalerts[j]+'\\n'; + break; + } + } + } + } +|; + } + $intargjs .= qq| + if (rulesmsg != '') { + rulesmsg = '$alertmsg'+rulesmsg; + alert(rulesmsg); + return; + } +|; + } + return ($numrules,$intargjs); +} + ############################################################### ############################################################### sub upload_manager_javascript_forward_associate { @@ -642,8 +799,9 @@ sub upload_manager_javascript_forward_as $numbuttons ++; } if (!$can_assign->{'int'}) { - my $warning = &mt('You may not specify an initial password for each user, as this is only available when new users use LON-CAPA internal authentication.').'\n' + my $warning = &mt('You may not specify an initial password for each user, as this is only available when new users use LON-CAPA internal authentication.')."\n". &mt('Your current role does not have rights to create users with that authentication type.'); + &js_escape(\$warning); $auth_update = <<"END"; // Currently the initial password field is only supported for internal auth // (see bug 6368). @@ -781,6 +939,7 @@ sub upload_manager_javascript_reverse_as if (!$can_assign->{'int'}) { my $warning = &mt('You may not specify an initial password, as this is only available when new users use LON-CAPA internal authentication.\n'). &mt('Your current role does not have rights to create users with that authentication type.'); + &js_escape(\$warning); $auth_update = <<"END"; // Currently the initial password field is only supported for internal auth // (see bug 6368). @@ -878,6 +1037,7 @@ sub print_upload_manager_footer { my $krbform = &Apache::loncommon::authform_kerberos(%param); my $intform = &Apache::loncommon::authform_internal(%param); my $locform = &Apache::loncommon::authform_local(%param); + my $ltiform = &Apache::loncommon::authform_lti(%param); my $date_table = &date_setting_table(undef,undef,$context,undef, $formname,$permission,$crstype); @@ -906,7 +1066,7 @@ sub print_upload_manager_footer { &Apache::loncommon::help_open_topic('Auth_Options'). "</p>\n"; } - $Str .= &set_login($defdom,$krbform,$intform,$locform); + $Str .= &set_login($defdom,$krbform,$intform,$locform,$ltiform); my ($home_server_pick,$numlib) = &Apache::loncommon::home_server_form_item($defdom,'lcserver', @@ -923,8 +1083,14 @@ sub print_upload_manager_footer { &Apache::lonhtmlcommon::row_closure(); } + my ($trusted,$untrusted); + if ($context eq 'course') { + ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('enroll',$defdom); + } elsif ($context eq 'author') { + ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('othcoau',$defdom); + } $Str .= &Apache::lonhtmlcommon::row_title(&mt('Default domain')) - .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1) + .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1,undef,$trusted,$untrusted) .&Apache::lonhtmlcommon::row_closure(); $Str .= &Apache::lonhtmlcommon::row_title(&mt('Starting and Ending Dates')) @@ -1013,7 +1179,9 @@ sub print_upload_manager_footer { .&Apache::lonhtmlcommon::row_closure(); } if ($context eq 'course' || $context eq 'domain') { - $Str .= &forceid_change($context); + $Str .= &Apache::lonhtmlcommon::row_title(&mt('Student/Employee ID')) + .&forceid_change($context) + .&Apache::lonhtmlcommon::row_closure(1); # last row in pick_box } $Str .= &Apache::lonhtmlcommon::end_pick_box(); @@ -1047,10 +1215,12 @@ sub get_defaultcredits { return unless(($cdom =~ /^$match_domain$/) && ($cnum =~ /^$match_courseid$/)); my ($defaultcredits,$domdefcredits); my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom); - if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'}) { + if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'}) { my $instcode = $env{'course.'.$cdom.'_'.$cnum.'.internal.coursecode'}; if ($instcode) { $domdefcredits = $domdefaults{'officialcredits'}; + } elsif ($env{'course.'.$cdom.'_'.$cnum.'.internal.textbook'}) { + $domdefcredits = $domdefaults{'textbookcredits'}; } else { $domdefcredits = $domdefaults{'unofficialcredits'}; } @@ -1076,18 +1246,15 @@ sub get_defaultcredits { sub forceid_change { my ($context) = @_; my $output = - &Apache::lonhtmlcommon::row_title(&mt('Student/Employee ID')) - .'<label><input type="checkbox" name="forceid" value="yes" />' - .&mt('Disable Student/Employee ID Safeguard and force change of conflicting IDs') - .'</label><br />'."\n" - .&mt('(only do if you know what you are doing.)')."\n"; + '<label><input type="checkbox" name="forceid" value="yes" />' + .&mt('Force change of existing ID') + .'</label>'.&Apache::loncommon::help_open_topic('ForceIDChange')."\n"; if ($context eq 'domain') { - $output .= '<br /><label><input type="checkbox" name="recurseid"'. - ' value="yes" />'. - &mt('Update student/employee ID in courses in which user is active/future student,[_1](if forcing change).','<br />'). - '</label>'."\n"; + $output .= + '<br />' + .'<label><input type="checkbox" name="recurseid" value="yes" />' + .&mt("Update ID in user's course(s).").'</label>'."\n"; } - $output .= &Apache::lonhtmlcommon::row_closure(1); # last row in pick_box return $output; } @@ -1100,8 +1267,15 @@ sub print_upload_manager_form { if (!$env{'form.datatoken'}) { $datatoken=&Apache::loncommon::upfile_store($r); } else { - $datatoken=$env{'form.datatoken'}; - &Apache::loncommon::load_tmp_file($r); + $datatoken=&Apache::loncommon::valid_datatoken($env{'form.datatoken'}); + if ($datatoken ne '') { + &Apache::loncommon::load_tmp_file($r,$datatoken); + } + } + if ($datatoken eq '') { + $r->print('<p class="LC_error">'.&mt('Error').': '. + &mt('Invalid datatoken').'</p>'); + return 'missingdata'; } my @records=&Apache::loncommon::upfile_record_sep(); if($env{'form.noFirstLine'}){ @@ -1185,6 +1359,7 @@ sub print_upload_manager_form { } &print_upload_manager_footer($r,$i,$keyfields,$defdom,$today,$halfyear, $context,$permission,$crstype,$showcredits); + return 'ok'; } sub setup_date_selectors { @@ -1392,9 +1567,9 @@ sub default_role_selector { &default_course_roles($context,$checkpriv,'Course',%customroles)."\n". '</select></td><td>'. '<table class="LC_createuser">'. - '<tr class="LC_section_row"><td valign"top">'. + '<tr class="LC_section_row"><td valign="top">'. $lt{'exs'}.'<br /><select name="currsec">'. - ' <option value=""><--'.&mt('Pick course first'). + ' <option value=""><--'.&mt('Pick course first'). '</select></td>'. '<td> </td>'. '<td valign="top">'.$lt{'new'}.'<br />'. @@ -1526,10 +1701,10 @@ sub curr_role_permissions { # ======================================================= Existing Custom Roles sub my_custom_roles { - my ($crstype) = @_; + my ($crstype,$udom,$uname) = @_; my %returnhash=(); my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1}); - my %rolehash=&Apache::lonnet::dump('roles'); + my %rolehash=&Apache::lonnet::dump('roles',$udom,$uname); foreach my $key (keys(%rolehash)) { if ($key=~/^rolesdef\_(\w+)$/) { if ($crstype eq 'Community') { @@ -1637,7 +1812,7 @@ sub print_userlist { return; } my ($indexhash,$keylist) = &make_keylist_array(); - my (%userlist,%userinfo,$clearcoursepick); + my (%userlist,%userinfo,$clearcoursepick,$needauthorquota,$needauthorusage); if (($context eq 'domain') && ($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')) { @@ -1709,6 +1884,12 @@ sub print_userlist { \%cstr_roles,$permission); } elsif ($context eq 'domain') { if ($env{'form.roletype'} eq 'domain') { + if (grep(/^authorusage$/,@cols)) { + $needauthorusage = 1; + } + if (grep(/^authorquota$/,@cols)) { + $needauthorquota = 1; + } %dom_roles = &Apache::lonnet::get_domain_roles($env{'request.role.domain'}); foreach my $key (keys(%dom_roles)) { if (ref($dom_roles{$key}) eq 'HASH') { @@ -1821,7 +2002,7 @@ sub print_userlist { } else { ($usercount) = &show_users_list($r,$context,$env{'form.output'}, $permission,$env{'form.Status'},\%userlist, - $keylist,'',$showcredits); + $keylist,'',$showcredits,$needauthorquota,$needauthorusage); } if (!$usercount) { $r->print('<br /><span class="LC_info">' @@ -1988,10 +2169,10 @@ sub get_cols_array { } if (($context eq 'course') && ($mode ne 'autoenroll') && ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'})) { - push(@cols,'photos'); + push(@cols,'photo'); } if ($context eq 'domain') { - push (@cols,'extent'); + push (@cols,('authorusage','authorquota','extent')); } } return @cols; @@ -2027,6 +2208,8 @@ sub column_checkboxes { if (($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')) { $disabledchk{'status'} = 1; + $disabledchk{'authorusage'} = 1; + $disabledchk{'authorquota'} = 1; } elsif ($env{'form.roletype'} eq 'domain') { $disabledchk{'extent'} = 1; } @@ -2078,7 +2261,11 @@ sub column_checkboxes { if (($env{'form.roletype'} eq 'domain') || ($env{'form.roletype'} eq '')) { $style = ' style="display: none;"'; } - } + } elsif (($cols[$i] eq 'authorusage') || ($cols[$i] eq 'authorquota')) { + if ($env{'form.roletype'} ne 'domain') { + $style = ' style="display: none;"'; + } + } $output .= '<span id="show'.$cols[$i].'"'.$style.'><label>'. '<input id="showcol'.$cols[$i].'" type="checkbox" name="showcol" value="'.$cols[$i].'"'.$checked.' /><span id="showcoltext'.$cols[$i].'">'. $lt{$cols[$i]}.'</span>'. @@ -2112,6 +2299,8 @@ sub get_column_names { 'photo' => "photo", 'lastlogin' => "last login", 'extent' => "extent", + 'authorusage' => "disk usage (%)", + 'authorquota' => "disk quota (MB)", 'ca' => "check all", 'ua' => "uncheck all", 'clicker' => "clicker-ID", @@ -2272,7 +2461,7 @@ sub courses_selector { my $allidlist = $idlist{$codetitles[0]}; $jscript .= &Apache::courseclassifier::courseset_js_start($formname,$longtitles_str,$allidlist); $jscript .= $scripttext; - $jscript .= &Apache::courseclassifier::javascript_code_selections($formname,@codetitles); + $jscript .= &Apache::courseclassifier::javascript_code_selections($formname,\@codetitles); } } my $cb_jscript = &Apache::loncommon::coursebrowser_javascript($cdom); @@ -2301,7 +2490,8 @@ function setCourseCat(formname) { } courseSet('$codetitles[1]'); for (var j=0; j<formname.Department.length; j++) { - if (formname.Department.options[j].value == "$env{'form.Department'}") { formname.Department.options[j].selected = true; + if (formname.Department.options[j].value == "$env{'form.Department'}") { + formname.Department.options[j].selected = true; } } if (formname.Department.options[formname.Department.selectedIndex].value == -1) { @@ -2395,6 +2585,9 @@ sub make_keylist_array { $index->{'photo'} = &Apache::loncoursedata::CL_PHOTO(); $index->{'thumbnail'} = &Apache::loncoursedata::CL_THUMBNAIL(); $index->{'credits'} = &Apache::loncoursedata::CL_CREDITS(); + $index->{'instsec'} = &Apache::loncoursedata::CL_INSTSEC(); + $index->{'authorquota'} = &Apache::loncoursedata::CL_AUTHORQUOTA(); + $index->{'authorusage'} = &Apache::loncoursedata::CL_AUTHORUSAGE(); foreach my $key (keys(%{$index})) { $keylist->[$index->{$key}] = $key; } @@ -2444,10 +2637,11 @@ sub process_date_info { sub show_users_list { my ($r,$context,$mode,$permission,$statusmode,$userlist,$keylist,$formname, - $showcredits)=@_; + $showcredits,$needauthorquota,$needauthorusage)=@_; if ($formname eq '') { $formname = 'studentform'; } + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; # # Variables for excel output my ($excel_workbook, $excel_sheet, $excel_filename,$row,$format); @@ -2464,11 +2658,17 @@ sub show_users_list { } } else { push(@sortable,'extent'); + if (($context eq 'domain') && ($env{'form.roletype'} eq 'domain') && + (($env{'form.showrole'} eq 'Any') || ($env{'form.showrole'} eq 'au'))) { + push(@sortable,('authorusage','authorquota')); + } } if ($mode eq 'pickauthor') { @sortable = ('username','fullname','email','status'); } - if (!grep(/^\Q$sortby\E$/,@sortable)) { + my %is_sortable; + map { $is_sortable{$_} = 1; } @sortable; + unless ($is_sortable{$sortby}) { $sortby = 'username'; } my $setting = $env{'form.roletype'}; @@ -2518,14 +2718,22 @@ $verify_action_js function username_display_launch(username,domain) { var target; - for (var i=0; i<document.$formname.usernamelink.length; i++) { - if (document.$formname.usernamelink[i].checked) { - target = document.$formname.usernamelink[i].value; + if (!document.$formname.usernamelink.length) { + target = document.$formname.usernamelink.value; + } else { + for (var i=0; i<document.$formname.usernamelink.length; i++) { + if (document.$formname.usernamelink[i].checked) { + target = document.$formname.usernamelink[i].value; + } } } - if (target == 'modify') { + if ((target == 'modify') || (target == 'activity')) { + var nextaction = 'singleuser'; + if (target == 'activity') { + nextaction = 'accesslogs'; + } if (document.$formname.userwin.checked == true) { - var url = '/adm/createuser?srchterm='+username+'&srchdomain='+domain+'&phase=get_user_info&action=singleuser&srchin=dom&srchby=uname&srchtype=exact&popup=1'; + var url = '/adm/createuser?srchterm='+username+'&srchdomain='+domain+'&phase=get_user_info&srchin=dom&srchby=uname&srchtype=exact&popup=1&action='+nextaction; var options = 'height=600,width=800,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no'; modifywin = window.open(url,'',options,1); modifywin.focus(); @@ -2534,7 +2742,7 @@ function username_display_launch(usernam document.$formname.srchterm.value=username; document.$formname.srchdomain.value=domain; document.$formname.phase.value='get_user_info'; - document.$formname.action.value = 'singleuser'; + document.$formname.action.value = nextaction; document.$formname.submit(); } } @@ -2580,6 +2788,7 @@ END 'owin' => "Open in a new window", 'modify' => "Modify a user's information", 'track' => "View a user's recent activity", + 'activity' => "View a user's access log", ); my %lt = (%coltxt,%acttxt); my $rolefilter = $env{'form.showrole'}; @@ -2670,12 +2879,17 @@ END if ($permission->{'cusr'}) { unshift (@linkdests,'modify'); } - if (&Apache::lonnet::allowed('vsa', $env{'request.course.id'}) || - &Apache::lonnet::allowed('vsa', $env{'request.course.id'}.'/'. - $env{'request.course.sec'})) { - push(@linkdests,'track'); + if ($context eq 'course') { + if (&Apache::lonnet::allowed('vsa', $env{'request.course.id'}) || + &Apache::lonnet::allowed('vsa', $env{'request.course.id'}.'/'. + $env{'request.course.sec'})) { + push(@linkdests,'track'); + } + } elsif ($context eq 'domain') { + if (&Apache::lonnet::allowed('vac',$env{'request.role.domain'})) { + push(@linkdests,'activity'); + } } - $output .= '<td>'; my $usernamelink = $env{'form.usernamelink'}; if ($usernamelink eq '') { @@ -2698,7 +2912,7 @@ END .'<input type="checkbox" name="userwin" value="1"'.$checkwin.' />'.$lt{'owin'} .'</label></span></td></tr></table></fieldset></div>'; } - $output .= "\n".'<br clear="all" />'."\n". + $output .= "\n".'<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n". &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(); if ($mode eq 'autoenroll') { @@ -2708,11 +2922,17 @@ END } else { $output .= "\n".'<th> </th>'."\n"; if ($actionselect) { - $output .= '<th>'.&mt('Select').'</th>'."\n"; + $output .= '<th class="LC_nobreak" valign="top">'.&mt('Select').'</th>'."\n"; } } foreach my $item (@cols) { - $output .= "<th><a href=\"javascript:document.$formname.sortby.value='$item';document.$formname.submit();\">$lt{$item}</a></th>\n"; + $output .= '<th class="LC_nobreak" valign="top">'; + if ($is_sortable{$item}) { + $output .= "<a href=\"javascript:document.$formname.sortby.value='$item';document.$formname.submit();\" style=\"text-decoration:none;\">$lt{$item}<span class=\"LC_fontsize_small\"> ▼</span></a>"; + } else { + $output .= $lt{$item}; + } + $output .= "</th>\n"; } my %role_types = &role_type_names(); $output .= &Apache::loncommon::end_data_table_header_row(); @@ -2883,6 +3103,26 @@ END if ($emails{'permanentemail'} =~ /\S/) { $userlist->{$user}->[$index{'email'}] = $emails{'permanentemail'}; } + if (($context eq 'domain') && ($env{'form.roletype'} eq 'domain') && + ($role eq 'au')) { + my ($disk_quota,$current_disk_usage,$percent); + if (($needauthorusage) || ($needauthorquota)) { + $disk_quota = &Apache::loncommon::get_user_quota($uname,$udom,'author'); + } + if ($needauthorusage) { + $current_disk_usage = + &Apache::lonnet::diskusage($udom,$uname,"$londocroot/priv/$udom/$uname"); + if ($disk_quota == 0) { + $percent = 100.0; + } else { + $percent = $current_disk_usage/(10 * $disk_quota); + } + $userlist->{$user}->[$index{'authorusage'}] = sprintf("%.0f",$percent); + } + if ($needauthorquota) { + $userlist->{$user}->[$index{'authorquota'}] = sprintf("%.2f",$disk_quota); + } + } $usercount ++; } my $autocount = 0; @@ -2903,13 +3143,27 @@ END my $index = $index{$sortby}; my $second = $index{'username'}; my $third = $index{'domain'}; - my @sorted_users = sort { - lc($userlist->{$a}->[$index]) cmp lc($userlist->{$b}->[$index]) - || - lc($userlist->{$a}->[$second]) cmp lc($userlist->{$b}->[$second]) || - lc($userlist->{$a}->[$third]) cmp lc($userlist->{$b}->[$third]) - } (keys(%$userlist)); + my @sorted_users; + if (($sortby eq 'authorquota') || ($sortby eq 'authorusage')) { + @sorted_users = sort { + $userlist->{$b}->[$index] <=> $userlist->{$a}->[$index] || + lc($userlist->{$a}->[$second]) cmp lc($userlist->{$b}->[$second]) || + lc($userlist->{$a}->[$third]) cmp lc($userlist->{$b}->[$third]) + } (keys(%$userlist)); + } else { + @sorted_users = sort { + lc($userlist->{$a}->[$index]) cmp lc($userlist->{$b}->[$index]) || + lc($userlist->{$a}->[$second]) cmp lc($userlist->{$b}->[$second]) || + lc($userlist->{$a}->[$third]) cmp lc($userlist->{$b}->[$third]) + } (keys(%$userlist)); + } my $rowcount = 0; + my $disabled; + if ($mode eq 'autoenroll') { + unless ($permission->{'cusr'}) { + $disabled = ' disabled="disabled"'; + } + } foreach my $user (@sorted_users) { my %in; my $sdata = $userlist->{$user}; @@ -2919,7 +3173,7 @@ END } my $clickers = (&Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers'))[1]; if ($clickers!~/\w/) { $clickers='-'; } - $in{'clicker'} = $clickers; + $in{'clicker'} = $clickers; my $role = $in{'role'}; $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}],$crstype); unless ($mode eq 'excel') { @@ -2946,16 +3200,16 @@ END if ($mode eq 'autoenroll') { my $cellentry; if ($in{'type'} eq 'auto') { - $cellentry = '<b>'.&mt('auto').'</b> <label><input type="checkbox" name="chgauto" value="'.$in{'username'}.':'.$in{'domain'}.'" /> Change</label>'; + $cellentry = '<b>'.&mt('auto').'</b> <label><input type="checkbox" name="chgauto" value="'.$in{'username'}.':'.$in{'domain'}.'"'.$disabled.' /> '.&mt('Change').'</label>'; $autocount ++; } else { - $cellentry = '<table border="0" cellspacing="0"><tr><td rowspan="2"><b>'.&mt('manual').'</b></td><td><span class="LC_nobreak"><label><input type="checkbox" name="chgmanual" value="'.$in{'username'}.':'.$in{'domain'}.'" /> Change</label></span></td></tr><tr><td><span class="LC_nobreak">'; + $cellentry = '<table border="0" cellspacing="0"><tr><td rowspan="2"><b>'.&mt('manual').'</b></td><td><span class="LC_nobreak"><label><input type="checkbox" name="chgmanual" value="'.$in{'username'}.':'.$in{'domain'}.'"'.$disabled.' /> '.&mt('Change').'</label></span></td></tr><tr><td><span class="LC_nobreak">'; $manualcount ++; if ($in{'lockedtype'}) { - $cellentry .= '<label><input type="checkbox" name="unlockchg" value="'.$in{'username'}.':'.$in{'domain'}.'" /> '.&mt('Unlock').'</label>'; + $cellentry .= '<label><input type="checkbox" name="unlockchg" value="'.$in{'username'}.':'.$in{'domain'}.'"'.$disabled.' /> '.&mt('Unlock').'</label>'; $unlockcount ++; } else { - $cellentry .= '<label><input type="checkbox" name="lockchg" value="'.$in{'username'}.':'.$in{'domain'}.'" /> '.&mt('Lock').'</label>'; + $cellentry .= '<label><input type="checkbox" name="lockchg" value="'.$in{'username'}.':'.$in{'domain'}.'"'.$disabled.' /> '.&mt('Lock').'</label>'; $lockcount ++; } $cellentry .= '</span></td></tr></table>'; @@ -2995,13 +3249,21 @@ END if ($role eq 'st') { $checkval .= ':'.$in{'type'}.':'. $in{'lockedtype'}.':'. - $in{'credits'}; + $in{'credits'}.':'. + &escape($in{'instsec'}); } } } if ($showcheckbox) { $r->print('<td><input type="checkbox" name="'. - 'actionlist" value="'.$checkval.'" /></td>'); + 'actionlist" value="'. + &HTML::Entities::encode($checkval,'&<>"').'" />'); + foreach my $item ('start','end') { + $r->print('<input type="hidden" name="'. + &HTML::Entities::encode($checkval.'_'.$item,'&<>"').'"'. + ' value="'.$sdata->[$index{$item}].'" />'); + } + $r->print('</td>'); } else { $r->print('<td> </td>'); } @@ -3015,8 +3277,6 @@ END foreach my $item (@cols) { if ($item eq 'username') { $r->print('<td>'.&print_username_link($mode,\%in).'</td>'); - } elsif (($item eq 'start' || $item eq 'end') && ($actionselect)) { - $r->print('<td>'.$in{$item}.'<input type="hidden" name="'.$checkval.'_'.$item.'" value="'.$sdata->[$index{$item}].'" /></td>'."\n"); } elsif ($item eq 'status') { my $showitem = $in{$item}; if (defined($ltstatus{$in{$item}})) { @@ -3043,6 +3303,8 @@ END $r->print('<td> </td>'."\n"); } } + } elsif (($item eq 'authorquota') || ($item eq 'authorusage')) { + $r->print('<td align="right">'.$in{$item}.'</td>'."\n"); } else { $r->print('<td>'.$in{$item}.'</td>'."\n"); } @@ -3078,10 +3340,10 @@ END $r->print(&Apache::loncommon::end_data_table().'<br />'); } elsif ($mode eq 'excel') { $excel_workbook->close(); - $r->print(&mt('[_1]Your Excel spreadsheet[_2] is ready for download.', '<p><a href="'.$excel_filename.'">','</a>')."</p>\n"); + $r->print('<p>'.&mt('[_1]Your Excel spreadsheet[_2] is ready for download.', '<a href="'.$excel_filename.'">','</a>')."</p>\n"); } elsif ($mode eq 'csv') { close($CSVfile); - $r->print(&mt('[_1]Your CSV file[_2] is ready for download.', '<p><a href="'.$CSVfilename.'">','</a>')."</p>\n"); + $r->print('<p>'.&mt('[_1]Your CSV file[_2] is ready for download.', '<a href="'.$CSVfilename.'">','</a>')."</p>\n"); $r->rflush(); } if ($mode eq 'autoenroll') { @@ -3113,6 +3375,10 @@ sub bulkaction_javascript { my $noaction = &mt("You need to select an action to take for the user(s) you have selected"); my $singconfirm = &mt(' for a single user?'); my $multconfirm = &mt(' for multiple users?'); + &js_escape(\$alert); + &js_escape(\$noaction); + &js_escape(\$singconfirm); + &js_escape(\$multconfirm); my $output = <<"ENDJS"; function verify_action (field) { var numchecked = 0; @@ -3779,7 +4045,6 @@ sub show_drop_list { $check_uncheck_js // ]]> </script> -<p> <input type="hidden" name="phase" value="four" /> END my ($indexhash,$keylist) = &make_keylist_array(); @@ -3816,6 +4081,7 @@ END $classlist,$keylist,$cdom,$cnum); my %lt=&Apache::lonlocal::texthash('usrn' => "username", 'dom' => "domain", + 'id' => "ID", 'sn' => "student name", 'mn' => "member name", 'sec' => "section", @@ -3834,7 +4100,7 @@ END <th> </th> <th>$lt{'usrn'}</th> <th>$lt{'dom'}</th> - <th>ID</th> + <th>$lt{'id'}</th> <th>$nametitle</th> <th>$lt{'sec'}</th> <th>$lt{'start'}</th> @@ -3848,21 +4114,21 @@ END $r->print(<<END); <th> </th> <th> - <a href="/adm/createuser?action=$action&sortby=username">$lt{'usrn'}</a> + <a href="/adm/createuser?action=$action&sortby=username">$lt{'usrn'}</a> </th><th> - <a href="/adm/createuser?action=$action&sortby=domain">$lt{'dom'}</a> + <a href="/adm/createuser?action=$action&sortby=domain">$lt{'dom'}</a> </th><th> - <a href="/adm/createuser?action=$action&sortby=id">ID</a> + <a href="/adm/createuser?action=$action&sortby=id">$lt{'id'}</a> </th><th> - <a href="/adm/createuser?action=$action&sortby=fullname">$nametitle</a> + <a href="/adm/createuser?action=$action&sortby=fullname">$nametitle</a> </th><th> - <a href="/adm/createuser?action=$action&sortby=section">$lt{'sec'}</a> + <a href="/adm/createuser?action=$action&sortby=section">$lt{'sec'}</a> </th><th> - <a href="/adm/createuser?action=$action&sortby=start">$lt{'start'}</a> + <a href="/adm/createuser?action=$action&sortby=start">$lt{'start'}</a> </th><th> - <a href="/adm/createuser?action=$action&sortby=end">$lt{'end'}</a> + <a href="/adm/createuser?action=$action&sortby=end">$lt{'end'}</a> </th><th> - <a href="/adm/createuser?action=$action&sortby=groups">$lt{'groups'}</a> + <a href="/adm/createuser?action=$action&sortby=groups">$lt{'groups'}</a> </th> END $r->print(&Apache::loncommon::end_data_table_header_row()); @@ -3933,7 +4199,6 @@ END $btn = $lt{'dm'}; } $r->print(<<"END"); -</p> <p> <input type="button" value="$lt{'ca'}" onclick="javascript:checkAll(document.studentform.droplist)" /> <input type="button" value="$lt{'ua'}" onclick="javascript:uncheckAll(document.studentform.droplist)" /> @@ -3997,7 +4262,10 @@ sub print_first_users_upload_form { # ================================================= Drop/Add from uploaded file sub upfile_drop_add { my ($r,$context,$permission,$showcredits) = @_; - &Apache::loncommon::load_tmp_file($r); + my $datatoken = &Apache::loncommon::valid_datatoken($env{'form.datatoken'}); + if ($datatoken ne '') { + &Apache::loncommon::load_tmp_file($r,$datatoken); + } my @userdata=&Apache::loncommon::upfile_record_sep(); if($env{'form.noFirstLine'}){shift(@userdata);} my @keyfields = split(/\,/,$env{'form.keyfields'}); @@ -4011,10 +4279,6 @@ sub upfile_drop_add { $fields{$env{'form.f'.$i}}=$keyfields[$i]; } } - if ($env{'form.fullup'} ne 'yes') { - $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n". - '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />'); - } # # Store the field choices away my @storefields = qw/username names fname mname lname gen id @@ -4028,17 +4292,19 @@ sub upfile_drop_add { $fieldstype{$field.'_choice'} = 'scalar'; } &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype); - my ($cid,$crstype,$setting); + my ($cid,$crstype,$setting,$crsdom); if ($context eq 'domain') { $setting = $env{'form.roleaction'}; } if ($env{'request.course.id'} ne '') { $cid = $env{'request.course.id'}; $crstype = &Apache::loncommon::course_type(); + $crsdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; } elsif ($setting eq 'course') { if (&Apache::lonnet::is_course($env{'form.dcdomain'},$env{'form.dccourse'})) { $cid = $env{'form.dcdomain'}.'_'.$env{'form.dccourse'}; $crstype = &Apache::loncommon::course_type($cid); + $crsdom = $env{'form.dcdomain'}; } } my ($startdate,$enddate) = &get_dates_from_form(); @@ -4049,7 +4315,47 @@ sub upfile_drop_add { my $defdom=$env{'request.role.domain'}; my $domain; if ($env{'form.defaultdomain'} ne '') { - $domain = $env{'form.defaultdomain'}; + if (($context eq 'course') || ($setting eq 'course')) { + if ($env{'form.defaultdomain'} eq $crsdom) { + $domain = $env{'form.defaultdomain'}; + } else { + if (&Apache::lonnet::will_trust('enroll',$crsdom,$env{'form.defaultdomain'})) { + $domain = $env{'form.defaultdomain'}; + } else { + $r->print('<span class="LC_error">'.&mt('Error').': '. + &mt('Enrollment of users not permitted for specified default domain: [_1].', + &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).'</span>'); + return 'untrusted'; + } + } + } elsif ($context eq 'author') { + if ($env{'form.defaultdomain'} eq $defdom) { + $domain = $env{'form.defaultdomain'}; + } else { + if ((&Apache::lonnet::will_trust('othcoau',$defdom,$env{'form.defaultdomain'})) && + (&Apache::lonnet::will_trust('coaurem',$env{'form.defaultdomain'},$defdom))) { + $domain = $env{'form.defaultdomain'}; + } else { + $r->print('<span class="LC_error">'.&mt('Error').': '. + &mt('Addition of users not permitted for specified default domain: [_1].', + &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).'</span>'); + return 'untrusted'; + } + } + } elsif (($context eq 'domain') && ($setting eq 'domain')) { + if ($env{'form.defaultdomain'} eq $defdom) { + $domain = $env{'form.defaultdomain'}; + } else { + if (&Apache::lonnet::will_trust('domroles',$defdom,$env{'form.defaultdomain'})) { + $domain = $env{'form.defaultdomain'}; + } else { + $r->print('<span class="LC_error">'.&mt('Error').': '. + &mt('Addition of users not permitted for specified default domain: [_1].', + &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).'</span>'); + return 'untrusted'; + } + } + } } else { $domain = $defdom; } @@ -4059,10 +4365,9 @@ sub upfile_drop_add { } else { my %home_servers = &Apache::lonnet::get_servers($defdom,'library'); if (! exists($home_servers{$desiredhost})) { - $r->print('<span class="LC_error">'.&mt('Error'). - &mt('Invalid home server specified').'</span>'); - $r->print(&Apache::loncommon::end_page()); - return; + $r->print('<p class="LC_error">'.&mt('Error').': '. + &mt('Invalid home server specified').'</p>'); + return 'invalidhome'; } } # Determine authentication mechanism @@ -4086,6 +4391,8 @@ sub upfile_drop_add { if ((defined($env{'form.locarg'})) && ($env{'form.locarg'})) { $genpwd=$env{'form.locarg'}; } + } elsif ($env{'form.login'} eq 'lti') { + $amode='lti'; } if ($amode =~ /^krb/) { if (! defined($genpwd) || $genpwd eq '') { @@ -4162,6 +4469,11 @@ sub upfile_drop_add { } } } + if ($datatoken eq '') { + $r->print('<p class="LC_error">'.&mt('Error').': '. + &mt('Invalid datatoken').'</p>'); + return 'missingdata'; + } if ( $domain eq &LONCAPA::clean_domain($domain) && ($amode ne '')) { ####################################### @@ -4231,7 +4543,11 @@ sub upfile_drop_add { my $newuserdom = $env{'request.role.domain'}; map { $cancreate{$_} = &can_create_user($newuserdom,$context,$_); } keys(%longtypes); # Get new users list + my (%existinguser,%userinfo,%disallow,%rulematch,%inst_results,%alerts,%checkuname); + my $counter = -1; + my (%willtrust,%trustchecked); foreach my $line (@userdata) { + $counter ++; my @secs; my %entries=&Apache::loncommon::record_sep($line); # Determine user name @@ -4263,18 +4579,42 @@ sub upfile_drop_add { if ($entries{$fields{'username'}} =~ /\s/) { $nowhitespace = ' - '.&mt('usernames may not contain spaces.'); } - $r->print('<br />'. - &mt('[_1]: Unacceptable username for user [_2] [_3] [_4] [_5]', - '<b>'.$entries{$fields{'username'}}.'</b>',$fname,$mname,$lname,$gen). - $nowhitespace); + $disallow{$counter} = + &mt('Unacceptable username [_1] for user [_2] [_3] [_4] [_5]', + '"<b>'.$entries{$fields{'username'}}.'</b>"', + $fname,$mname,$lname,$gen).$nowhitespace; next; } else { $entries{$fields{'domain'}} =~ s/^\s+|\s+$//g; if ($entries{$fields{'domain'}} ne &LONCAPA::clean_domain($entries{$fields{'domain'}})) { - $r->print('<br />'. '<b>'.$entries{$fields{'domain'}}. - '</b>: '.&mt('Unacceptable domain for user [_1] [_2] [_3] [_4]',$fname,$mname,$lname,$gen)); + $disallow{$counter} = + &mt('Unacceptable domain [_1] for user [_2] [_3] [_4] [_5]', + '"<b>'.$entries{$fields{'domain'}}.'</b>"', + $fname,$mname,$lname,$gen); next; + } elsif ($entries{$fields{'domain'}} ne $domain) { + my $possdom = $entries{$fields{'domain'}}; + if ($context eq 'course' || $setting eq 'course') { + unless ($trustchecked{$possdom}) { + $willtrust{$possdom} = &Apache::lonnet::will_trust('enroll',$domain,$possdom); + $trustchecked{$possdom} = 1; + } + } elsif ($context eq 'author') { + unless ($trustchecked{$possdom}) { + $willtrust{$possdom} = &Apache::lonnet::will_trust('othcoau',$domain,$possdom); + } + if ($willtrust{$possdom}) { + $willtrust{$possdom} = &Apache::lonnet::will_trust('coaurem',$possdom,$domain); + } + } + unless ($willtrust{$possdom}) { + $disallow{$counter} = + &mt('Unacceptable domain [_1] for user [_2] [_3] [_4] [_5]', + '"<b>'.$possdom.'</b>"', + $fname,$mname,$lname,$gen); + next; + } } my $username = $entries{$fields{'username'}}; my $userdomain = $entries{$fields{'domain'}}; @@ -4286,10 +4626,15 @@ sub upfile_drop_add { $entries{$fields{'sec'}} =~ s/\W//g; my $item = $entries{$fields{'sec'}}; if ($item eq "none" || $item eq 'all') { - $r->print('<br />'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a reserved word.','<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item)); + $disallow{$counter} = + &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a reserved word.', + '<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item); next; } elsif (exists($curr_groups{$item})) { - $r->print('<br />'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a course group.','<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item).' '.&mt('Section names and group names must be distinct.')); + $disallow{$counter} = + &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a course group.', + '<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item).' '. + &mt('Section names and group names must be distinct.'); next; } else { push(@secs,$item); @@ -4301,14 +4646,21 @@ sub upfile_drop_add { if (ref($userlist{$username.':'.$userdomain}) eq 'ARRAY') { my $currsec = $userlist{$username.':'.$userdomain}[$secidx]; if ($currsec ne $env{'request.course.sec'}) { - $r->print('<br />'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".','<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$secs[0]).'<br />'); + $disallow{$counter} = + &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".', + '<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$secs[0]); if ($currsec eq '') { - $r->print(&mt('This user already has an active/future student role in the course, unaffiliated to any section.')); + $disallow{$counter} .= + &mt('This user already has an active/future student role in the course, unaffiliated to any section.'); } else { - $r->print(&mt('This user already has an active/future role in section "[_1]" of the course.',$currsec)); + $disallow{$counter} .= + &mt('This user already has an active/future role in section "[_1]" of the course.',$currsec); } - $r->print('<br />'.&mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',$secs[0]).'<br />'); + $disallow{$counter} .= + '<br />'. + &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.', + $secs[0]); next; } } @@ -4360,13 +4712,12 @@ sub upfile_drop_add { } if ($role eq '') { my $rolestr = join(', ',@permitted_roles); - $r->print('<br />' - .&mt('[_1]: You do not have permission to add the requested role [_2] for the user.' - ,'<b>'.$entries{$fields{'username'}}.'</b>' - ,$entries{$fields{'role'}}) - .'<br />' - .&mt('Allowable role(s) is/are: [_1].',$rolestr)."\n" - ); + $disallow{$counter} = + &mt('[_1]: You do not have permission to add the requested role [_2] for the user.' + ,'<b>'.$entries{$fields{'username'}}.'</b>' + ,$entries{$fields{'role'}}) + .'<br />' + .&mt('Allowable role(s) is/are: [_1].',$rolestr); next; } } @@ -4396,55 +4747,36 @@ sub upfile_drop_add { # check against rules my $checkid = 0; my $newuser = 0; - my (%rulematch,%inst_results,%idinst_results); my $uhome=&Apache::lonnet::homeserver($username,$userdomain); if ($uhome eq 'no_host') { if ($userdomain ne $newuserdom) { if ($context eq 'course') { - $r->print('<br />'. - &mt('[_1]: The domain specified ([_2]) is different to that of the course.', - '<b>'.$username.'</b>',$userdomain).'<br />'); + $disallow{$counter} = + &mt('[_1]: The domain specified ([_2]) is different to that of the course.', + '<b>'.$username.'</b>',$userdomain); } elsif ($context eq 'author') { - $r->print(&mt('[_1]: The domain specified ([_2]) is different to that of the author.', - '<b>'.$username.'</b>',$userdomain).'<br />'); + $disallow{$counter} = + &mt('[_1]: The domain specified ([_2]) is different to that of the author.', + '<b>'.$username.'</b>',$userdomain); } else { - $r->print(&mt('[_1]: The domain specified ([_2]) is different to that of your current role.', - '<b>'.$username.'</b>',$userdomain).'<br />'); + $disallow{$counter} = + &mt('[_1]: The domain specified ([_2]) is different to that of your current role.', + '<b>'.$username.'</b>',$userdomain); } - $r->print(&mt('The user does not already exist, and you may not create a new user in a different domain.')); + $disallow{$counter} .= + &mt('The user does not already exist, and you may not create a new user in a different domain.'); next; + } else { + unless (($password ne '') || ($env{'form.login'} eq 'loc') || ($env{'form.login'} eq 'lti')) { + $disallow{$counter} = + &mt('[_1]: This is a new user but no default password was provided, and the authentication type requires one.', + '<b>'.$username.'</b>'); + next; + } } $checkid = 1; $newuser = 1; - my $user = $username.':'.$newuserdom; - my $checkhash; - my $checks = { 'username' => 1 }; - $checkhash->{$username.':'.$newuserdom} = { 'newuser' => 1, }; - &Apache::loncommon::user_rule_check($checkhash,$checks, - \%alerts,\%rulematch,\%inst_results,\%curr_rules, - \%got_rules); - if (ref($alerts{'username'}) eq 'HASH') { - if (ref($alerts{'username'}{$newuserdom}) eq 'HASH') { - if ($alerts{'username'}{$newuserdom}{$username}) { - $r->print('<br />'. - &mt('[_1]: matches the username format at your institution, but is not known to your directory service.','<b>'.$username.'</b>').'<br />'. - &mt('Consequently, the user was not created.')); - next; - } - } - } - my $usertype = 'unofficial'; - if (ref($rulematch{$user}) eq 'HASH') { - if ($rulematch{$user}{'username'}) { - $usertype = 'official'; - } - } - unless ($cancreate{$usertype}) { - my $showtype = $longtypes{$usertype}; - $r->print('<br />'. - &mt('[_1]: The user does not exist, and you are not permitted to create users of type: [_2].','<b>'.$username.'</b>',$showtype)); - next; - } + $checkuname{$username.':'.$newuserdom} = { 'newuser' => $newuser, 'id' => $id }; } else { if ($context eq 'course' || $context eq 'author') { if ($userdomain eq $domain ) { @@ -4477,77 +4809,205 @@ sub upfile_drop_add { } } } + if ($id) { + $existinguser{$userdomain}{$username} = $id; + } } - if ($id ne '') { - if (!$newuser) { - my %idhash = &Apache::lonnet::idrget($userdomain,($username)); - if ($idhash{$username} ne $id) { - $checkid = 1; + $userinfo{$counter} = { + username => $username, + domain => $userdomain, + fname => $fname, + mname => $mname, + lname => $lname, + gen => $gen, + email => $email, + id => $id, + password => $password, + inststatus => $inststatus, + role => $role, + sections => \@secs, + credits => $credits, + newuser => $newuser, + checkid => $checkid, + }; + } + } + } # end of foreach (@userdata) + if ($counter > -1) { + my $total = $counter + 1; + my %checkids; + if ((keys(%existinguser)) || (keys(%checkuname))) { + $r->print(&mt('Please be patient -- checking for institutional data ...')); + $r->rflush(); + if (keys(%existinguser)) { + foreach my $dom (keys(%existinguser)) { + if (ref($existinguser{$dom}) eq 'HASH') { + my %idhash = &Apache::lonnet::idrget($dom,keys(%{$existinguser{$dom}})); + foreach my $username (keys(%{$existinguser{$dom}})) { + if ($idhash{$username} ne $existinguser{$dom}{$username}) { + $checkids{$username.':'.$dom} = { + 'id' => $existinguser{$dom}{$username}, + }; + } + } + if (keys(%checkids)) { + &Apache::loncommon::user_rule_check(\%checkids,{ 'id' => 1 }, + \%alerts,\%rulematch, + \%inst_results,\%curr_rules, + \%got_rules); + } + } + } + } + if (keys(%checkuname)) { + &Apache::loncommon::user_rule_check(\%checkuname,{ 'username' => 1, 'id' => 1, }, + \%alerts,\%rulematch,\%inst_results, + \%curr_rules,\%got_rules); + } + $r->print(' '.&mt('done').'<br /><br />'); + $r->rflush(); + } + my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,$total); + $r->print('<ul>'); + for (my $i=0; $i<=$counter; $i++) { + if ($disallow{$i}) { + $r->print('<li>'.$disallow{$i}.'</li>'); + } elsif (ref($userinfo{$i}) eq 'HASH') { + my $password = $userinfo{$i}{'password'}; + my $newuser = $userinfo{$i}{'newuser'}; + my $checkid = $userinfo{$i}{'checkid'}; + my $id = $userinfo{$i}{'id'}; + my $role = $userinfo{$i}{'role'}; + my @secs; + if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') { + @secs = @{$userinfo{$i}{'sections'}}; + } + my $fname = $userinfo{$i}{'fname'}; + my $mname = $userinfo{$i}{'mname'}; + my $lname = $userinfo{$i}{'lname'}; + my $gen = $userinfo{$i}{'gen'}; + my $email = $userinfo{$i}{'email'}; + my $inststatus = $userinfo{$i}{'inststatus'}; + my $credits = $userinfo{$i}{'credits'}; + my $username = $userinfo{$i}{'username'}; + my $userdomain = $userinfo{$i}{'domain'}; + my $user = $username.':'.$userdomain; + if ($newuser) { + if (ref($alerts{'username'}) eq 'HASH') { + if (ref($alerts{'username'}{$userdomain}) eq 'HASH') { + if ($alerts{'username'}{$userdomain}{$username}) { + $r->print('<li>'. + &mt('[_1]: matches the username format at your institution, but is not known to your directory service.','<b>'.$username.'</b>').'<br />'. + &mt('Consequently, the user was not created.').'</li>'); + next; + } + } + } + if (ref($inst_results{$user}) eq 'HASH') { + if ($inst_results{$user}{'firstname'} ne '') { + $fname = $inst_results{$user}{'firstname'}; + } + if ($inst_results{$user}{'middlename'} ne '') { + $mname = $inst_results{$user}{'middlename'}; + } + if ($inst_results{$user}{'lasttname'} ne '') { + $lname = $inst_results{$user}{'lastname'}; + } + if ($inst_results{$user}{'permanentemail'} ne '') { + $email = $inst_results{$user}{'permanentemail'}; + } + if ($inst_results{$user}{'id'} ne '') { + $id = $inst_results{$user}{'id'}; + $checkid = 0; + } + if (ref($inst_results{$user}{'inststatus'}) eq 'ARRAY') { + $inststatus = join(':',@{$inst_results{$user}{'inststatus'}}); } } - if ($checkid) { - my $checkhash; - my $checks = { 'id' => 1 }; - $checkhash->{$username.':'.$userdomain} = { 'newuser' => $newuser, - 'id' => $id }; - &Apache::loncommon::user_rule_check($checkhash,$checks, - \%alerts,\%rulematch,\%idinst_results,\%curr_rules, - \%got_rules); + if (($checkid) && ($id ne '')) { if (ref($alerts{'id'}) eq 'HASH') { if (ref($alerts{'id'}{$userdomain}) eq 'HASH') { - if ($alerts{'id'}{$userdomain}{$id}) { - $r->print(&mt('[_1]: has a student/employee ID matching the format at your institution, but the ID is found by your directory service.', + if ($alerts{'id'}{$userdomain}{$username}) { + $r->print('<li>'. + &mt('[_1]: has a student/employee ID matching the format at your institution, but the ID is not found by your directory service.', '<b>'.$username.'</b>').'<br />'. - &mt('Consequently, the user was not created.')); + &mt('Consequently, the user was not created.').'</li>'); next; } } } } + my $usertype = 'unofficial'; + if (ref($rulematch{$user}) eq 'HASH') { + if ($rulematch{$user}{'username'}) { + $usertype = 'official'; + } + } + unless ($cancreate{$usertype}) { + my $showtype = $longtypes{$usertype}; + $r->print('<li>'. + &mt('[_1]: The user does not exist, and you are not permitted to create users of type: [_2].','<b>'.$username.'</b>',$showtype).'</li>'); + next; + } + } elsif ($id ne '') { + if (exists($checkids{$user})) { + $checkid = 1; + if (ref($alerts{'id'}) eq 'HASH') { + if (ref($alerts{'id'}{$userdomain}) eq 'HASH') { + if ($alerts{'id'}{$userdomain}{$username}) { + $r->print('<li>'. + &mt('[_1]: has a student/employee ID matching the format at your institution, but the ID is not found by your directory service.', + '<b>'.$username.'</b>').'<br />'. + &mt('Consequently, the ID was not changed.').'</li>'); + $id = ''; + } + } + } + } } - if ($password || $env{'form.login'} eq 'loc') { - my $multiple = 0; - my ($userresult,$authresult,$roleresult,$idresult); - my (%userres,%authres,%roleres,%idres); - my $singlesec = ''; - if ($role eq 'st') { - my $sec; + my $multiple = 0; + my ($userresult,$authresult,$roleresult,$idresult); + my (%userres,%authres,%roleres,%idres); + my $singlesec = ''; + if ($role eq 'st') { + my $sec; + if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') { if (@secs > 0) { $sec = $secs[0]; } - &modifystudent($userdomain,$username,$cid,$sec, - $desiredhost,$context); - $roleresult = - &Apache::lonnet::modifystudent - ($userdomain,$username,$id,$amode,$password, - $fname,$mname,$lname,$gen,$sec,$enddate, - $startdate,$env{'form.forceid'}, - $desiredhost,$email,'manual','',$cid, - '',$context,$inststatus,$credits); - $userresult = $roleresult; - } else { - if ($role ne '') { - if ($context eq 'course' || $setting eq 'course') { - if ($customroles{$role}) { - $role = 'cr_'.$env{'user.domain'}.'_'. - $env{'user.name'}.'_'.$role; - } - if (($role ne 'cc') && ($role ne 'co')) { - if (@secs > 1) { - $multiple = 1; - foreach my $sec (@secs) { - ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) = - &modifyuserrole($context,$setting, - $changeauth,$cid,$userdomain,$username, - $id,$amode,$password,$fname, - $mname,$lname,$gen,$sec, - $env{'form.forceid'},$desiredhost, - $email,$role,$enddate, - $startdate,$checkid,$inststatus); - } - } elsif (@secs > 0) { - $singlesec = $secs[0]; + } + &modifystudent($userdomain,$username,$cid,$sec, + $desiredhost,$context); + $roleresult = + &Apache::lonnet::modifystudent + ($userdomain,$username,$id,$amode,$password, + $fname,$mname,$lname,$gen,$sec,$enddate, + $startdate,$env{'form.forceid'}, + $desiredhost,$email,'manual','',$cid, + '',$context,$inststatus,$credits); + $userresult = $roleresult; + } else { + if ($role ne '') { + if ($context eq 'course' || $setting eq 'course') { + if ($customroles{$role}) { + $role = 'cr_'.$env{'user.domain'}.'_'. + $env{'user.name'}.'_'.$role; + } + if (($role ne 'cc') && ($role ne 'co')) { + if (@secs > 1) { + $multiple = 1; + foreach my $sec (@secs) { + ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) = + &modifyuserrole($context,$setting, + $changeauth,$cid,$userdomain,$username, + $id,$amode,$password,$fname, + $mname,$lname,$gen,$sec, + $env{'form.forceid'},$desiredhost, + $email,$role,$enddate, + $startdate,$checkid,$inststatus); } + } elsif (@secs > 0) { + $singlesec = $secs[0]; } } } @@ -4562,45 +5022,36 @@ sub upfile_drop_add { $checkid,$inststatus); } } - if ($multiple) { - foreach my $sec (sort(keys(%userres))) { - $flushc = + } + if ($multiple) { + foreach my $sec (sort(keys(%userres))) { + $flushc = &user_change_result($r,$userres{$sec},$authres{$sec}, $roleres{$sec},$idres{$sec},\%counts,$flushc, $username,$userdomain,\%userchg); - } - } else { - $flushc = - &user_change_result($r,$userresult,$authresult, - $roleresult,$idresult,\%counts,$flushc, - $username,$userdomain,\%userchg); } } else { - if ($context eq 'course') { - $r->print('<br />'. - &mt('[_1]: Unable to enroll. No password specified.','<b>'.$username.'</b>') - ); - } elsif ($context eq 'author') { - $r->print('<br />'. - &mt('[_1]: Unable to add co-author. No password specified.','<b>'.$username.'</b>') - ); - } else { - $r->print('<br />'. - &mt('[_1]: Unable to add user. No password specified.','<b>'.$username.'</b>') - ); - } + $flushc = + &user_change_result($r,$userresult,$authresult, + $roleresult,$idresult,\%counts,$flushc, + $username,$userdomain,\%userchg); } } - } - } # end of foreach (@userdata) + &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,'last user'); + } # end of loop + $r->print('</ul>'); + &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state); + } # Flush the course logs so reverse user roles immediately updated $r->register_cleanup(\&Apache::lonnet::flushcourselogs); $r->print("</p>\n<p>\n".&mt('Processed [quant,_1,user].',$counts{'user'}). "</p>\n"); if ($counts{'role'} > 0) { $r->print("<p>\n". - &mt('Roles added for [quant,_1,user].',$counts{'role'}).' '.&mt('If a user is currently logged-in to LON-CAPA, any new roles which are active will be available when the user next logs in.')."</p>\n"); + &mt('Roles added for [quant,_1,user].',$counts{'role'}).' '. + &mt('If a user is currently logged-in to LON-CAPA, any new roles which are active will be available when the user next logs in.'). + "</p>\n"); } else { $r->print('<p>'.&mt('No roles added').'</p>'); } @@ -4618,10 +5069,9 @@ sub upfile_drop_add { # Get current classlist my $classlist = &Apache::loncoursedata::get_classlist(); if (! defined($classlist)) { - $r->print('<form name="studentform" method="post" action="/adm/createuser">'. - '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />'. - '<p class="LC_info">'.&mt('There are no students with current/future access to the course.').'</p>'. - '</form>'."\n"); + $r->print('<p class="LC_info">'. + &mt('There are no students with current/future access to the course.'). + '</p>'."\n"); } elsif (ref($classlist) eq 'HASH') { # Remove the students we just added from the list of students. foreach my $line (@userdata) { @@ -4637,9 +5087,7 @@ sub upfile_drop_add { } } } # end of unless - if ($env{'form.fullup'} ne 'yes') { - $r->print('</form>'); - } + return 'ok'; } sub print_namespacing_alerts { @@ -4686,11 +5134,12 @@ sub user_change_result { my ($r,$userresult,$authresult,$roleresult,$idresult,$counts,$flushc, $username,$userdomain,$userchg) = @_; my $okresult = 0; + my @status; if ($userresult ne 'ok') { if ($userresult =~ /^error:(.+)$/) { my $error = $1; - $r->print('<br />'. - &mt('[_1]: Unable to add/modify: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error)); + push(@status, + &mt('[_1]: Unable to add/modify: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error)); } } else { $counts->{'user'} ++; @@ -4699,8 +5148,8 @@ sub user_change_result { if ($authresult ne 'ok') { if ($authresult =~ /^error:(.+)$/) { my $error = $1; - $r->print('<br />'. - &mt('[_1]: Unable to modify authentication: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error)); + push(@status, + &mt('[_1]: Unable to modify authentication: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error)); } } else { $counts->{'auth'} ++; @@ -4709,8 +5158,8 @@ sub user_change_result { if ($roleresult ne 'ok') { if ($roleresult =~ /^error:(.+)$/) { my $error = $1; - $r->print('<br />'. - &mt('[_1]: Unable to add role: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error)); + push(@status, + &mt('[_1]: Unable to add role: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error)); } } else { $counts->{'role'} ++; @@ -4719,14 +5168,16 @@ sub user_change_result { if ($okresult) { $flushc++; $userchg->{$username.':'.$userdomain}=1; - $r->print('. '); if ($flushc>15) { $r->rflush; $flushc=0; } } if ($idresult) { - $r->print($idresult); + push(@status,$idresult); + } + if (@status) { + $r->print('<li>'.join('<br />',@status).'</li>'); } return $flushc; } @@ -4754,7 +5205,7 @@ sub print_drop_menu { } else { &show_drop_list($r,$classlist,'nosort',$permission,$crstype); } - $r->print('</form>'. &Apache::loncommon::end_page()); + $r->print('</form>'); return; } @@ -4797,7 +5248,7 @@ sub update_user_list { foreach my $item (@changelist) { my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype, @sections,$scopestem,$singlesec,$showsecs,$warn_singlesec, - $nothingtodo,$keepnosection,$credits); + $nothingtodo,$keepnosection,$credits,$instsec); if ($choice eq 'drop') { ($uname,$udom,$sec) = split(/:/,$item,-1); $role = 'st'; @@ -4810,8 +5261,9 @@ sub update_user_list { $scope = $scopestem.'/'.$sec; } } elsif ($context eq 'course') { - ($uname,$udom,$role,$sec,$type,$locktype,$credits) = - split(/\:/,$item); + ($uname,$udom,$role,$sec,$type,$locktype,$credits,$instsec) = + split(/\:/,$item,8); + $instsec = &unescape($instsec); $cid = $env{'request.course.id'}; $scopestem = '/'.$cid; $scopestem =~s/\_/\//g; @@ -4830,8 +5282,9 @@ sub update_user_list { } elsif ($setting eq 'author') { ($uname,$udom,$role,$scope) = split(/\:/,$item); } elsif ($setting eq 'course') { - ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits) = - split(/\:/,$item); + ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits,$instsec) = + split(/\:/,$item,9); + $instsec = &unescape($instsec); $scope = '/'.$cid; $scope =~s/\_/\//g; if ($sec ne '') { @@ -4853,7 +5306,7 @@ sub update_user_list { $end = $now; if ($role eq 'st') { $result = - &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits); + &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { $result = &Apache::lonnet::revokerole($udom,$uname,$scope,$role, @@ -4861,7 +5314,7 @@ sub update_user_list { } } elsif ($choice eq 'delete') { if ($role eq 'st') { - &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid,'',$context,$credits); + &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$now, @@ -4874,7 +5327,7 @@ sub update_user_list { } if ($choice eq 'reenable') { if ($role eq 'st') { - $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits); + $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end, @@ -4882,14 +5335,14 @@ sub update_user_list { } } elsif ($choice eq 'activate') { if ($role eq 'st') { - $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits); + $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end, $now,'','',$context); } } elsif ($choice eq 'chgdates') { if ($role eq 'st') { - $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits); + $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end, $start,'','',$context); @@ -4959,7 +5412,7 @@ sub update_user_list { } else { if ($role eq 'st') { $result = - &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid,'',$context,$credits); + &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { my $newscope = $scopestem; $result = &Apache::lonnet::assignrole($udom,$uname,$newscope,$role,$end,$start,'','',$context); @@ -4973,7 +5426,7 @@ sub update_user_list { foreach my $newsec (@newsecs) { if (!grep(/^\Q$newsec\E$/,@retained)) { if ($role eq 'st') { - $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid,'',$context,$credits); + $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); if (@newsecs > 1) { my $showsingle; if ($newsec eq '') { @@ -5151,18 +5604,25 @@ sub active_student_roles { sub section_check_js { my $groupslist= &get_groupslist(); + my %js_lt = &Apache::lonlocal::texthash( + mayn => 'may not be used as the name for a section, as it is a reserved word.', + plch => 'Please choose a different section name.', + mnot => 'may not be used as a section name, as it is the name of a course group.', + secn => 'Section names and group names must be distinct. Please choose a different section name.', + ); + &js_escape(\%js_lt); return <<"END"; function validate(caller) { var groups = new Array($groupslist); var secname = caller.value; if ((secname == 'all') || (secname == 'none')) { - alert("'"+secname+"' may not be used as the name for a section, as it is a reserved word.\\nPlease choose a different section name."); + alert("'"+secname+"' $js_lt{'mayn'}\\n$js_lt{'plch'}"); return 'error'; } if (secname != '') { for (var k=0; k<groups.length; k++) { if (secname == groups[k]) { - alert("'"+secname+"' may not be used as the name for a section, as it is the name of a course group.\\nSection names and group names must be distinct. Please choose a different section name."); + alert("'"+secname+"' $js_lt{'mnot'}\\n$js_lt{'secn'}"); return 'error'; } } @@ -5173,7 +5633,7 @@ END } sub set_login { - my ($dom,$authformkrb,$authformint,$authformloc) = @_; + my ($dom,$authformkrb,$authformint,$authformloc,$authformlti) = @_; my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom); my $response; my ($authnum,%can_assign) = @@ -5195,19 +5655,24 @@ sub set_login { '<td>'.$authformloc.'</td>'. &Apache::loncommon::end_data_table_row()."\n"; } + if ($can_assign{'lti'}) { + $response .= &Apache::loncommon::start_data_table_row(). + '<td>'.$authformlti.'</td>'. + &Apache::loncommon::end_data_table_row()."\n"; + } $response .= &Apache::loncommon::end_data_table(); } return $response; } sub course_sections { - my ($sections_count,$role,$current_sec) = @_; + my ($sections_count,$role,$current_sec,$disabled) = @_; my $output = ''; - my @sections = (sort {$a <=> $b} keys %{$sections_count}); + my @sections = (sort {$a <=> $b} keys(%{$sections_count})); my $numsec = scalar(@sections); my $is_selected = ' selected="selected"'; if ($numsec <= 1) { - $output = '<select name="currsec_'.$role.'" >'."\n". + $output = '<select name="currsec_'.$role.'"'.$disabled.'>'."\n". ' <option value="">'.&mt('Select').'</option>'."\n"; if ($current_sec eq 'none') { $output .= @@ -5230,7 +5695,7 @@ sub course_sections { my $multiple = 4; if (scalar(@sections) < 4) { $multiple = scalar(@sections); } if ($role eq 'st') { - $output .= '>'."\n". + $output .= $disabled.'>'."\n". ' <option value="">'.&mt('Select').'</option>'."\n"; if ($current_sec eq 'none') { $output .= @@ -5240,7 +5705,7 @@ sub course_sections { ' <option value="">'.&mt('No section')."</option>\n"; } } else { - $output .= 'multiple="multiple" size="'.$multiple.'">'."\n"; + $output .= 'multiple="multiple" size="'.$multiple.'"'.$disabled.'>'."\n"; } foreach my $sec (@sections) { if ($current_sec eq $sec) { @@ -5287,7 +5752,7 @@ sub setsections_javascript { } $rolecode = "var match = str.split('_'); var role = match[3];\n"; - } elsif ($formname eq 'enrollstudent') { + } elsif (($formname eq 'enrollstudent') || ($formname eq 'selfenroll')) { $checkincluded = 'formname.name == "'.$formname.'"'; if ($checkauth) { $finish = "var authcheck = auth_check();\n". @@ -5321,7 +5786,8 @@ sub setsections_javascript { mnot => 'may not be used as a section name, as it is the name of a course group.', secn => 'Section names and group names must be distinct. Please choose a different section name.', nonw => 'Section names may only contain letters or numbers.', - ); + ); + &js_escape(\%alerts); $setsection_js .= <<"ENDSECCODE"; function setSections(formname,crstype) { @@ -5332,6 +5798,9 @@ function setSections(formname,crstype) { var groups = new Array($groupslist); for (var i=0;i<formname.elements.length;i++) { var str = formname.elements[i].name; + if (typeof(str) === "undefined") { + continue; + } var checkcurr = str.match(re1); if (checkcurr != null) { var num = i; @@ -5453,6 +5922,9 @@ sub can_create_user { my $cancreate = 1; if (&Apache::lonnet::allowed('mau',$dom)) { return $cancreate; + } elsif ($context eq 'domain') { + $cancreate = 0; + return $cancreate; } if (ref($domconf{'usercreation'}) eq 'HASH') { if (ref($domconf{'usercreation'}{'cancreate'}) eq 'HASH') { @@ -5532,6 +6004,51 @@ sub can_modify_userinfo { return %canmodify; } +sub can_change_internalpass { + my ($uname,$udom,$crstype,$permission) = @_; + my $canchange; + if (&Apache::lonnet::allowed('mau',$udom)) { + $canchange = 1; + } elsif ((ref($permission) eq 'HASH') && ($permission->{'mip'}) && + ($udom eq $env{'request.role.domain'})) { + unless ($env{'course.'.$env{'request.course.id'}.'.internal.nopasswdchg'}) { + my ($cnum,$cdom) = &get_course_identity(); + if ((&Apache::lonnet::is_course_owner($cdom,$cnum)) && ($udom eq $env{'user.domain'})) { + my $noupdate; + my %owned = &Apache::lonnet::courseiddump($cdom,'.',1,'.', + $env{'user.name'}.':'.$env{'user.domain'}, + undef,undef,undef,'.'); + my %roleshash = &Apache::lonnet::get_my_roles($uname,$udom,'userroles', + ['active','future']); + foreach my $key (keys(%roleshash)) { + my ($name,$domain,$role) = split(/:/,$key); + if ($role eq 'st') { + next if (($name eq $cnum) && ($domain eq $cdom)); + if ($owned{$domain.'_'.$name}) { + if (ref($owned{$domain.'_'.$name}) eq 'HASH') { + if ($owned{$domain.'_'.$name}{'nopasswdchg'}) { + $noupdate = 1; + last; + } + } + } else { + $noupdate = 1; + last; + } + } else { + $noupdate = 1; + last; + } + } + unless ($noupdate) { + $canchange = 1; + } + } + } + } + return $canchange; +} + sub check_usertype { my ($dom,$uname,$rules,$curr_rules,$got_rules) = @_; my $usertype; @@ -5595,7 +6112,7 @@ sub roles_by_context { } elsif ($context eq 'author') { @allroles = ('ca','aa'); } elsif ($context eq 'domain') { - @allroles = ('li','ad','dg','sc','au','dc'); + @allroles = ('li','ad','dg','dh','da','sc','au','dc'); } return @allroles; } @@ -5637,6 +6154,39 @@ sub get_permission { if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) { $permission{'grp_manage'} = 1; } + if ($permission{'cusr'}) { + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my %coursehash = ( + 'internal.selfenrollmgrdc' => $env{'course.'.$env{'request.course.id'}.'.internal.selfenrollmgrdc'}, + 'internal.selfenrollmgrcc' => $env{'course.'.$env{'request.course.id'}.'.internal.selfenrollmgrcc'}, + 'internal.coursecode' => $env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}, + 'internal.textbook' =>$env{'course.'.$env{'request.course.id'}.'.internal.textbook'}, + ); + my ($managed_by_cc,$managed_by_dc) = &selfenrollment_administration($cdom,$cnum,$crstype,\%coursehash); + if (ref($managed_by_cc) eq 'ARRAY') { + if (@{$managed_by_cc}) { + $permission{'selfenrolladmin'} = 1; + } + } + } + if ($env{'request.course.id'}) { + my $user; + if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '')) { + $user = $env{'user.name'}.':'.$env{'user.domain'}; + } + if (($user ne '') && ($env{'course.'.$env{'request.course.id'}.'.internal.courseowner'} eq + $user)) { + $permission{'owner'} = 1; + if (&Apache::lonnet::allowed('mip',$env{'request.course.id'})) { + $permission{'mip'} = 1; + } + } elsif (($user ne '') && ($env{'course.'.$env{'request.course.id'}.'.internal.co-owners'} ne '')) { + if (grep(/^\Q$user\E$/,split(/,/,$env{'course.'.$env{'request.course.id'}.'.internal.co-owners'}))) { + $permission{'co-owner'} = 1; + } + } + } } elsif ($context eq 'author') { $permission{'cusr'} = &authorpriv($env{'user.name'},$env{'request.role.domain'}); $permission{'view'} = $permission{'cusr'}; @@ -5656,7 +6206,15 @@ sub get_permission { if (&Apache::lonnet::allowed('ccr',$env{'request.role.domain'})) { $permission{'custom'} = 1; } - $permission{'view'} = $permission{'cusr'}; + if (&Apache::lonnet::allowed('vac',$env{'request.role.domain'})) { + $permission{'activity'} = 1; + } + if (&Apache::lonnet::allowed('vur',$env{'request.role.domain'})) { + $permission{'view'} = 1; + } + if (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'})) { + $permission{'owner'} = 1; + } } my $allowed = 0; foreach my $perm (values(%permission)) { @@ -5709,7 +6267,7 @@ sub get_course_identity { } sub dc_setcourse_js { - my ($formname,$mode,$context,$showcredits) = @_; + my ($formname,$mode,$context,$showcredits,$domain) = @_; my ($dc_setcourse_code,$authen_check); my $cctext = &Apache::lonnet::plaintext('cc'); my $cotext = &Apache::lonnet::plaintext('co'); @@ -5718,7 +6276,7 @@ sub dc_setcourse_js { if ($mode eq 'upload') { $role = 'courserole'; } else { - $authen_check = &verify_authen($formname,$context); + $authen_check = &verify_authen($formname,$context,$domain); } $dc_setcourse_code = (<<"SCRIPTTOP"); $authen_check @@ -5862,12 +6420,14 @@ ENDSCRIPT } sub verify_authen { - my ($formname,$context) = @_; + my ($formname,$context,$domain) = @_; my %alerts = &authcheck_alerts(); my $finish = "return 'ok';"; if ($context eq 'author') { $finish = "document.$formname.submit();"; } + my ($numrules,$intargjs) = + &passwd_validation_js('argpicked',$domain); my $outcome = <<"ENDSCRIPT"; function auth_check() { @@ -5901,6 +6461,7 @@ function auth_check() { break; case 'int': alertmsg = '$alerts{'ipass'}'; + break; case 'fsys': alertmsg = '$alerts{'ipass'}'; break; @@ -5914,6 +6475,11 @@ function auth_check() { alert(alertmsg); return; } + } else if (logintype == 'int') { + var numrules = $numrules; + if (numrules > 0) { +$intargjs + } } $finish } @@ -5939,6 +6505,7 @@ sub sectioncheck_alerts { thwa => 'There was a problem with your course selection', thwc => 'There was a problem with your community selection', ); + &js_escape(\%alerts); return %alerts; } @@ -5949,6 +6516,7 @@ sub authcheck_alerts { krb => 'You need to specify the Kerberos domain.', ipass => 'You need to specify the initial password.', ); + &js_escape(\%alerts); return %alerts; } @@ -5967,5 +6535,570 @@ sub is_courseowner { return; } +sub get_selfenroll_titles { + my @row = ('types','registered','enroll_dates','access_dates','section', + 'approval','limit'); + my %lt = &Apache::lonlocal::texthash ( + types => 'Users allowed to self-enroll', + registered => 'Registration status (official courses)' , + enroll_dates => 'Dates self-enrollment available', + access_dates => 'Access dates for self-enrolling users', + section => "Self-enrolling users' section", + approval => 'Processing of requests', + limit => 'Enrollment limit', + ); + return (\@row,\%lt); +} + +sub selfenroll_default_descs { + my %desc = ( + types => { + dom => &mt('Course domain'), + all => &mt('Any domain'), + '' => &mt('None'), + }, + limit => { + none => &mt('No limit'), + allstudents => &mt('Limit by total students'), + selfenrolled => &mt('Limit by total self-enrolled'), + }, + approval => { + '0' => &mt('Processed automatically'), + '1' => &mt('Queued for approval'), + '2' => &mt('Queued, pending validation'), + }, + registered => { + 0 => 'No registration required', + 1 => 'Registered students only', + }, + ); + return %desc; +} + +sub selfenroll_validation_types { + my @items = ('url','fields','button','markup'); + my %names = &Apache::lonlocal::texthash ( + url => 'Web address of validation server/script', + fields => 'Form fields to send to validator', + button => 'Text for validation button', + markup => 'Validation description (HTML)', + ); + my @fields = ('username','domain','uniquecode','course','coursetype','description'); + return (\@items,\%names,\@fields); +} + +sub get_extended_type { + my ($cdom,$cnum,$crstype,$current) = @_; + my $type = 'unofficial'; + my %settings; + if (ref($current) eq 'HASH') { + %settings = %{$current}; + } else { + %settings = &Apache::lonnet::get('environment',['internal.coursecode','internal.textbook'],$cdom,$cnum); + } + if ($crstype eq 'Community') { + $type = 'community'; + } elsif ($crstype eq 'Placement') { + $type = 'placement'; + } elsif ($settings{'internal.coursecode'}) { + $type = 'official'; + } elsif ($settings{'internal.textbook'}) { + $type = 'textbook'; + } + return $type; +} + +sub selfenrollment_administration { + my ($cdom,$cnum,$crstype,$coursehash) = @_; + my %settings; + if (ref($coursehash) eq 'HASH') { + %settings = %{$coursehash}; + } else { + %settings = &Apache::lonnet::get('environment', + ['internal.selfenrollmgrdc','internal.selfenrollmgrcc', + 'internal.coursecode','internal.textbook'],$cdom,$cnum); + } + my ($possconfigs) = &get_selfenroll_titles(); + my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom); + my $selfenrolltype = &get_extended_type($cdom,$cnum,$crstype,\%settings); + + my (@in_course,@in_domain); + if ($settings{'internal.selfenrollmgrcc'} ne '') { + @in_course = split(/,/,$settings{'internal.selfenrollmgrcc'}); + my @diffs = &Apache::loncommon::compare_arrays($possconfigs,\@in_course); + unless (@diffs) { + return (\@in_course,\@in_domain); + } + } + if ($settings{'internal.selfenrollmgrdc'} ne '') { + my @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'}); + my @diffs = &Apache::loncommon::compare_arrays(\@in_domain,$possconfigs); + unless (@diffs) { + return (\@in_course,\@in_domain); + } + } + my @combined = @in_course; + push(@combined,@in_domain); + my @diffs = &Apache::loncommon::compare_arrays(\@combined,$possconfigs); + unless (@diffs) { + return (\@in_course,\@in_domain); + } + if ($domdefaults{$selfenrolltype.'selfenrolladmdc'} eq '') { + push(@in_course,@diffs); + } else { + my @defaultdc = split(/,/,$domdefaults{$selfenrolltype.'selfenrolladmdc'}); + foreach my $item (@diffs) { + if (grep(/^\Q$item\E$/,@defaultdc)) { + push(@in_domain,$item); + } else { + push(@in_course,$item); + } + } + } + return (\@in_course,\@in_domain); +} + +sub custom_role_header { + my ($context,$crstype,$templaterolerefs,$prefix) = @_; + my %lt = &Apache::lonlocal::texthash( + sele => 'Select a Template', + ); + my ($context_code,$button_code); + if ($context eq 'domain') { + $context_code = &custom_coursetype_switch($crstype,$prefix); + } + if (ref($templaterolerefs) eq 'ARRAY') { + foreach my $role (@{$templaterolerefs}) { + my $display = 'inline'; + if (($context eq 'domain') && ($role eq 'co')) { + $display = 'none'; + } + $button_code .= &make_button_code($role,$crstype,$display,$prefix).' '; + } + } + return <<"END"; +<div class="LC_left_float"> +<fieldset> +<legend>$lt{'sele'}</legend> +$button_code +</fieldset></div> +$context_code +<br clear="all" /> +END +} + +sub custom_coursetype_switch { + my ($crstype,$prefix) = @_; + my ($checkedcourse,$checkedcommunity); + if ($crstype eq 'Community') { + $checkedcommunity = ' checked="checked"'; + } else { + $checkedcourse = ' checked="checked"'; + } + my %lt = &Apache::lonlocal::texthash( + cont => 'Context', + cour => 'Course', + comm => 'Community', + ); + return <<"END"; +<div class="LC_left_float"> +<fieldset> +<legend>$lt{'cont'}</legend> +<label> +<input type="radio" name="${prefix}_custrolecrstype" value="Course"$checkedcourse onclick="javascript:customSwitchType('$prefix');" /> +$lt{'cour'} +</label> +<label> +<input type="radio" name="${prefix}_custrolecrstype" value="Community"$checkedcommunity onclick="javascript:customSwitchType('$prefix');" /> +$lt{'comm'} +</label> +</fieldset> +</div> +END +} + +sub custom_role_table { + my ($crstype,$full,$levels,$levelscurrent,$prefix,$add_class,$id) = @_; + return unless ((ref($full) eq 'HASH') && (ref($levels) eq 'HASH') && + (ref($levelscurrent) eq 'HASH')); + my %lt=&Apache::lonlocal::texthash ( + 'prv' => "Privilege", + 'crl' => "Course Level", + 'dml' => "Domain Level", + 'ssl' => "System Level"); + my %cr = ( + course => '_c', + domain => '_d', + system => '_s', + ); + + my $output=&Apache::loncommon::start_data_table($add_class,$id). + &Apache::loncommon::start_data_table_header_row(). + '<th>'.$lt{'prv'}.'</th><th>'.$lt{'crl'}.'</th><th>'.$lt{'dml'}. + '</th><th>'.$lt{'ssl'}.'</th>'. + &Apache::loncommon::end_data_table_header_row(); + foreach my $priv (sort(keys(%{$full}))) { + my $privtext = &Apache::lonnet::plaintext($priv,$crstype); + $output .= &Apache::loncommon::start_data_table_row(). + '<td><span id="'.$prefix.$priv.'">'.$privtext.'</span></td>'; + foreach my $type ('course','domain','system') { + if (($type eq 'system') && ($priv eq 'bre') && ($crstype eq 'Community')) { + $output .= '<td> </td>'; + } else { + $output .= '<td>'. + ($levels->{$type}{$priv}?'<input type="checkbox" id="'.$prefix.$priv.$cr{$type}.'"'. + ' name="'.$prefix.$priv.$cr{$type}.'"'. + ($levelscurrent->{$type}{$priv}?' checked="checked"':'').' />':' '). + '</td>'; + } + } + $output .= &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::end_data_table(); + return $output; +} + +sub custom_role_privs { + my ($privs,$full,$levels,$levelscurrent)= @_; + return unless ((ref($privs) eq 'HASH') && (ref($full) eq 'HASH') && + (ref($levels) eq 'HASH') && (ref($levelscurrent) eq 'HASH')); + my %cr = ( + course => 'cr:c', + domain => 'cr:d', + system => 'cr:s', + ); + foreach my $type ('course','domain','system') { + foreach my $item (split(/\:/,$Apache::lonnet::pr{$cr{$type}})) { + my ($priv,$restrict)=split(/\&/,$item); + if (!$restrict) { $restrict='F'; } + $levels->{$type}->{$priv}=$restrict; + if ($privs->{$type}=~/\:$priv/) { + $levelscurrent->{$type}->{$priv}=1; + } + $full->{$priv}=1; + } + } + return; +} + +sub custom_template_roles { + my ($context,$crstype) = @_; + my @template_roles = ("in","ta","ep"); + if (($context eq 'domain') || ($context eq 'domprefs')) { + push(@template_roles,"ad"); + } + push(@template_roles,"st"); + if ($context eq 'domain') { + unshift(@template_roles,('co','cc')); + } else { + if ($crstype eq 'Community') { + unshift(@template_roles,'co'); + } else { + unshift(@template_roles,'cc'); + } + } + return @template_roles; +} + +sub custom_roledefs_js { + my ($context,$crstype,$formname,$full,$templaterolesref,$jsback) = @_; + my $button_code = "\n"; + my $head_script = "\n"; + my (%roletitlestr,$rolenamestr); + my %role_titles = ( + Course => [], + Community => [], + ); + $head_script .= '<script type="text/javascript">'."\n" + .'// <![CDATA['."\n"; + if (ref($templaterolesref) eq 'ARRAY') { + if ($context eq 'domain') { + $rolenamestr = join("','",@{$templaterolesref}); + } + foreach my $role (@{$templaterolesref}) { + $head_script .= &make_script_template($role,$crstype,$formname); + if ($context eq 'domain') { + foreach my $type ('Course','Community') { + push(@{$role_titles{$type}},&Apache::lonnet::plaintext($role,$type)); + } + } + } + } + if ($context eq 'domain') { + foreach my $type ('Course','Community') { + $roletitlestr{$type} = join("','",@{$role_titles{$type}}); + } + my %pt = ( + Community => { + cst => &mt('Grant/revoke role of Member'), + mdc => &mt('Edit community contents'), + pch => &mt('Post discussion on community resources'), + pfo => &mt('Print for other users and entire community'), + }, + Course => { + cst => &mt('Grant/revoke role of Student'), + mdc => &mt('Edit course contents'), + pch => &mt('Post discussion on course resources'), + pfo => &mt('Print for other users and entire course'), + }, + ); + $head_script .= <<"ENDJS"; +function customSwitchType(prefix) { + var privnames = new Array('cst','mdc','pch','pfo'); + var privtxtcrs = new Array('$pt{Course}{cst}','$pt{Course}{mdc}','$pt{Course}{pch}','$pt{Course}{pfo}'); + var privtxtcom = new Array('$pt{Community}{cst}','$pt{Community}{mdc}','$pt{Community}{pch}','$pt{Community}{pfo}'); + var rolenames = new Array('$rolenamestr'); + var rolescrs = new Array('$roletitlestr{Course}'); + var rolescom = new Array('$roletitlestr{Community}'); + var radio = prefix+'_custrolecrstype'; + if (document.$formname.elements[radio].length > 1) { + for (var i=0; i<document.$formname.elements[radio].length; i++) { + if (document.$formname.elements[radio][i].checked) { + if ((document.getElementById(prefix+'bre_s')) && (document.getElementById(prefix+'bro_s'))) { + if (document.$formname.elements[radio][i].value == 'Community') { + if (document.getElementById(prefix+'bre_s').checked) { + document.getElementById(prefix+'bro_s').checked = true; + document.getElementById(prefix+'bre_s').checked = false; + + } + document.getElementById(prefix+'bre_s').style.visibility = 'hidden'; + } else { + document.getElementById(prefix+'bre_s').style.visibility = 'visible'; + if (document.getElementById(prefix+'bro_s').checked) { + document.getElementById(prefix+'bre_s').checked = true; + document.getElementById(prefix+'bro_s').checked = false; + } + } + } + for (var j=0; j<privnames.length; j++) { + if (document.getElementById(prefix+privnames[j])) { + if (document.getElementById(prefix+privnames[j])) { + if (document.$formname.elements[radio][i].value == 'Course') { + document.getElementById(prefix+privnames[j]).innerHTML = privtxtcrs[j]; + } else { + document.getElementById(prefix+privnames[j]).innerHTML = privtxtcom[j]; + } + } + } + } + for (var j=0; j<rolenames.length; j++) { + if (document.getElementById(prefix+rolenames[j])) { + if (document.getElementById(prefix+rolenames[j])) { + if (document.$formname.elements[radio][i].value == 'Course') { + document.getElementById(prefix+rolenames[j]).value = rolescrs[j]; + if (rolenames[j] == 'cc') { + document.getElementById(prefix+rolenames[j]).style.display = 'inline'; + } + if (rolenames[j] == 'co') { + document.getElementById(prefix+rolenames[j]).style.display = 'none'; + } + } else { + document.getElementById(prefix+rolenames[j]).value = rolescom[j]; + if (rolenames[j] == 'cc') { + document.getElementById(prefix+rolenames[j]).style.display = 'none'; + } + if (rolenames[j] == 'co') { + document.getElementById(prefix+rolenames[j]).style.display = 'inline'; + } + } + } + } + } + } + } + } + return; +} +ENDJS + } + $head_script .= "\n".$jsback."\n" + .'// ]]>'."\n" + .'</script>'."\n"; + return $head_script; +} + +# -------------------------------------------------------- +sub make_script_template { + my ($role,$crstype,$formname) = @_; + my $return_script = 'function set_'.$role.'(prefix) {'."\n"; + my (%full_by_level,%role_priv); + foreach my $level ('c','d','s') { + foreach my $item (split(/\:/,$Apache::lonnet::pr{'cr:'.$level})) { + next if (($level eq 's') && ($crstype eq 'Community') && ($item eq 'bre&S')); + my ($priv,$restrict)=split(/\&/,$item); + $full_by_level{$level}{$priv}=1; + } + $role_priv{$level} = {}; + my @temp = split(/:/,$Apache::lonnet::pr{$role.':'.$level}); + foreach my $priv (@temp) { + my ($priv_item, $dummy) = split(/\&/,$priv); + $role_priv{$level}{$priv_item} = 1; + } + } + my %to_check = ( + c => ['c','d','s'], + d => ['d','s'], + s => ['s'], + ); + foreach my $level ('c','d','s') { + if (ref($full_by_level{$level}) eq 'HASH') { + foreach my $priv (keys(%{$full_by_level{$level}})) { + my $value = 'false'; + if (ref($to_check{$level}) eq 'ARRAY') { + foreach my $lett (@{$to_check{$level}}) { + if (exists($role_priv{$lett}{$priv})) { + $value = 'true'; + last; + } + } + $return_script .= "document.$formname.elements[prefix+'".$priv."_".$level."'].checked = $value;\n"; + } + } + } + } + $return_script .= '}'."\n"; + return ($return_script); +} +# ---------------------------------------------------------- +sub make_button_code { + my ($role,$crstype,$display,$prefix) = @_; + my $label = &Apache::lonnet::plaintext($role,$crstype); + my $button_code = '<input type="button" onclick="set_'.$role."('$prefix'".')" '. + 'id="'.$prefix.$role.'" value="'.$label.'" '. + 'style="display:'.$display.'" />'; + return ($button_code); +} + +sub custom_role_update { + my ($rolename,$prefix) = @_; +# ------------------------------------------------------- What can be assigned? + my %privs = ( + c => '', + d => '', + s => '', + ); + foreach my $level (keys(%privs)) { + foreach my $item (split(/\:/,$Apache::lonnet::pr{'cr:'.$level})) { + my ($priv,$restrict)=split(/\&/,$item); + if (!$restrict) { $restrict=''; } + if ($env{'form.'.$prefix.$priv.'_'.$level}) { + $privs{$level} .=':'.$item; + } + } + } + return %privs; +} + +sub adhoc_status_types { + my ($cdom,$context,$role,$selectedref,$othertitle,$usertypes,$types,$disabled) = @_; + my $output = &Apache::loncommon::start_data_table(); + my $numinrow = 3; + my $rem; + if (ref($types) eq 'ARRAY') { + for (my $i=0; $i<@{$types}; $i++) { + if (defined($usertypes->{$types->[$i]})) { + my $rem = $i%($numinrow); + if ($rem == 0) { + if ($i > 0) { + $output .= &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::start_data_table_row(); + } + my $check; + if (ref($selectedref) eq 'ARRAY') { + if (grep(/^\Q$types->[$i]\E$/,@{$selectedref})) { + $check = ' checked="checked"'; + } + } + $output .= '<td>'. + '<span class="LC_nobreak"><label>'. + '<input type="checkbox" name="'.$context.$role.'_status" '. + 'value="'.$types->[$i].'"'.$check.$disabled.' />'. + $usertypes->{$types->[$i]}.'</label></span></td>'; + } + } + $rem = @{$types}%($numinrow); + } + my $colsleft = $numinrow - $rem; + if (($rem == 0) && (@{$types} > 0)) { + $output .= &Apache::loncommon::start_data_table_row(); + } + if ($colsleft > 1) { + $output .= '<td colspan="'.$colsleft.'">'; + } else { + $output .= '<td>'; + } + my $defcheck; + if (ref($selectedref) eq 'ARRAY') { + if (grep(/^default$/,@{$selectedref})) { + $defcheck = ' checked="checked"'; + } + } + $output .= '<span class="LC_nobreak"><label>'. + '<input type="checkbox" name="'.$context.$role.'_status"'. + 'value="default"'.$defcheck.$disabled.' />'. + $othertitle.'</label></span></td>'. + &Apache::loncommon::end_data_table_row(). + &Apache::loncommon::end_data_table(); + return $output; +} + +sub adhoc_staff { + my ($access,$context,$role,$selectedref,$adhocref,$disabled) = @_; + my $output; + if (ref($adhocref) eq 'HASH') { + my %by_fullname; + my $numinrow = 4; + my $rem; + my @personnel = keys(%{$adhocref}); + if (@personnel) { + foreach my $person (@personnel) { + my ($uname,$udom) = split(/:/,$person); + my $fullname = &Apache::loncommon::plainname($uname,$udom,'lastname'); + $by_fullname{$fullname} = $person; + } + my @sorted = sort(keys(%by_fullname)); + my $count = scalar(@sorted); + $output = &Apache::loncommon::start_data_table(); + for (my $i=0; $i<$count; $i++) { + my $rem = $i%($numinrow); + if ($rem == 0) { + if ($i > 0) { + $output .= &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::start_data_table_row(); + } + my $check; + my $user = $by_fullname{$sorted[$i]}; + if (ref($selectedref) eq 'ARRAY') { + if (grep(/^\Q$user\E$/,@{$selectedref})) { + $check = ' checked="checked"'; + } + } + if ($i == $count-1) { + my $colsleft = $numinrow - $rem; + if ($colsleft > 1) { + $output .= '<td colspan="'.$colsleft.'">'; + } else { + $output .= '<td>'; + } + } else { + $output .= '<td>'; + } + $output .= '<span class="LC_nobreak"><label>'. + '<input type="checkbox" name="'.$context.$role.'_staff_'.$access.'" '. + 'value="'.$user.'"'.$check.$disabled.' />'.$sorted[$i]. + '</label></span></td>'; + if ($i == $count-1) { + $output .= &Apache::loncommon::end_data_table_row(); + } + } + $output .= &Apache::loncommon::end_data_table(); + } + } + return $output; +} + + 1;