--- loncom/interface/lonuserutils.pm 2010/02/02 06:05:03 1.97.2.15 +++ loncom/interface/lonuserutils.pm 2019/08/22 19:31:20 1.184.4.4 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Utility functions for managing LON-CAPA user accounts # -# $Id: lonuserutils.pm,v 1.97.2.15 2010/02/02 06:05:03 raeburn Exp $ +# $Id: lonuserutils.pm,v 1.184.4.4 2019/08/22 19:31:20 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); ############################################################### @@ -237,6 +254,8 @@ sub domain_roles_select { # Role types my @roletypes = ('domain','author','course','community'); my %lt = &role_type_names(); + my $onchangefirst = "updateCols('showrole')"; + my $onchangesecond = "updateCols('showrole')"; # # build up the menu information to be passed to # &Apache::loncommon::linked_select_forms @@ -283,7 +302,8 @@ sub domain_roles_select { my $result = &Apache::loncommon::linked_select_forms ('studentform',(' 'x3).&mt('Role: '),$env{'form.roletype'}, 'roletype','showrole',\%select_menus, - ['domain','author','course','community']); + ['domain','author','course','community'],$onchangefirst, + $onchangesecond); return $result; } @@ -295,7 +315,8 @@ sub hidden_input { } sub print_upload_manager_header { - my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission,$crstype)=@_; + my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission,$crstype, + $can_assign)=@_; my $javascript; # if (! exists($env{'form.upfile_associate'})) { @@ -309,9 +330,9 @@ sub print_upload_manager_header { } } if ($env{'form.upfile_associate'} eq 'reverse') { - $javascript=&upload_manager_javascript_reverse_associate(); + $javascript=&upload_manager_javascript_reverse_associate($can_assign); } else { - $javascript=&upload_manager_javascript_forward_associate(); + $javascript=&upload_manager_javascript_forward_associate($can_assign); } # # Deal with restored settings @@ -334,13 +355,22 @@ sub print_upload_manager_header { $env{'request.role.domain'},$context, $groupslist,$crstype); my $checked=(($env{'form.noFirstLine'})?' checked="checked"':''); - $r->print('

' - .&mt('Total number of records found in file: [_1]' - ,''.$distotal.'') - ."

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

'. - &mt('Identify fields in uploaded list')."

\n"); - $r->print(&mt('Enter as many fields as you can.
The system will inform you and bring you back to this page,
if the data selected are insufficient to add users.')."
\n"); + $r->print( + '

'.&mt('Identify fields in uploaded list')."

\n". + '

'. + &mt('Total number of records found in file: [_1]' + ,''.$distotal.''). + "

\n" + ); + if ($distotal == 0) { + $r->print('

'.&mt('None found').'

'); + } + $r->print( + '

'. + &mt('Enter as many fields as you can.').'
'. + &mt('The system will inform you and bring you back to this page,[_1]if the data selected are insufficient to add users.','
'). + "

\n" + ); $r->print(&hidden_input('action','upload'). &hidden_input('state','got_file'). &hidden_input('associate',''). @@ -348,17 +378,23 @@ sub print_upload_manager_header { &hidden_input('fileupload',$env{'form.fileupload'}). &hidden_input('upfiletype',$env{'form.upfiletype'}). &hidden_input('upfile_associate',$env{'form.upfile_associate'})); - $r->print('

