--- loncom/interface/lonuserutils.pm 2013/08/29 12:35:32 1.154 +++ loncom/interface/lonuserutils.pm 2021/08/23 20:10:40 1.208 @@ -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.208 2021/08/23 20:10:40 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 .= (< 0) { +$intargjs + } } END } @@ -623,6 +650,138 @@ 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; + $min = $Apache::lonnet::passwdmin; + if (ref($passwdconf{'chars'}) eq 'ARRAY') { + if ($passwdconf{'min'} =~ /^\d+$/) { + if ($passwdconf{'min'} > $min) { + $min = $passwdconf{'min'}; + } + } + if ($passwdconf{'max'} =~ /^\d+$/) { + $max = $passwdconf{'max'}; + $numrules ++; + } + @chars = @{$passwdconf{'chars'}}; + if (@chars) { + $numrules ++; + } + } + if ($min > 0) { + $numrules ++; + } + if (($min > 0) || ($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{'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 +941,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 +1039,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 +1068,7 @@ sub print_upload_manager_footer { &Apache::loncommon::help_open_topic('Auth_Options'). "

\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 +1085,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 +1181,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 +1217,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 +1248,15 @@ sub get_defaultcredits { sub forceid_change { my ($context) = @_; my $output = - &Apache::lonhtmlcommon::row_title(&mt('Student/Employee ID')) - .'
'."\n" - .&mt('(only do if you know what you are doing.)')."\n"; + ''.&Apache::loncommon::help_open_topic('ForceIDChange')."\n"; if ($context eq 'domain') { - $output .= '
'."\n"; + $output .= + '
' + .''."\n"; } - $output .= &Apache::lonhtmlcommon::row_closure(1); # last row in pick_box return $output; } @@ -1100,8 +1269,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('

'.&mt('Error').': '. + &mt('Invalid datatoken').'

'); + return 'missingdata'; } my @records=&Apache::loncommon::upfile_record_sep(); if($env{'form.noFirstLine'}){ @@ -1185,6 +1361,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 +1569,9 @@ sub default_role_selector { &default_course_roles($context,$checkpriv,'Course',%customroles)."\n". ''. ''. - ''. ''. '
'. + '
'. $lt{'exs'}.'
  '.$lt{'new'}.'
'. @@ -1526,16 +1703,17 @@ 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+)$/) { + my $role = $1; if ($crstype eq 'Community') { next if ($rolehash{$key} =~ /bre\&S/); } - $returnhash{$1}=$1; + $returnhash{$role}=$role; } } return %returnhash; @@ -1637,7 +1815,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 +1887,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 +2005,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('
' @@ -1988,10 +2172,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 +2211,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 +2264,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 .= '
'; my $usernamelink = $env{'form.usernamelink'}; if ($usernamelink eq '') { @@ -2698,7 +2915,7 @@ END .''.$lt{'owin'} .'
'; } - $output .= "\n".'
'."\n". + $output .= "\n".'
'."\n". &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(); if ($mode eq 'autoenroll') { @@ -2708,11 +2925,17 @@ END } else { $output .= "\n".' '."\n"; if ($actionselect) { - $output .= ''.&mt('Select').''."\n"; + $output .= ''.&mt('Select').''."\n"; } } foreach my $item (@cols) { - $output .= "$lt{$item}\n"; + $output .= ''; + if ($is_sortable{$item}) { + $output .= "$lt{$item}"; + } else { + $output .= $lt{$item}; + } + $output .= "\n"; } my %role_types = &role_type_names(); $output .= &Apache::loncommon::end_data_table_header_row(); @@ -2883,6 +3106,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 +3146,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 +3176,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 +3203,16 @@ END if ($mode eq 'autoenroll') { my $cellentry; if ($in{'type'} eq 'auto') { - $cellentry = ''.&mt('auto').' '; + $cellentry = ''.&mt('auto').' '; $autocount ++; } else { - $cellentry = ''); + 'actionlist" value="'. + &HTML::Entities::encode($checkval,'&<>"').'" />'); + foreach my $item ('start','end') { + $r->print(''); + } + $r->print(''); } else { $r->print(''); } @@ -3015,8 +3280,6 @@ END foreach my $item (@cols) { if ($item eq 'username') { $r->print(''); - } elsif (($item eq 'start' || $item eq 'end') && ($actionselect)) { - $r->print(''."\n"); } elsif ($item eq 'status') { my $showitem = $in{$item}; if (defined($ltstatus{$in{$item}})) { @@ -3043,6 +3306,8 @@ END $r->print(''."\n"); } } + } elsif (($item eq 'authorquota') || ($item eq 'authorusage')) { + $r->print(''."\n"); } else { $r->print(''."\n"); } @@ -3078,10 +3343,10 @@ END $r->print(&Apache::loncommon::end_data_table().'
'); } elsif ($mode eq 'excel') { $excel_workbook->close(); - $r->print(&mt('[_1]Your Excel spreadsheet[_2] is ready for download.', '

','')."

\n"); + $r->print('

'.&mt('[_1]Your Excel spreadsheet[_2] is ready for download.', '','')."

\n"); } elsif ($mode eq 'csv') { close($CSVfile); - $r->print(&mt('[_1]Your CSV file[_2] is ready for download.', '

','')."

\n"); + $r->print('

'.&mt('[_1]Your CSV file[_2] is ready for download.', '','')."

\n"); $r->rflush(); } if ($mode eq 'autoenroll') { @@ -3113,6 +3378,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; @@ -3401,6 +3670,8 @@ END setSections(formname,'$crstype'); if (seccheck == 'ok') { opener.document.$callingform.newsecs.value = formname.sections.value; + } else { + return; } END } else { @@ -3779,7 +4050,6 @@ sub show_drop_list { $check_uncheck_js // ]]> -

END my ($indexhash,$keylist) = &make_keylist_array(); @@ -3816,6 +4086,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 +4105,7 @@ END

- + @@ -3848,21 +4119,21 @@ END $r->print(<  END $r->print(&Apache::loncommon::end_data_table_header_row()); @@ -3933,7 +4204,6 @@ END $btn = $lt{'dm'}; } $r->print(<<"END"); -

  @@ -3986,7 +4256,7 @@ sub print_first_users_upload_form { .&Apache::lonhtmlcommon::end_pick_box(); $str .= '

' - .'' .'

'; @@ -3997,7 +4267,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 +4284,6 @@ sub upfile_drop_add { $fields{$env{'form.f'.$i}}=$keyfields[$i]; } } - if ($env{'form.fullup'} ne 'yes') { - $r->print(''."\n". - ''); - } # # Store the field choices away my @storefields = qw/username names fname mname lname gen id @@ -4028,17 +4297,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 +4320,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(''.&mt('Error').': '. + &mt('Enrollment of users not permitted for specified default domain: [_1].', + &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).''); + 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(''.&mt('Error').': '. + &mt('Addition of users not permitted for specified default domain: [_1].', + &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).''); + 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(''.&mt('Error').': '. + &mt('Addition of users not permitted for specified default domain: [_1].', + &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).''); + return 'untrusted'; + } + } + } } else { $domain = $defdom; } @@ -4059,10 +4370,9 @@ sub upfile_drop_add { } else { my %home_servers = &Apache::lonnet::get_servers($defdom,'library'); if (! exists($home_servers{$desiredhost})) { - $r->print(''.&mt('Error'). - &mt('Invalid home server specified').''); - $r->print(&Apache::loncommon::end_page()); - return; + $r->print('

'.&mt('Error').': '. + &mt('Invalid home server specified').'

'); + return 'invalidhome'; } } # Determine authentication mechanism @@ -4072,6 +4382,7 @@ sub upfile_drop_add { } my $amode = ''; my $genpwd = ''; + my @genpwdfail; if ($env{'form.login'} eq 'krb') { $amode='krb'; $amode.=$env{'form.krbver'}; @@ -4080,12 +4391,16 @@ sub upfile_drop_add { $amode='internal'; if ((defined($env{'form.intarg'})) && ($env{'form.intarg'})) { $genpwd=$env{'form.intarg'}; + @genpwdfail = + &Apache::loncommon::check_passwd_rules($domain,$genpwd); } } elsif ($env{'form.login'} eq 'loc') { $amode='localauth'; 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 '') { @@ -4158,10 +4473,14 @@ sub upfile_drop_add { \@statuses,\@poss_roles); &gather_userinfo($context,'view',\%userlist,$indexhash,\%info, \%cstr_roles,$permission); - } } } + if ($datatoken eq '') { + $r->print('

'.&mt('Error').': '. + &mt('Invalid datatoken').'

'); + return 'missingdata'; + } if ( $domain eq &LONCAPA::clean_domain($domain) && ($amode ne '')) { ####################################### @@ -4231,7 +4550,12 @@ 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, + %showpasswdrules,$haspasswdmap); + 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 +4587,42 @@ sub upfile_drop_add { if ($entries{$fields{'username'}} =~ /\s/) { $nowhitespace = ' - '.&mt('usernames may not contain spaces.'); } - $r->print('
'. - &mt('[_1]: Unacceptable username for user [_2] [_3] [_4] [_5]', - ''.$entries{$fields{'username'}}.'',$fname,$mname,$lname,$gen). - $nowhitespace); + $disallow{$counter} = + &mt('Unacceptable username [_1] for user [_2] [_3] [_4] [_5]', + '"'.$entries{$fields{'username'}}.'"', + $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('
'. ''.$entries{$fields{'domain'}}. - ': '.&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]', + '"'.$entries{$fields{'domain'}}.'"', + $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]', + '"'.$possdom.'"', + $fname,$mname,$lname,$gen); + next; + } } my $username = $entries{$fields{'username'}}; my $userdomain = $entries{$fields{'domain'}}; @@ -4286,10 +4634,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('
'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a reserved word.',''.$username.'',$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.', + ''.$username.'',$fname,$mname,$lname,$gen,$item); next; } elsif (exists($curr_groups{$item})) { - $r->print('
'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a course group.',''.$username.'',$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.', + ''.$username.'',$fname,$mname,$lname,$gen,$item).' '. + &mt('Section names and group names must be distinct.'); next; } else { push(@secs,$item); @@ -4301,14 +4654,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('
'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".',''.$username.'',$fname,$mname,$lname,$gen,$secs[0]).'
'); + $disallow{$counter} = + &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".', + ''.$username.'',$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('
'.&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]).'
'); + $disallow{$counter} .= + '
'. + &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; } } @@ -4342,11 +4702,43 @@ sub upfile_drop_add { } } # determine user password - my $password = $genpwd; + my $password; + my $passwdfromfile; if (defined($fields{'ipwd'})) { if ($entries{$fields{'ipwd'}}) { $password=$entries{$fields{'ipwd'}}; + $passwdfromfile = 1; + if ($env{'form.login'} eq 'int') { + my $uhome=&Apache::lonnet::homeserver($username,$userdomain); + if (($uhome eq 'no_host') || ($changeauth)) { + my @brokepwdrules = + &Apache::loncommon::check_passwd_rules($domain,$password); + if (@brokepwdrules) { + $disallow{$counter} = &mt('[_1]: Password included in file for this user did not meet requirements.', + ''.$username.''); + map { $showpasswdrules{$_} = 1; } @brokepwdrules; + next; + } + } + } + } + } + unless ($passwdfromfile) { + if ($env{'form.login'} eq 'int') { + if (@genpwdfail) { + my $uhome=&Apache::lonnet::homeserver($username,$userdomain); + if (($uhome eq 'no_host') || ($changeauth)) { + $disallow{$counter} = &mt('[_1]: No specific password in file for this user; default password did not meet requirements', + ''.$username.''); + unless ($haspasswdmap) { + map { $showpasswdrules{$_} = 1; } @genpwdfail; + $haspasswdmap = 1; + } + } + next; + } } + $password = $genpwd; } # determine user role my $role = ''; @@ -4360,13 +4752,12 @@ sub upfile_drop_add { } if ($role eq '') { my $rolestr = join(', ',@permitted_roles); - $r->print('
' - .&mt('[_1]: You do not have permission to add the requested role [_2] for the user.' - ,''.$entries{$fields{'username'}}.'' - ,$entries{$fields{'role'}}) - .'
' - .&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.' + ,''.$entries{$fields{'username'}}.'' + ,$entries{$fields{'role'}}) + .'
' + .&mt('Allowable role(s) is/are: [_1].',$rolestr); next; } } @@ -4396,55 +4787,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('
'. - &mt('[_1]: The domain specified ([_2]) is different to that of the course.', - ''.$username.'',$userdomain).'
'); + $disallow{$counter} = + &mt('[_1]: The domain specified ([_2]) is different to that of the course.', + ''.$username.'',$userdomain); } elsif ($context eq 'author') { - $r->print(&mt('[_1]: The domain specified ([_2]) is different to that of the author.', - ''.$username.'',$userdomain).'
'); + $disallow{$counter} = + &mt('[_1]: The domain specified ([_2]) is different to that of the author.', + ''.$username.'',$userdomain); } else { - $r->print(&mt('[_1]: The domain specified ([_2]) is different to that of your current role.', - ''.$username.'',$userdomain).'
'); + $disallow{$counter} = + &mt('[_1]: The domain specified ([_2]) is different to that of your current role.', + ''.$username.'',$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.', + ''.$username.''); + 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('
'. - &mt('[_1]: matches the username format at your institution, but is not known to your directory service.',''.$username.'').'
'. - &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('
'. - &mt('[_1]: The user does not exist, and you are not permitted to create users of type: [_2].',''.$username.'',$showtype)); - next; - } + $checkuname{$username.':'.$newuserdom} = { 'newuser' => $newuser, 'id' => $id }; } else { if ($context eq 'course' || $context eq 'author') { if ($userdomain eq $domain ) { @@ -4477,130 +4849,259 @@ 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').'

'); + $r->rflush(); + } + my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,$total); + $r->print(''); + &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("

\n

\n".&mt('Processed [quant,_1,user].',$counts{'user'}). "

\n"); if ($counts{'role'} > 0) { $r->print("

\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.')."

\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.'). + "

\n"); } else { $r->print('

'.&mt('No roles added').'

'); } @@ -4610,6 +5111,7 @@ sub upfile_drop_add { $counts{'auth'})."

\n"); } $r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules)); + $r->print(&passwdrule_alerts($domain,\%showpasswdrules)); ##################################### # Display list of students to drop # ##################################### @@ -4618,10 +5120,9 @@ sub upfile_drop_add { # Get current classlist my $classlist = &Apache::loncoursedata::get_classlist(); if (! defined($classlist)) { - $r->print(''. - ''. - '

'.&mt('There are no students with current/future access to the course.').'

'. - ''."\n"); + $r->print('

'. + &mt('There are no students with current/future access to the course.'). + '

'."\n"); } elsif (ref($classlist) eq 'HASH') { # Remove the students we just added from the list of students. foreach my $line (@userdata) { @@ -4637,9 +5138,7 @@ sub upfile_drop_add { } } } # end of unless - if ($env{'form.fullup'} ne 'yes') { - $r->print(''); - } + return 'ok'; } sub print_namespacing_alerts { @@ -4682,15 +5181,52 @@ sub print_namespacing_alerts { } } +sub passwdrule_alerts { + my ($domain,$passwdrules) = @_; + my $warning; + if (ref($passwdrules) eq 'HASH') { + my %showrules = %{$passwdrules}; + if (keys(%showrules)) { + my %passwdconf = &Apache::lonnet::get_passwdconf($domain); + $warning = ''.&mt('Password requirement(s) unmet for one or more users:').''; + } + } + return $warning; +} + 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('
'. - &mt('[_1]: Unable to add/modify: [_2]',''.$username.':'.$userdomain.'',$error)); + push(@status, + &mt('[_1]: Unable to add/modify: [_2]',''.$username.':'.$userdomain.'',$error)); } } else { $counts->{'user'} ++; @@ -4699,8 +5235,8 @@ sub user_change_result { if ($authresult ne 'ok') { if ($authresult =~ /^error:(.+)$/) { my $error = $1; - $r->print('
'. - &mt('[_1]: Unable to modify authentication: [_2]',''.$username.':'.$userdomain.'',$error)); + push(@status, + &mt('[_1]: Unable to modify authentication: [_2]',''.$username.':'.$userdomain.'',$error)); } } else { $counts->{'auth'} ++; @@ -4709,8 +5245,8 @@ sub user_change_result { if ($roleresult ne 'ok') { if ($roleresult =~ /^error:(.+)$/) { my $error = $1; - $r->print('
'. - &mt('[_1]: Unable to add role: [_2]',''.$username.':'.$userdomain.'',$error)); + push(@status, + &mt('[_1]: Unable to add role: [_2]',''.$username.':'.$userdomain.'',$error)); } } else { $counts->{'role'} ++; @@ -4719,14 +5255,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('
  • '.join('
    ',@status).'
  • '); } return $flushc; } @@ -4754,7 +5292,7 @@ sub print_drop_menu { } else { &show_drop_list($r,$classlist,'nosort',$permission,$crstype); } - $r->print(''. &Apache::loncommon::end_page()); + $r->print(''); return; } @@ -4797,7 +5335,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 +5348,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 +5369,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 +5393,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 +5401,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 +5414,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 +5422,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 +5499,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 +5513,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 +5691,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'.$authformloc.''. &Apache::loncommon::end_data_table_row()."\n"; } + if ($can_assign{'lti'}) { + $response .= &Apache::loncommon::start_data_table_row(). + ''. + &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 = ''."\n". ' '."\n"; if ($current_sec eq 'none') { $output .= @@ -5230,7 +5782,7 @@ sub course_sections { my $multiple = 4; if (scalar(@sections) < 4) { $multiple = scalar(@sections); } if ($role eq 'st') { - $output .= '>'."\n". + $output .= $disabled.'>'."\n". ' '."\n"; if ($current_sec eq 'none') { $output .= @@ -5240,7 +5792,7 @@ sub course_sections { ' \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 +5839,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 +5873,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 +5885,9 @@ function setSections(formname,crstype) { var groups = new Array($groupslist); for (var i=0;i{'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 @userstatuses = ('default'); + my %userenv = &Apache::lonnet::userenvironment($udom,$uname,'inststatus'); + if ($userenv{'inststatus'} ne '') { + @userstatuses = split(/:/,$userenv{'inststatus'}); + } + my $noupdate = 1; + my %passwdconf = &Apache::lonnet::get_passwdconf($cdom); + if (ref($passwdconf{'crsownerchg'}) eq 'HASH') { + if (ref($passwdconf{'crsownerchg'}{'for'}) eq 'ARRAY') { + foreach my $status (@userstatuses) { + if (grep(/^\Q$status\E$/,@{$passwdconf{'crsownerchg'}{'for'}})) { + undef($noupdate); + last; + } + } + } + } + if ($noupdate) { + return; + } + 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 +6218,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 +6260,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 +6312,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 +6373,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 +6382,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 +6526,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 +6567,7 @@ function auth_check() { break; case 'int': alertmsg = '$alerts{'ipass'}'; + break; case 'fsys': alertmsg = '$alerts{'ipass'}'; break; @@ -5914,6 +6581,11 @@ function auth_check() { alert(alertmsg); return; } + } else if (logintype == 'int') { + var numrules = $numrules; + if (numrules > 0) { +$intargjs + } } $finish } @@ -5939,6 +6611,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 +6622,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 +6641,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"; +
    +
    +$lt{'sele'} +$button_code +
    +$context_code +
    +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"; +
    +
    +$lt{'cont'} +   + +
    +
    +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(). + '
    '. + &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(). + ''; + foreach my $type ('course','domain','system') { + if (($type eq 'system') && ($priv eq 'bre') && ($crstype eq 'Community')) { + $output .= ''; + } else { + $output .= ''; + } + } + $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 .= ''."\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 = ''; + 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 .= ''; + } + } + $rem = @{$types}%($numinrow); + } + my $colsleft = $numinrow - $rem; + if (($rem == 0) && (@{$types} > 0)) { + $output .= &Apache::loncommon::start_data_table_row(); + } + if ($colsleft > 1) { + $output .= ''. + &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 .= ''; + if ($i == $count-1) { + $output .= &Apache::loncommon::end_data_table_row(); + } + } + $output .= &Apache::loncommon::end_data_table(); + } + } + return $output; +} + + 1; 500 Internal Server Error

    Internal Server Error

    The server encountered an internal error or misconfiguration and was unable to complete your request.

    Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

    More information about this error may be available in the server error log.

    '.&mt('manual').'
    '; + $cellentry = '
    '.&mt('manual').'
    '; $manualcount ++; if ($in{'lockedtype'}) { - $cellentry .= ''; + $cellentry .= ''; $unlockcount ++; } else { - $cellentry .= ''; + $cellentry .= ''; $lockcount ++; } $cellentry .= '
    '; @@ -2995,13 +3252,21 @@ END if ($role eq 'st') { $checkval .= ':'.$in{'type'}.':'. $in{'lockedtype'}.':'. - $in{'credits'}; + $in{'credits'}.':'. + &escape($in{'instsec'}); } } } if ($showcheckbox) { $r->print('
     '.&print_username_link($mode,\%in).''.$in{$item}.' '.$in{$item}.''.$in{$item}.'  $lt{'usrn'} $lt{'dom'}ID$lt{'id'} $nametitle $lt{'sec'} $lt{'start'} - $lt{'usrn'} + $lt{'usrn'} - $lt{'dom'} + $lt{'dom'} - ID + $lt{'id'} - $nametitle + $nametitle - $lt{'sec'} + $lt{'sec'} - $lt{'start'} + $lt{'start'} - $lt{'end'} + $lt{'end'} - $lt{'groups'} + $lt{'groups'}
    '.$authformlti.''.$lt{'prv'}.''.$lt{'crl'}.''.$lt{'dml'}. + ''.$lt{'ssl'}.''.$privtext.' '. + ($levels->{$type}{$priv}?'{$type}{$priv}?' checked="checked"':'').' />':' '). + ''. + ''; + } else { + $output .= ''; + } + my $defcheck; + if (ref($selectedref) eq 'ARRAY') { + if (grep(/^default$/,@{$selectedref})) { + $defcheck = ' checked="checked"'; + } + } + $output .= ''; + } else { + $output .= ''; + } + } else { + $output .= ''; + } + $output .= '