--- loncom/interface/lonuserutils.pm 2016/07/24 14:34:59 1.174 +++ loncom/interface/lonuserutils.pm 2022/11/17 19:07:21 1.211 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Utility functions for managing LON-CAPA user accounts # -# $Id: lonuserutils.pm,v 1.174 2016/07/24 14:34:59 raeburn Exp $ +# $Id: lonuserutils.pm,v 1.211 2022/11/17 19:07:21 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -30,6 +30,22 @@ 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(); @@ -422,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". @@ -515,21 +531,28 @@ END /* regexp here to check for non \d \. in credits */ END } else { + my ($numrules,$intargjs) = + &Apache::loncommon::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 = '$alert{'ipass'}'; + break; + case 'loc': alertmsg = ''; break; + case 'lti': default: alertmsg = ''; } @@ -537,6 +560,10 @@ END alert(alertmsg); return; } + } else if (current.radiovalue == 'int') { + if ($numrules > 0) { +$intargjs + } } END } @@ -625,6 +652,7 @@ END $section_checks.$authheader; return $result; } + ############################################################### ############################################################### sub upload_manager_javascript_forward_associate { @@ -882,6 +910,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); @@ -910,7 +939,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', @@ -927,8 +956,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')) @@ -1105,8 +1140,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'}){ @@ -1190,6 +1232,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 { @@ -1531,16 +1574,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; @@ -2263,7 +2307,6 @@ sub build_user_record { sub courses_selector { my ($cdom,$formname) = @_; - my %coursecodes = (); my %codes = (); my @codetitles = (); my %cat_titles = (); @@ -2276,14 +2319,15 @@ sub courses_selector { my $jscript = ''; my $totcodes = 0; - $totcodes = - &Apache::courseclassifier::retrieve_instcodes(\%coursecodes, - $cdom,$totcodes); - if ($totcodes > 0) { - $format_reply = - &Apache::lonnet::auto_instcode_format($caller,$cdom,\%coursecodes, - \%codes,\@codetitles,\%cat_titles,\%cat_order); - if ($format_reply eq 'ok') { + my $instcats = &Apache::lonnet::get_dom_instcats($cdom); + if (ref($instcats) eq 'HASH') { + if ((ref($instcats->{'codetitles'}) eq 'ARRAY') && (ref($instcats->{'codes'}) eq 'HASH') && + (ref($instcats->{'cat_titles'}) eq 'HASH') && (ref($instcats->{'cat_order'}) eq 'HASH')) { + %codes = %{$instcats->{'codes'}}; + @codetitles = @{$instcats->{'codetitles'}}; + %cat_titles = %{$instcats->{'cat_titles'}}; + %cat_order = %{$instcats->{'cat_order'}}; + $totcodes = scalar(keys(%codes)); my $numtypes = @codetitles; &Apache::courseclassifier::build_code_selections(\%codes,\@codetitles,\%cat_titles,\%cat_order,\%idlist,\%idnums,\%idlist_titles); my ($scripttext,$longtitles) = &Apache::courseclassifier::javascript_definitions(\@codetitles,\%idlist,\%idlist_titles,\%idnums,\%cat_titles); @@ -2291,7 +2335,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); @@ -2320,7 +2364,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) { @@ -2547,14 +2592,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(); @@ -2563,7 +2616,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(); } } @@ -2609,6 +2662,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'}; @@ -2699,12 +2753,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 '') { @@ -2727,7 +2786,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') { @@ -2973,6 +3032,12 @@ END } (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}; @@ -3009,16 +3074,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'}.'" /> '.&mt('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'}.'" /> '.&mt('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>'; @@ -3065,7 +3130,14 @@ END } if ($showcheckbox) { $r->print('<td><input type="checkbox" name="'. - 'actionlist" value="'.&HTML::Entities::encode($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>'); } @@ -3079,8 +3151,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="'.&HTML::Entities::encode($checkval.'_'.$item.'" value="'.$sdata->[$index{$item}],'&<>"').'" /></td>'."\n"); } elsif ($item eq 'status') { my $showitem = $in{$item}; if (defined($ltstatus{$in{$item}})) { @@ -3471,6 +3541,8 @@ END setSections(formname,'$crstype'); if (seccheck == 'ok') { opener.document.$callingform.newsecs.value = formname.sections.value; + } else { + return; } END } else { @@ -4055,7 +4127,7 @@ sub print_first_users_upload_form { .&Apache::lonhtmlcommon::end_pick_box(); $str .= '<p>' - .'<input type="submit" name="fileupload" value="'.&mt('Next').'"' + .'<input type="button" name="fileupload" value="'.&mt('Next').'"' .' onclick="javascript:checkUpload(this.form);" />' .'</p>'; @@ -4066,7 +4138,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'}); @@ -4080,10 +4155,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 @@ -4097,17 +4168,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(); @@ -4118,7 +4191,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; } @@ -4128,10 +4241,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 @@ -4141,6 +4253,7 @@ sub upfile_drop_add { } my $amode = ''; my $genpwd = ''; + my @genpwdfail; if ($env{'form.login'} eq 'krb') { $amode='krb'; $amode.=$env{'form.krbver'}; @@ -4149,12 +4262,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 '') { @@ -4227,10 +4344,14 @@ sub upfile_drop_add { \@statuses,\@poss_roles); &gather_userinfo($context,'view',\%userlist,$indexhash,\%info, \%cstr_roles,$permission); - } } } + 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 '')) { ####################################### @@ -4300,8 +4421,10 @@ 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 (%existinguser,%userinfo,%disallow,%rulematch,%inst_results,%alerts,%checkuname, + %showpasswdrules,$haspasswdmap); my $counter = -1; + my (%willtrust,%trustchecked); foreach my $line (@userdata) { $counter ++; my @secs; @@ -4349,6 +4472,28 @@ sub upfile_drop_add { '"<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'}}; @@ -4428,12 +4573,44 @@ 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.', + '<b>'.$username.'</b>'); + 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', + '<b>'.$username.'</b>'); + unless ($haspasswdmap) { + map { $showpasswdrules{$_} = 1; } @genpwdfail; + $haspasswdmap = 1; + } + } + next; + } + } + $password = $genpwd; + } # determine user role my $role = ''; if (defined($fields{'role'})) { @@ -4501,7 +4678,7 @@ sub upfile_drop_add { &mt('The user does not already exist, and you may not create a new user in a different domain.'); next; } else { - unless ($password || $env{'form.login'} eq 'loc') { + 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>'); @@ -4704,6 +4881,16 @@ sub upfile_drop_add { my (%userres,%authres,%roleres,%idres); my $singlesec = ''; if ($role eq 'st') { + if (($context eq 'domain') && ($changeauth eq 'Yes') && (!$newuser)) { + if ((&Apache::lonnet::allowed('mau',$userdomain)) && + (&Apache::lonnet::homeserver($username,$userdomain) ne 'no_host')) { + if ((($amode =~ /^krb4|krb5|internal$/) && $password ne '') || + ($amode eq 'localauth')) { + $authresult = + &Apache::lonnet::modifyuserauth($userdomain,$username,$amode,$password); + } + } + } my $sec; if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') { if (@secs > 0) { @@ -4745,16 +4932,16 @@ sub upfile_drop_add { } } } - if (!$multiple) { - ($userresult,$authresult,$roleresult,$idresult) = - &modifyuserrole($context,$setting, - $changeauth,$cid,$userdomain,$username, - $id,$amode,$password,$fname, - $mname,$lname,$gen,$singlesec, - $env{'form.forceid'},$desiredhost, - $email,$role,$enddate,$startdate, - $checkid,$inststatus); - } + } + if (!$multiple) { + ($userresult,$authresult,$roleresult,$idresult) = + &modifyuserrole($context,$setting, + $changeauth,$cid,$userdomain,$username, + $id,$amode,$password,$fname, + $mname,$lname,$gen,$singlesec, + $env{'form.forceid'},$desiredhost, + $email,$role,$enddate,$startdate, + $checkid,$inststatus); } } if ($multiple) { @@ -4783,7 +4970,9 @@ sub upfile_drop_add { "</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>'); } @@ -4793,6 +4982,7 @@ sub upfile_drop_add { $counts{'auth'})."</p>\n"); } $r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules)); + $r->print(&passwdrule_alerts($domain,\%showpasswdrules)); ##################################### # Display list of students to drop # ##################################### @@ -4801,10 +4991,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) { @@ -4820,9 +5009,7 @@ sub upfile_drop_add { } } } # end of unless - if ($env{'form.fullup'} ne 'yes') { - $r->print('</form>'); - } + return 'ok'; } sub print_namespacing_alerts { @@ -4865,6 +5052,42 @@ 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 = '<b>'.&mt('Password requirement(s) unmet for one or more users:').'</b><ul>'; + if ($showrules{'min'}) { + my $min = $passwdconf{'min'}; + if ($min eq '') { + $min = $Apache::lonnet::passwdmin; + } + $warning .= '<li>'.&mt('minimum [quant,_1,character]',$min).'</li>'; + } + if ($showrules{'max'}) { + $warning .= '<li>'.&mt('maximum [quant,_1,character]',$passwdconf{'max'}).'</li>'; + } + if ($showrules{'uc'}) { + $warning .= '<li>'.&mt('contain at least one upper case letter').'</li>'; + } + if ($showrules{'lc'}) { + $warning .= '<li>'.&mt('contain at least one lower case letter').'</li>'; + } + if ($showrules{'num'}) { + $warning .= '<li>'.&mt('contain at least one number').'</li>'; + } + if ($showrules{'spec'}) { + $warning .= '<li>'.&mt('contain at least one non-alphanumeric').'</li>'; + } + $warning .= '</ul>'; + } + } + return $warning; +} + sub user_change_result { my ($r,$userresult,$authresult,$roleresult,$idresult,$counts,$flushc, $username,$userdomain,$userchg) = @_; @@ -5368,7 +5591,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) = @@ -5390,19 +5613,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 $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 .= @@ -5425,7 +5653,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 .= @@ -5435,7 +5663,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) { @@ -5652,6 +5880,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') { @@ -5731,6 +5962,70 @@ 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 @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; @@ -5794,7 +6089,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; } @@ -5852,6 +6147,23 @@ sub get_permission { } } } + 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'}; @@ -5871,11 +6183,20 @@ 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)) { - if ($perm) { $allowed=1; last; } + foreach my $key (keys(%permission)) { + next if (($key eq 'owner') || ($key eq 'co-owner')); + if ($permission{$key}) { $allowed=1; last; } } return (\%permission,$allowed); } @@ -5924,7 +6245,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'); @@ -5933,7 +6254,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 @@ -6077,12 +6398,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) = + &Apache::loncommon::passwd_validation_js('argpicked',$domain); my $outcome = <<"ENDSCRIPT"; function auth_check() { @@ -6116,6 +6439,7 @@ function auth_check() { break; case 'int': alertmsg = '$alerts{'ipass'}'; + break; case 'fsys': alertmsg = '$alerts{'ipass'}'; break; @@ -6129,6 +6453,11 @@ function auth_check() { alert(alertmsg); return; } + } else if (logintype == 'int') { + var numrules = $numrules; + if (numrules > 0) { +$intargjs + } } $finish } @@ -6307,5 +6636,447 @@ sub selfenrollment_administration { 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;