'); - $r->print('
print( + '
'. + '
'.&mt('Functions').''. + ''. + ' '); - $r->print("

\n". - ''); + 'onclick="javascript:this.form.associate.value=\'Reverse Association\';submit(this.form);" />'. + '

' + ); + $r->print( + '' + ); } ############################################################### @@ -380,6 +416,12 @@ sub javascript_validations { $param{'curr_autharg'} = $curr_authfield; } + my $showcredits; + my %domdefaults = &Apache::lonnet::get_domain_defaults($domain); + if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'}) { + $showcredits = 1; + } + my ($setsection_call,$setsections_js); my $finish = " vf.submit();\n"; if ($mode eq 'upload') { @@ -389,13 +431,14 @@ sub javascript_validations { $setsection_call = 'setSections(document.'.$param{'formname'}.",'$crstype'".');'; $setsections_js = &setsections_javascript($param{'formname'},$groupslist, - $mode,'',$crstype); + $mode,'',$crstype,$showcredits); } else { $setsection_call = "'ok'"; } } elsif ($context eq 'domain') { $setsection_call = 'setCourse()'; - $setsections_js = &dc_setcourse_js($param{'formname'},$mode,$context); + $setsections_js = &dc_setcourse_js($param{'formname'},$mode, + $context,$showcredits,$domain); } $finish = " var checkSec = $setsection_call\n". " if (checkSec == 'ok') {\n". @@ -418,13 +461,17 @@ sub javascript_validations { domain => 'The optional domain field was not specified.', continue => 'Continue adding users?', ); + if ($showcredits) { + $alert{'credits'} = &mt('The optional credits field was not specified'); + } 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 -function verify_message (vf,founduname,foundpwd,foundname,foundid,foundsec,foundemail,foundrole,founddomain,foundinststatus) { +function verify_message (vf,founduname,foundpwd,foundname,foundid,foundsec,foundemail,foundrole,founddomain,foundinststatus,foundcredits) { END my ($authnum,%can_assign) = &Apache::loncommon::get_assignable_auth($domain); my $auth_checks; @@ -481,22 +528,27 @@ END return; } } +/* 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 } @@ -532,6 +588,7 @@ END if (message!='') { message+='\\n'; } + message+='$alert{'section'}'; } if (foundemail==0) { if (message!='') { @@ -552,6 +609,16 @@ END message+='$alert{'domain'}'; } END + if ($showcredits) { + $optional_checks .= < 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{'krb4'} || $can_assign->{'krb5'}) { + $argreset .= " vf.krbarg.value='';\n"; + $numbuttons ++ ; + } + if ($can_assign->{'int'}) { + $argreset .= " vf.intarg.value='';\n"; + $numbuttons ++; + } + if ($can_assign->{'loc'}) { + $argreset .= " vf.locarg.value='';\n"; + $numbuttons ++; + } + if (!$can_assign->{'int'}) { + my $warning = &mt('You may not specify an initial password for each user, as this is only available when new users use LON-CAPA internal authentication.')."\n". + &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). + if (nw==9) { + eval('vf.f'+tf+'.selectedIndex=0;') + alert('$warning'); + } +END + } elsif ($numbuttons > 1) { + $auth_update = <<"END"; + // If we set the password, make the password form below correspond to + // the new value. + if (nw==9) { + changed_radio('int',document.studentform); + set_auth_radio_buttons('int',document.studentform); +$argreset + } + +END + } + } + return(<{'krb4'} || $can_assign->{'krb5'}) { + $argreset .= " vf.krbarg.value='';\n"; + $numbuttons ++ ; + } + if ($can_assign->{'int'}) { + $argreset .= " vf.intarg.value='';\n"; + $numbuttons ++; + } + if ($can_assign->{'loc'}) { + $argreset .= " vf.locarg.value='';\n"; + $numbuttons ++; + } + 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). + if (tf==8 && nw!=0) { + eval('vf.f'+tf+'.selectedIndex=0;') + alert('$warning'); + } +END + } elsif ($numbuttons > 1) { + $auth_update = <<"END"; + // initial password specified, pick internal authentication + if (tf==8 && nw!=0) { + changed_radio('int',document.studentform); + set_auth_radio_buttons('int',document.studentform); +$argreset + } + +END + } + } + return(<=2) && (tf<=5) && (nw!=0)) { eval('vf.f1.selectedIndex=0;') } - // intial password specified, pick internal authentication - if (tf==8 && nw!=0) { - changed_radio('int',document.studentform); - set_auth_radio_buttons('int',document.studentform); - vf.krbarg.value=''; - vf.intarg.value=''; - vf.locarg.value=''; - } + $auth_update } function clearpwd(vf) { @@ -748,7 +1018,8 @@ ENDPICK ############################################################### ############################################################### sub print_upload_manager_footer { - my ($r,$i,$keyfields,$defdom,$today,$halfyear,$context,$permission,$crstype) = @_; + my ($r,$i,$keyfields,$defdom,$today,$halfyear,$context,$permission,$crstype, + $showcredits) = @_; my $form = 'document.studentform'; my $formname = 'studentform'; my ($krbdef,$krbdefdom) = @@ -837,9 +1108,15 @@ sub print_upload_manager_footer { &mt('Default role')) .&mt('Choose the role to assign to users without a value specified in the uploaded file.') } elsif ($context eq 'course') { - $Str .= &Apache::lonhtmlcommon::row_title( + if ($showcredits) { + $Str .= &Apache::lonhtmlcommon::row_title( + &mt('Default role, section and credits')) + .&mt('Choose the role and/or section(s) and/or credits to assign to users without values specified in the uploaded file.'); + } else { + $Str .= &Apache::lonhtmlcommon::row_title( &mt('Default role and section')) - .&mt('Choose the role and/or section(s) to assign to users without values specified in the uploaded file.'); + .&mt('Choose the role and/or section(s) to assign to users without values specified in the uploaded file.'); + } } else { $Str .= &Apache::lonhtmlcommon::row_title( &mt('Default role and/or section(s)')) @@ -847,7 +1124,8 @@ sub print_upload_manager_footer { } if (($context eq 'domain') || ($context eq 'author')) { $Str .= '
'; - my ($options,$cb_script,$coursepick) = &default_role_selector($context,1); + my ($options,$cb_script,$coursepick) = + &default_role_selector($context,1,'',$showcredits); if ($context eq 'domain') { $Str .= '

' .''.&mt('Domain Level').'
' @@ -864,8 +1142,13 @@ sub print_upload_manager_footer { } else { my ($cnum,$cdom) = &get_course_identity(); my $rowtitle = &mt('section'); - my $secbox = §ion_picker($cdom,$cnum,'Any',$rowtitle, - $permission,$context,'upload',$crstype); + my $defaultcredits; + if ($showcredits) { + $defaultcredits = &get_defaultcredits(); + } + my $secbox = §ion_picker($cdom,$cnum,'Any',$rowtitle,$permission, + $context,'upload',$crstype,$showcredits, + $defaultcredits); $Str .= $secbox .&Apache::lonhtmlcommon::row_closure(); my %lt; @@ -888,7 +1171,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(); @@ -911,35 +1196,78 @@ sub print_upload_manager_footer { return; } +sub get_defaultcredits { + my ($cdom,$cnum) = @_; + + if ($cdom eq '' || $cnum eq '') { + return unless ($env{'request.course.id'}); + $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + } + return unless(($cdom =~ /^$match_domain$/) && ($cnum =~ /^$match_courseid$/)); + my ($defaultcredits,$domdefcredits); + my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom); + 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'}; + } + } else { + return; + } + + if ($env{'request.course.id'} eq $cdom.'_'.$cnum) { + $defaultcredits = $env{'course.'.$cdom.'_'.$cnum.'.internal.defaultcredits'}; + } elsif (exists($env{'course.'.$cdom.'_'.$cnum.'.internal.defaultcredits'})) { + $defaultcredits = $env{'course.'.$cdom.'_'.$cnum.'.internal.defaultcredits'}; + } else { + my %crsinfo = + &Apache::lonnet::coursedescription("$cdom/$cnum",{'one_time' => 1}); + $defaultcredits = $crsinfo{'internal.defaultcredits'}; + } + if ($defaultcredits eq '') { + $defaultcredits = $domdefcredits; + } + return $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; } ############################################################### ############################################################### sub print_upload_manager_form { - my ($r,$context,$permission,$crstype) = @_; + my ($r,$context,$permission,$crstype,$showcredits) = @_; my $firstLine; my $datatoken; 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'}){ @@ -965,7 +1293,9 @@ sub print_upload_manager_form { 'domain_choice' => 'scalar', 'inststatus_choice' => 'scalar', }; - my $defdom = $env{'request.role.domain'}; + if ($showcredits) { + $col_setting_names->{'credits_choice'} = 'scalar'; + } if ($context eq 'course') { &Apache::loncommon::restore_course_settings('enrollment_upload', $col_setting_names); @@ -973,13 +1303,15 @@ sub print_upload_manager_form { &Apache::loncommon::restore_settings($context,'user_upload', $col_setting_names); } + my $defdom = $env{'request.role.domain'}; # # Determine kerberos parameters as appropriate my ($krbdef,$krbdefdom) = &Apache::loncommon::get_kerberos_defaults($defdom); # + my ($authnum,%can_assign) = &Apache::loncommon::get_assignable_auth($defdom); &print_upload_manager_header($r,$datatoken,$distotal,$krbdefdom,$context, - $permission,$crstype); + $permission,$crstype,\%can_assign); my $i; my $keyfields; if ($total>=0) { @@ -997,6 +1329,10 @@ sub print_upload_manager_form { ['role',&mt('Role'), $env{'form.role_choice'}], ['domain',&mt('Domain'), $env{'form.domain_choice'}], ['inststatus',&mt('Affiliation'), $env{'form.inststatus_choice'}]); + if ($showcredits) { + push(@field, + ['credits',&mt('Student Credits'), $env{'form.credits_choice'}]); + } if ($env{'form.upfile_associate'} eq 'reverse') { &Apache::loncommon::csv_print_samples($r,\@records); $i=&Apache::loncommon::csv_print_select_table($r,\@records, @@ -1013,9 +1349,9 @@ sub print_upload_manager_form { $keyfields=join(',',sort(keys(%sone))); } } - $r->print('
'); &print_upload_manager_footer($r,$i,$keyfields,$defdom,$today,$halfyear, - $context,$permission,$crstype); + $context,$permission,$crstype,$showcredits); + return 'ok'; } sub setup_date_selectors { @@ -1172,7 +1508,7 @@ sub make_dates_default { } sub default_role_selector { - my ($context,$checkpriv,$crstype) = @_; + my ($context,$checkpriv,$crstype,$showcredits) = @_; my %customroles; my ($options,$coursepick,$cb_jscript); if ($context ne 'author') { @@ -1184,6 +1520,7 @@ sub default_role_selector { 'grs' => "Section", 'exs' => "Existing sections", 'new' => "New section", + 'crd' => "Credits", ); $options = ''; + } $cb_jscript = - &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'},'currsec','studentform','courserole','Course/Community'); + &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'},'currsec','studentform','courserole','Course/Community',$credit_elem); $coursepick = &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(). ''.$courseform.''.$lt{'rol'}.''. ''.$lt{'grs'}.''. + ''.$lt{'crd'}.''. &Apache::loncommon::end_data_table_header_row(). &Apache::loncommon::start_data_table_row()."\n". ''."\n". @@ -1216,9 +1559,9 @@ sub default_role_selector { &default_course_roles($context,$checkpriv,'Course',%customroles)."\n". ''. ''. - ''. ''. '
'. + '
'. $lt{'exs'}.'
  '.$lt{'new'}.'
'. @@ -1230,7 +1573,7 @@ sub default_role_selector { ''. ''. ''. - '
'. + ''.$creditsinput. &Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table()."\n"; } @@ -1350,9 +1693,10 @@ sub curr_role_permissions { # ======================================================= Existing Custom Roles sub my_custom_roles { - my ($crstype) = @_; + my ($crstype,$udom,$uname) = @_; my %returnhash=(); - my %rolehash=&Apache::lonnet::dump('roles'); + my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1}); + my %rolehash=&Apache::lonnet::dump('roles',$udom,$uname); foreach my $key (keys(%rolehash)) { if ($key=~/^rolesdef\_(\w+)$/) { if ($crstype eq 'Community') { @@ -1366,7 +1710,7 @@ sub my_custom_roles { sub print_userlist { my ($r,$mode,$permission,$context,$formname,$totcodes,$codetitles, - $idlist,$idlist_titles) = @_; + $idlist,$idlist_titles,$showcredits) = @_; my $format = $env{'form.output'}; if (! exists($env{'form.sortby'})) { $env{'form.sortby'} = 'username'; @@ -1374,8 +1718,9 @@ sub print_userlist { if ($env{'form.Status'} !~ /^(Any|Expired|Active|Future)$/) { $env{'form.Status'} = 'Active'; } + my $onchange = "javascript:updateCols('Status');"; my $status_select = &Apache::lonhtmlcommon::StatusOptions - ($env{'form.Status'}); + ($env{'form.Status'},undef,undef,$onchange); if ($env{'form.showrole'} eq '') { if ($context eq 'course') { @@ -1400,20 +1745,16 @@ sub print_userlist { @statuses = ('future'); } -# if ($context eq 'course') { -# $r->print(&display_adv_courseroles()); -# } - # # Interface output $r->print('
'."\n". ''); - $r->print("

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

'."\n"); if ($env{'form.action'} ne 'modifystudent') { my %lt=&Apache::lonlocal::texthash('csv' => "CSV", 'excel' => "Excel", 'html' => 'HTML'); - my $output_selector = ''; foreach my $outputformat ('html','csv','excel') { my $option = '
'. + &column_checkboxes($context,$mode,$formname,$showcredits). + '
'); if ($env{'form.phase'} eq '') { - $r->print('

'.&list_submit_button(&mt('Display List of Users')). - "\n

\n". + $r->print('
'. + &list_submit_button(&mt('Display List of Users'))."\n". '
'); return; } if (!(($context eq 'domain') && - (($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')))) { - $r->print( - "\n

\n" - .'

' - .&list_submit_button(&mt('Update Display')) - ."

\n" - ); + (($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')))) { + $r->print('
'. + &list_submit_button(&mt('Update Display'))."\n"); + } + + my @cols = &infocolumns($context,$mode,$showcredits); + if (!@cols) { + $r->print('
'. + &mt('No user information selected for display.').''. + ''."\n"); + 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 'course') || ($env{'form.roletype'} eq 'community')) { my ($crstype,$numcodes,$title,$warning); if ($env{'form.roletype'} eq 'course') { @@ -1472,15 +1820,15 @@ sub print_userlist { $title = &mt('Select Communities'); $warning = &mt('Warning: data retrieval for multiple communities can take considerable time, as this operation is not currently optimized.'); } + my @standardnames = &Apache::loncommon::get_standard_codeitems(); my $courseform = &Apache::lonhtmlcommon::course_selection($formname,$numcodes, - $codetitles,$idlist,$idlist_titles,$crstype); - $r->print('

'.&Apache::lonhtmlcommon::start_pick_box()."\n". - &Apache::lonhtmlcommon::start_pick_box()."\n". - &Apache::lonhtmlcommon::row_title($title,'LC_oddrow_value')."\n". + $codetitles,$idlist,$idlist_titles,$crstype, + \@standardnames); + $r->print('

'. + '
'.$title.''."\n". $courseform."\n". - &Apache::lonhtmlcommon::row_closure(1). - &Apache::lonhtmlcommon::end_pick_box().'

'. + '

'. '

'. &list_submit_button(&mt('Update Display')). "\n".'

'.$warning.''."\n"); @@ -1490,10 +1838,10 @@ sub print_userlist { $clearcoursepick = 1; } if (($env{'form.coursepick'}) && (!$clearcoursepick)) { - $r->print('
'.&mt('Searching').' ...
 
'); + $r->print('
'.&mt('Searching ...').'
 
'); } } else { - $r->print('
'.&mt('Searching').' ...
 
'); + $r->print('
'.&mt('Searching ...').'
'); } $r->rflush(); if ($context eq 'course') { @@ -1528,6 +1876,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') { @@ -1562,7 +1916,8 @@ sub print_userlist { } } } - } elsif ($env{'form.roletype'} eq 'course') { + } elsif (($env{'form.roletype'} eq 'course') || + ($env{'form.roletype'} eq 'community')) { if (($env{'form.coursepick'}) && (!$clearcoursepick)) { my %courses = &process_coursepick(); my %allusers; @@ -1612,33 +1967,37 @@ sub print_userlist { } } if (keys(%userlist) == 0) { + my $msg = ''; if ($context eq 'author') { - $r->print(&mt('There are no co-authors to display.')."\n"); + $msg = &mt('There are no co-authors to display.'); } elsif ($context eq 'domain') { if ($env{'form.roletype'} eq 'domain') { - $r->print(&mt('There are no users with domain roles to display.')."\n"); + $msg = &mt('There are no users with domain roles to display.'); } elsif ($env{'form.roletype'} eq 'author') { - $r->print(&mt('There are no authors or co-authors to display.')."\n"); + $msg = &mt('There are no authors or co-authors to display.'); } elsif ($env{'form.roletype'} eq 'course') { - $r->print(&mt('There are no course users to display')."\n"); + $msg = &mt('There are no course users to display'); } elsif ($env{'form.roletype'} eq 'community') { - $r->print(&mt('There are no community users to display')."\n"); + $msg = &mt('There are no community users to display'); } } elsif ($context eq 'course') { $r->print(&mt('There are no course users to display.')."\n"); } + $r->print('

'.$msg.'

'."\n") if $msg; } else { # Print out the available choices my $usercount; if ($env{'form.action'} eq 'modifystudent') { ($usercount) = &show_users_list($r,$context,'view',$permission, - $env{'form.Status'},\%userlist,$keylist); + $env{'form.Status'},\%userlist,$keylist,'', + $showcredits); } else { ($usercount) = &show_users_list($r,$context,$env{'form.output'}, - $permission,$env{'form.Status'},\%userlist,$keylist); + $permission,$env{'form.Status'},\%userlist, + $keylist,'',$showcredits,$needauthorquota,$needauthorusage); } if (!$usercount) { - $r->print('
' + $r->print('
' .&mt('There are no users matching the search criteria.') .'' ); @@ -1646,6 +2005,7 @@ sub print_userlist { } $r->print(''); + return; } sub role_filter { @@ -1658,11 +2018,11 @@ sub role_filter { my ($role_select); if ($context eq 'domain') { $role_select = &domain_roles_select(); - $output = ''; + .'
'; } else { - $role_select = ''."\n". ''; my ($roletype,$crstype); @@ -1689,9 +2049,9 @@ sub role_filter { $role_select .= ''; } $role_select .= ''; - $output = ''; + .''; } return $output; } @@ -1754,11 +2114,200 @@ sub section_group_filter { return $output; } +sub infocolumns { + my ($context,$mode,$showcredits) = @_; + my @cols; + if (($mode eq 'pickauthor') || ($mode eq 'autoenroll')) { + @cols = &get_cols_array($context,$mode,$showcredits); + } else { + my @posscols = &get_cols_array($context,$mode,$showcredits); + if ($env{'form.phase'} ne '') { + my @checkedcols = &Apache::loncommon::get_env_multiple('form.showcol'); + foreach my $col (@checkedcols) { + if (grep(/^$col$/,@posscols)) { + push(@cols,$col); + } + } + } else { + @cols = @posscols; + } + } + return @cols; +} + +sub get_cols_array { + my ($context,$mode,$showcredits) = @_; + my @cols; + if ($mode eq 'pickauthor') { + @cols = ('username','fullname','status','email'); + } else { + @cols = ('username','domain','id','fullname'); + if ($context eq 'course') { + push(@cols,'section'); + } + push(@cols,('start','end','role')); + unless (($mode eq 'autoenroll') && ($env{'form.Status'} ne 'Any')) { + push(@cols,'status'); + } + if ($context eq 'course') { + push(@cols,'groups'); + } + push(@cols,'email'); + if (($context eq 'course') && ($mode ne 'autoenroll')) { + if ($showcredits) { + push(@cols,'credits'); + } + push(@cols,'lastlogin','clicker'); + } + if (($context eq 'course') && ($mode ne 'autoenroll') && + ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'})) { + push(@cols,'photo'); + } + if ($context eq 'domain') { + push (@cols,('authorusage','authorquota','extent')); + } + } + return @cols; +} + +sub column_checkboxes { + my ($context,$mode,$formname,$showcredits) = @_; + my @cols = &get_cols_array($context,$mode,$showcredits); + my @showncols = &Apache::loncommon::get_env_multiple('form.showcol'); + my (%disabledchk,%unchecked); + if ($env{'form.phase'} eq '') { + $disabledchk{'status'} = 1; + if ($context eq 'course') { + $disabledchk{'role'} = 1; + $unchecked{'photo'} = 1; + $unchecked{'clicker'} = 1; + if ($showcredits) { + $unchecked{'credits'} = 1; + } + } elsif ($context eq 'domain') { + $unchecked{'extent'} = 1; + } + $unchecked{'start'} = 1; + $unchecked{'end'} = 1; + } else { + if ($env{'form.Status'} ne 'Any') { + $disabledchk{'status'} = 1; + } + if (($env{'form.showrole'} ne 'Any') && ($env{'form.showrole'} ne 'cr')) { + $disabledchk{'role'} = 1; + } + if ($context eq 'domain') { + 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; + } + } + } + my $numposs = scalar(@cols); + my $numinrow = 7; + my %lt = &get_column_names($context); + my $output = '
'.&mt('Information to show').''."\n".''. + ''. + (' 'x3). + ''. + ''; + + for (my $i=0; $i<$numposs; $i++) { + my $rem = $i%($numinrow); + if ($rem == 0) { + if ($i > 0) { + $output .= ''; + } + $output .= ''; + } + my $checked; + if ($env{'form.phase'} eq '') { + $checked = ' checked="checked"'; + if ($unchecked{$cols[$i]}) { + $checked = ''; + } + if ($disabledchk{$cols[$i]}) { + $checked = ' disabled="disabled"'; + } + } elsif (grep(/^\Q$cols[$i]\E$/,@showncols)) { + $checked = ' checked="checked"'; + } elsif ($disabledchk{$cols[$i]}) { + $checked = ' disabled="disabled"'; + } + if ($i == $numposs-1) { + my $colsleft = $numinrow-$rem; + if ($colsleft > 1) { + $output .= ''; + } + $output .= '
'; + } else { + $output .= ''; + } + } else { + $output .= ''; + } + my $style; + if ($cols[$i] eq 'extent') { + 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 .= '
'; + return $output; +} + sub list_submit_button { my ($text) = @_; return ''; } +sub get_column_names { + my ($context) = @_; + my %lt = &Apache::lonlocal::texthash( + 'username' => "username", + 'domain' => "domain", + 'id' => 'ID', + 'fullname' => "name", + 'section' => "section", + 'groups' => "active groups", + 'start' => "start date", + 'end' => "end date", + 'status' => "status", + 'role' => "role", + 'credits' => "credits", + 'type' => "enroll type/action", + 'email' => "e-mail address", + 'photo' => "photo", + 'lastlogin' => "last login", + 'extent' => "extent", + 'authorusage' => "disk usage (%)", + 'authorquota' => "disk quota (MB)", + 'ca' => "check all", + 'ua' => "uncheck all", + 'clicker' => "clicker-ID", + ); + if ($context eq 'domain' && $env{'form.roletype'} eq 'course') { + $lt{'extent'} = &mt('course(s): description, section(s), status'); + } elsif ($context eq 'domain' && $env{'form.roletype'} eq 'community') { + $lt{'extent'} = &mt('community(s): description, section(s), status'); + } elsif (($context eq 'author') || + ($context eq 'domain' && $env{'form.roletype'} eq 'author')) { + $lt{'extent'} = &mt('author'); + } + return %lt; +} + sub gather_userinfo { my ($context,$format,$userlist,$indexhash,$userinfo,$rolehash,$permission) = @_; my $viewablesec; @@ -1876,7 +2425,6 @@ sub build_user_record { sub courses_selector { my ($cdom,$formname) = @_; - my %coursecodes = (); my %codes = (); my @codetitles = (); my %cat_titles = (); @@ -1889,14 +2437,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); @@ -1904,7 +2453,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); @@ -1922,7 +2471,7 @@ function setCourseCat(formname) { if (formname.Year.options[formname.Year.selectedIndex].value == -1) { return; } - courseSet('Year'); + courseSet('$codetitles[0]'); for (var j=0; j'.$role.''; - foreach my $user (split(',',$coursepersonnel{$role})) { - my ($puname,$pudom)=split(':',$user); - $output .= ' '.&Apache::loncommon::aboutmewrapper( - &Apache::loncommon::plainname($puname,$pudom), - $puname,$pudom); - } - $output .= ''.&Apache::loncommon::end_data_table_row(); - } - $output .= &Apache::loncommon::end_data_table(); -} - sub make_keylist_array { my ($index,$keylist); $index->{'domain'} = &Apache::loncoursedata::CL_SDOM(); @@ -2049,6 +2576,10 @@ sub make_keylist_array { $index->{'extent'} = &Apache::loncoursedata::CL_EXTENT(); $index->{'photo'} = &Apache::loncoursedata::CL_PHOTO(); $index->{'thumbnail'} = &Apache::loncoursedata::CL_THUMBNAIL(); + $index->{'credits'} = &Apache::loncoursedata::CL_CREDITS(); + $index->{'instsec'} = &Apache::loncoursedata::CL_INSTSEC(); + $index->{'authorquota'} = &Apache::loncoursedata::CL_AUTHORQUOTA(); + $index->{'authorusage'} = &Apache::loncoursedata::CL_AUTHORUSAGE(); foreach my $key (keys(%{$index})) { $keylist->[$index->{$key}] = $key; } @@ -2097,10 +2628,12 @@ sub process_date_info { } sub show_users_list { - my ($r,$context,$mode,$permission,$statusmode,$userlist,$keylist,$formname)=@_; + my ($r,$context,$mode,$permission,$statusmode,$userlist,$keylist,$formname, + $showcredits,$needauthorquota,$needauthorusage)=@_; if ($formname eq '') { $formname = 'studentform'; } + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; # # Variables for excel output my ($excel_workbook, $excel_sheet, $excel_filename,$row,$format); @@ -2112,34 +2645,36 @@ sub show_users_list { my @sortable = ('username','domain','id','fullname','start','end','email','role'); if ($context eq 'course') { push(@sortable,('section','groups','type')); + if ($showcredits) { + push(@sortable,'credits'); + } } else { push(@sortable,'extent'); + if (($context eq 'domain') && ($env{'form.roletype'} eq 'domain') && + (($env{'form.showrole'} eq 'Any') || ($env{'form.showrole'} eq 'au'))) { + push(@sortable,('authorusage','authorquota')); + } } if ($mode eq 'pickauthor') { @sortable = ('username','fullname','email','status'); } - if (!grep(/^\Q$sortby\E$/,@sortable)) { + my %is_sortable; + map { $is_sortable{$_} = 1; } @sortable; + unless ($is_sortable{$sortby}) { $sortby = 'username'; } my $setting = $env{'form.roletype'}; - my ($cid,$cdom,$cnum,$classgroups,$displayphotos,$displayclickers,$crstype); + my ($cid,$cdom,$cnum,$classgroups,$crstype,$defaultcredits); if ($context eq 'course') { $cid = $env{'request.course.id'}; $crstype = &Apache::loncommon::course_type(); ($cnum,$cdom) = &get_course_identity($cid); + $defaultcredits = $env{'course.'.$cid.'.internal.defaultcredits'}; ($classgroups) = &Apache::loncoursedata::get_group_memberships( $userlist,$keylist,$cdom,$cnum); if ($mode eq 'autoenroll') { $env{'form.showrole'} = 'st'; } else { - if (! exists($env{'form.displayphotos'})) { - $env{'form.displayphotos'} = 'off'; - } - $displayphotos = $env{'form.displayphotos'}; - if (! exists($env{'form.displayclickers'})) { - $env{'form.displayclickers'} = 'off'; - } - $displayclickers = $env{'form.displayclickers'}; if ($env{'course.'.$cid.'.internal.showphoto'}) { $r->print(' '); } - $r->print(< - -END } } elsif ($context eq 'domain') { if ($setting eq 'community') { @@ -2168,27 +2699,33 @@ END } } if ($mode ne 'autoenroll' && $mode ne 'pickauthor') { - my $check_uncheck_js = &Apache::loncommon::check_uncheck_jscript(); my $date_sec_selector = &date_section_javascript($context,$setting,$statusmode); my $verify_action_js = &bulkaction_javascript($formname); $r->print(< // print(< END - - my %lt=&Apache::lonlocal::texthash( - 'username' => "username", - 'domain' => "domain", - 'id' => 'ID', - 'fullname' => "name", - 'section' => "section", - 'groups' => "active groups", - 'start' => "start date", - 'end' => "end date", - 'status' => "status", - 'role' => "role", - 'type' => "enroll type/action", - 'email' => "e-mail address", - 'photo' => "photo", - 'extent' => "extent", + my @cols = &infocolumns($context,$mode,$showcredits); + my %coltxt = &get_column_names($context); + my %acttxt = &Apache::lonlocal::texthash( 'pr' => "Proceed", - 'ca' => "check all", - 'ua' => "uncheck all", 'ac' => "Action to take for selected users", 'link' => "Behavior of clickable username link for each user", 'aboutme' => "Display a user's personal information page", 'owin' => "Open in a new window", 'modify' => "Modify a user's information", 'track' => "View a user's recent activity", - 'clicker' => "Clicker-ID", + 'activity' => "View a user's access log", ); - if ($context eq 'domain' && $env{'form.roletype'} eq 'course') { - $lt{'extent'} = &mt('Course(s): description, section(s), status'); - } elsif ($context eq 'domain' && $env{'form.roletype'} eq 'community') { - $lt{'extent'} = &mt('Communities: description, section(s), status'); - } elsif ($context eq 'author') { - $lt{'extent'} = &mt('Author'); - } - my @cols; - if ($mode eq 'pickauthor') { - @cols = ('username','fullname','status','email'); - } else { - @cols = ('username','domain','id','fullname'); - if ($context eq 'course') { - push(@cols,'section'); - } - if (!($context eq 'domain' && ($env{'form.roletype'} eq 'course') - && ($env{'form.roletype'} eq 'community'))) { - push(@cols,('start','end')); - } - if ($env{'form.showrole'} eq 'Any' || $env{'form.showrole'} eq 'cr') { - push(@cols,'role'); - } - if ($context eq 'domain' && ($env{'form.roletype'} eq 'author' || - $env{'form.roletype'} eq 'course' || - $env{'form.roletype'} eq 'community')) { - push (@cols,'extent'); - } - if (($statusmode eq 'Any') && - (!($context eq 'domain' && (($env{'form.roletype'} eq 'course') - || ($env{'form.roletype'} eq 'community'))))) { - push(@cols,'status'); - } - if ($context eq 'course') { - push(@cols,'groups'); - } - push(@cols,'email'); - } - + my %lt = (%coltxt,%acttxt); my $rolefilter = $env{'form.showrole'}; if ($env{'form.showrole'} eq 'cr') { $rolefilter = &mt('custom'); } elsif ($env{'form.showrole'} ne 'Any') { - $rolefilter = &Apache::lonnet::plaintext($env{'form.showrole'}); + $rolefilter = &Apache::lonnet::plaintext($env{'form.showrole'},$crstype); } my $results_description; if ($mode ne 'autoenroll') { $results_description = &results_header_row($rolefilter,$statusmode, $context,$permission,$mode,$crstype); - - $r->print(''.$results_description.'

'); + $r->print(''.$results_description.'
'); } my ($output,$actionselect,%canchange,%canchangesec); if ($mode eq 'html' || $mode eq 'view' || $mode eq 'autoenroll' || $mode eq 'pickauthor') { @@ -2330,7 +2814,7 @@ END END if ($actionselect) { $output .= <<"END"; -
$lt{'ac'} +
$lt{'ac'} $actionselect

 
@@ -2371,20 +2855,32 @@ END if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'}.'/'.$env{'request.course.sec'})) { $canchangesec{$role} = $env{'request.course.sec'}; } + } elsif ((($role eq 'co') && ($crstype eq 'Community')) || + (($role eq 'cc') && ($crstype eq 'Course'))) { + if (&is_courseowner($env{'request.course.id'}, + $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'})) { + $canchange{$role} = 1; + } } } } } - $output .= '
'.$lt{'link'}.''. + $output .= '
'.$lt{'link'}.''. ''; my @linkdests = ('aboutme'); 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 .= '
'; my $usernamelink = $env{'form.usernamelink'}; @@ -2402,9 +2898,13 @@ END if ($env{'form.userwin'}) { $checkwin = ' checked="checked"'; } - $output .= ''.$lt{'owin'}.'
'; + $output .= + '' + .'
'; } - $output .= "\n".''."\n". + $output .= "\n".'
'."\n". &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(); if ($mode eq 'autoenroll') { @@ -2414,49 +2914,19 @@ END } else { $output .= "\n".' '."\n"; if ($actionselect) { - $output .= ''.&mt('Select').''."\n"; + $output .= ''.&mt('Select').''."\n"; } } foreach my $item (@cols) { - $output .= "$lt{$item}\n"; - } - my %role_types = &role_type_names(); - if ($context eq 'course' && $mode ne 'autoenroll') { - if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') { - # Clicker display on or off? - my %clicker_options = ( - 'on' => 'Show', - 'off' => 'Hide', - ); - my $clickerchg = 'on'; - if ($displayclickers eq 'on') { - $clickerchg = 'off'; - } - $output .= ' '."\n".' ' - .&mt('[_1]'.$clicker_options{$clickerchg}.'[_2] clicker id' - ,'' - ,'') - ."\n".' '."\n"; - - # Photo display on or off? - if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) { - my %photo_options = &Apache::lonlocal::texthash( - 'on' => 'Show', - 'off' => 'Hide', - ); - my $photochg = 'on'; - if ($displayphotos eq 'on') { - $photochg = 'off'; - } - $output .= ' '."\n".' '. - ''. - $photo_options{$photochg}.' '.$lt{'photo'}."\n". - ' '."\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(); # Done with the HTML header line } elsif ($mode eq 'csv') { @@ -2477,14 +2947,12 @@ END $CSVfile = undef; } # - push @cols,'clicker'; # Write headers and data to file print $CSVfile '"'.$results_description.'"'."\n"; print $CSVfile '"'.join('","',map { &Apache::loncommon::csv_translate($lt{$_}) } (@cols))."\"\n"; } elsif ($mode eq 'excel') { - push @cols,'clicker'; # Create the excel spreadsheet ($excel_workbook,$excel_filename,$format) = &Apache::loncommon::create_workbook($r); @@ -2520,6 +2988,11 @@ END Future => 'Future', Expired => 'Expired', ); + # If this is for a single course get last course "log-in". + my %crslogins; + if ($context eq 'course') { + %crslogins=&Apache::lonnet::dump('nohist_crslastlogin',$cdom,$cnum); + } # Get groups, role, permanent e-mail so we can sort on them if # necessary. foreach my $user (keys(%{$userlist})) { @@ -2603,7 +3076,7 @@ END } } if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) { - if (($displayphotos eq 'on') && ($role eq 'st')) { + if ((grep/^photo$/,@cols) && ($role eq 'st')) { $userlist->{$user}->[$index{'photo'}] = &Apache::lonnet::retrievestudentphoto($udom,$uname,'jpg'); $userlist->{$user}->[$index{'thumbnail'}] = @@ -2611,12 +3084,37 @@ END 'gif','thumbnail'); } } + if (($role eq 'st') && ($defaultcredits)) { + if ($userlist->{$user}->[$index{'credits'}] eq '') { + $userlist->{$user}->[$index{'credits'}] = $defaultcredits; + } + } } } my %emails = &Apache::loncommon::getemails($uname,$udom); 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; @@ -2637,13 +3135,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}; @@ -2653,18 +3165,26 @@ 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); - if (! defined($in{'start'}) || $in{'start'} == 0) { - $in{'start'} = &mt('none'); - } else { - $in{'start'} = &Apache::lonlocal::locallocaltime($in{'start'}); + $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}],$crstype); + unless ($mode eq 'excel') { + if (! defined($in{'start'}) || $in{'start'} == 0) { + $in{'start'} = &mt('none'); + } else { + $in{'start'} = &Apache::lonlocal::locallocaltime($in{'start'}); + } + if (! defined($in{'end'}) || $in{'end'} == 0) { + $in{'end'} = &mt('none'); + } else { + $in{'end'} = &Apache::lonlocal::locallocaltime($in{'end'}); + } } - if (! defined($in{'end'}) || $in{'end'} == 0) { - $in{'end'} = &mt('none'); - } else { - $in{'end'} = &Apache::lonlocal::locallocaltime($in{'end'}); + if ($context eq 'course') { + my $lastlogin = $crslogins{$in{'username'}.':'.$in{'domain'}.':'.$in{'section'}.':'.$role}; + if ($lastlogin ne '') { + $in{'lastlogin'} = &Apache::lonlocal::locallocaltime($lastlogin); + } } if ($mode eq 'view' || $mode eq 'html' || $mode eq 'autoenroll' || $mode eq 'pickauthor') { $r->print(&Apache::loncommon::start_data_table_row()); @@ -2672,16 +3192,16 @@ END if ($mode eq 'autoenroll') { my $cellentry; if ($in{'type'} eq 'auto') { - $cellentry = ''.&mt('auto').' '; + $cellentry = ''.&mt('auto').' '; $autocount ++; } else { - $cellentry = ''); + } else { + $r->print(''); } - $r->print(''); } else { $r->print(''); } @@ -2731,51 +3269,42 @@ 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}})) { $showitem = $ltstatus{$in{$item}}; } $r->print(''."\n"); - } else { - $r->print(''."\n"); - } - } - if (($context eq 'course') && ($mode ne 'autoenroll')) { - if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') { - if ($displayclickers eq 'on') { - my $clickers = + } elsif ($item eq 'photo') { + if (($context eq 'course') && ($mode ne 'autoenroll') && + ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'})) { + if ($role eq 'st') { + $r->print(''); + } else { + $r->print(''); + } + } + } elsif ($item eq 'clicker') { + if (($context eq 'course') && ($mode ne 'autoenroll')) { + if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') { + my $clickers = (&Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers'))[1]; - if ($clickers!~/\w/) { $clickers='-'; } - $r->print(''); - } else { - $r->print(' '); - } - if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) { - if ($displayphotos eq 'on' && $role eq 'st' && $in{'photo'} ne '') { - $r->print(' '); + if ($clickers!~/\w/) { $clickers='-'; } + $r->print(''); } else { - $r->print(' '); - } + $r->print(''."\n"); + } } + } elsif (($item eq 'authorquota') || ($item eq 'authorusage')) { + $r->print(''."\n"); + } else { + $r->print(''."\n"); } } $r->print(&Apache::loncommon::end_data_table_row()); } elsif ($mode eq 'csv') { next if (! defined($CSVfile)); # no need to bother with $linkto - if (! defined($in{'start'}) || $in{'start'} == 0) { - $in{'start'} = &mt('none'); - } else { - $in{'start'} = &Apache::lonlocal::locallocaltime($in{'start'}); - } - if (! defined($in{'end'}) || $in{'end'} == 0) { - $in{'end'} = &mt('none'); - } else { - $in{'end'} = &Apache::lonlocal::locallocaltime($in{'end'}); - } my @line = (); foreach my $item (@cols) { push @line,&Apache::loncommon::csv_translate($in{$item}); @@ -2785,9 +3314,9 @@ END my $col = 0; foreach my $item (@cols) { if ($item eq 'start' || $item eq 'end') { - if (defined($item) && $item != 0) { + if ((defined($in{$item})) && ($in{$item} != 0)) { $excel_sheet->write($row,$col++, - &Apache::lonstathelpers::calc_serial($in{item}), + &Apache::lonstathelpers::calc_serial($in{$item}), $format->{'date'}); } else { $excel_sheet->write($row,$col++,'none'); @@ -2803,10 +3332,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') { @@ -2838,6 +3367,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; @@ -2954,7 +3487,6 @@ sub role_type_names { 'author' => 'Co-Author Roles', 'course' => 'Course Roles', 'community' => 'Community Roles', - ); return %lt; } @@ -2969,6 +3501,7 @@ sub select_actions { chgdates => "Change starting/ending dates", chgsec => "Change section associated with user roles", ); + # FIXME Add an option to change credits for student roles. my ($output,$options,%choices); # FIXME Disable actions for now for roletype=course in domain context if ($context eq 'domain' && $setting eq 'course') { @@ -2976,15 +3509,20 @@ sub select_actions { } if ($context eq 'course') { if ($env{'form.showrole'} ne 'Any') { - if (!&Apache::lonnet::allowed('c'.$env{'form.showrole'}, - $env{'request.course.id'})) { - if ($env{'request.course.sec'} eq '') { - return; - } else { - if (!&Apache::lonnet::allowed('c'.$env{'form.showrole'},$env{'request.course.id'}.'/'.$env{'request.course.sec'})) { - return; - } - } + my $showactions; + if (&Apache::lonnet::allowed('c'.$env{'form.showrole'}, + $env{'request.course.id'})) { + $showactions = 1; + } elsif ($env{'request.course.sec'} ne '') { + if (&Apache::lonnet::allowed('c'.$env{'form.showrole'},$env{'request.course.id'}.'/'.$env{'request.course.sec'})) { + $showactions = 1; + } + } + unless ($showactions) { + unless (&is_courseowner($env{'request.course.id'}, + $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'})) { + return; + } } } } @@ -3091,11 +3629,13 @@ ENDTWO } sub date_section_selector { - my ($context,$permission,$crstype) = @_; + my ($context,$permission,$crstype,$showcredits) = @_; my $callingform = $env{'form.callingform'}; my $formname = 'dateselect'; my $groupslist = &get_groupslist(); - my $sec_js = &setsections_javascript($formname,$groupslist); + my $sec_js = + &setsections_javascript($formname,$groupslist,undef,undef,$crstype, + $showcredits); my $output = <<"END"; -

END my ($indexhash,$keylist) = &make_keylist_array(); @@ -3512,17 +4060,20 @@ END } } if (!$studentcount) { + my $msg = ''; if ($crstype eq 'Community') { - $r->print(&mt('There are no members to drop.')); + $msg = &mt('There are no members to drop.'); } else { - $r->print(&mt('There are no students to drop.')); + $msg = &mt('There are no students to drop.'); } + $r->print('

'.$msg.'

'); return; } my ($classgroups) = &Apache::loncoursedata::get_group_memberships( $classlist,$keylist,$cdom,$cnum); my %lt=&Apache::lonlocal::texthash('usrn' => "username", 'dom' => "domain", + 'id' => "ID", 'sn' => "student name", 'mn' => "member name", 'sec' => "section", @@ -3541,7 +4092,7 @@ END - + @@ -3555,21 +4106,21 @@ END $r->print(<  END $r->print(&Apache::loncommon::end_data_table_header_row()); @@ -3640,7 +4191,6 @@ END $btn = $lt{'dm'}; } $r->print(<<"END"); -

  @@ -3662,20 +4212,27 @@ sub print_first_users_upload_form { $str .= ''; $str .= ''; + $str .= &Apache::grades::checkforfile_js(); $str .= '

'.&mt('Upload a file containing information about users').'

'."\n"; # Excel and CSV Help - $str .= '
' + $str .= '
' .&Apache::loncommon::help_open_topic("Course_Create_Class_List", &mt("How do I create a users list from a spreadsheet")) - .'
'."\n" - .&Apache::loncommon::help_open_topic("Course_Convert_To_CSV", + .' '.&Apache::loncommon::help_open_topic("Course_Convert_To_CSV", &mt("How do I create a CSV file from a spreadsheet")) - .'

'."\n"; + ."
\n"; $str .= &Apache::lonhtmlcommon::start_pick_box() - .&Apache::lonhtmlcommon::row_title(&mt('File')) - .&Apache::loncommon::upfile_select_html() + .&Apache::lonhtmlcommon::row_title(&mt('File')); + if (&Apache::lonlocal::current_language() ne 'en') { + if ($context eq 'course') { + $str .= '

'."\n" + .&mt('Please upload an UTF8 encoded file to ensure a correct character encoding in your classlist.')."\n" + .'

'."\n"; + } + } + $str .= &Apache::loncommon::upfile_select_html() .&Apache::lonhtmlcommon::row_closure() .&Apache::lonhtmlcommon::row_title( ''. + &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 .= '
'; @@ -2710,17 +3230,35 @@ END if ($showcheckbox) { $checkval = $user; if ($context eq 'course') { - if ($role eq 'st') { - $checkval .= ':st'; - } - $checkval .= ':'.$in{'section'}; - if ($role eq 'st') { - $checkval .= ':'.$in{'type'}.':'. - $in{'lockedtype'}; + if (($role eq 'co' || $role eq 'cc') && + ($user =~ /^\Q$env{'user.name'}:$env{'user.domain'}:$role\E/)) { + $showcheckbox = 0; + } else { + if ($role eq 'st') { + $checkval .= ':st'; + } + $checkval .= ':'.$in{'section'}; + if ($role eq 'st') { + $checkval .= ':'.$in{'type'}.':'. + $in{'lockedtype'}.':'. + $in{'credits'}.':'. + &escape($in{'instsec'}); + } + } + } + if ($showcheckbox) { + $r->print('
'); + foreach my $item ('start','end') { + $r->print(''); } + $r->print('  '.&print_username_link($mode,\%in).''.$in{$item}.''.$showitem.''.$in{$item}.' '.$clickers.' '.$clickers.'  '.$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'} '.$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 .= '