--- loncom/interface/lonuserutils.pm 2010/01/20 16:46:23 1.114 +++ loncom/interface/lonuserutils.pm 2016/11/09 00:32:45 1.178 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Utility functions for managing LON-CAPA user accounts # -# $Id: lonuserutils.pm,v 1.114 2010/01/20 16:46:23 raeburn Exp $ +# $Id: lonuserutils.pm,v 1.178 2016/11/09 00:32:45 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); } $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,6 +528,7 @@ END return; } } +/* regexp here to check for non \d \. in credits */ END } else { $auth_checks .= (<{'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 +880,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 +970,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 +986,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 +1004,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 +1033,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,28 +1058,64 @@ 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'}) { @@ -965,7 +1148,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 +1158,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 +1184,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 +1204,8 @@ 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); } sub setup_date_selectors { @@ -1172,7 +1362,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 +1374,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 +1413,9 @@ sub default_role_selector { &default_course_roles($context,$checkpriv,'Course',%customroles)."\n". ''. ''. - ''. ''. '
'. + '
'. $lt{'exs'}.'
  '.$lt{'new'}.'
'. @@ -1230,7 +1427,7 @@ sub default_role_selector { ''. ''. ''. - '
'. + ''.$creditsinput. &Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table()."\n"; } @@ -1350,9 +1547,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 +1564,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 +1572,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 +1599,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" - ); + $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 'community')) { @@ -1472,15 +1674,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 +1692,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 +1730,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') { @@ -1613,33 +1821,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.') .'' ); @@ -1647,6 +1859,7 @@ sub print_userlist { } $r->print(''); + return; } sub role_filter { @@ -1659,11 +1872,11 @@ sub role_filter { my ($role_select); if ($context eq 'domain') { $role_select = &domain_roles_select(); - $output = ''; + .'
'; } else { - $role_select = ''."\n". ''; my ($roletype,$crstype); @@ -1690,9 +1903,9 @@ sub role_filter { $role_select .= ''; } $role_select .= ''; - $output = ' '; + .''; } return $output; } @@ -1755,11 +1968,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; @@ -1923,7 +2325,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(); @@ -2050,6 +2429,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; } @@ -2098,10 +2481,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); @@ -2113,34 +2498,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') { @@ -2169,22 +2552,24 @@ 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", ); - 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'); @@ -2309,7 +2641,7 @@ END 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') { @@ -2371,6 +2703,12 @@ 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; + } } } } @@ -2403,9 +2741,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') { @@ -2415,49 +2757,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') { @@ -2478,14 +2790,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); @@ -2521,6 +2831,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})) { @@ -2604,7 +2919,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'}] = @@ -2612,12 +2927,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; @@ -2638,13 +2978,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}; @@ -2654,18 +3008,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'}); + 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()); @@ -2673,16 +3035,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(''); } @@ -2733,50 +3106,43 @@ END if ($item eq 'username') { $r->print(''); } elsif (($item eq 'start' || $item eq 'end') && ($actionselect)) { - $r->print(''."\n"); + $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}); @@ -2786,9 +3152,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'); @@ -2804,10 +3170,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') { @@ -2839,6 +3205,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; @@ -2969,6 +3339,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 +3347,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 +3467,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(); @@ -3510,17 +3898,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", @@ -3539,7 +3930,7 @@ END - + @@ -3553,21 +3944,21 @@ END $r->print(<  END $r->print(&Apache::loncommon::end_data_table_header_row()); @@ -3638,7 +4029,6 @@ END $btn = $lt{'dm'}; } $r->print(<<"END"); -

  @@ -3660,16 +4050,17 @@ 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')); if (&Apache::lonlocal::current_language() ne 'en') { @@ -3690,7 +4081,8 @@ sub print_first_users_upload_form { .&Apache::lonhtmlcommon::end_pick_box(); $str .= '

' - .'' + .'' .'

'; $r->print($str); @@ -3699,7 +4091,7 @@ sub print_first_users_upload_form { # ================================================= Drop/Add from uploaded file sub upfile_drop_add { - my ($r,$context,$permission) = @_; + my ($r,$context,$permission,$showcredits) = @_; &Apache::loncommon::load_tmp_file($r); my @userdata=&Apache::loncommon::upfile_record_sep(); if($env{'form.noFirstLine'}){shift(@userdata);} @@ -3720,25 +4112,17 @@ sub upfile_drop_add { } # # Store the field choices away - foreach my $field (qw/username names - fname mname lname gen id sec ipwd email role domain/) { + my @storefields = qw/username names fname mname lname gen id + sec ipwd email role domain inststatus/; + if ($showcredits) { + push (@storefields,'credits'); + } + my %fieldstype; + foreach my $field (@storefields) { $env{'form.'.$field.'_choice'}=$fields{$field}; + $fieldstype{$field.'_choice'} = 'scalar'; } - &Apache::loncommon::store_course_settings('enrollment_upload', - { 'username_choice' => 'scalar', - 'names_choice' => 'scalar', - 'fname_choice' => 'scalar', - 'mname_choice' => 'scalar', - 'lname_choice' => 'scalar', - 'gen_choice' => 'scalar', - 'id_choice' => 'scalar', - 'sec_choice' => 'scalar', - 'ipwd_choice' => 'scalar', - 'email_choice' => 'scalar', - 'role_choice' => 'scalar', - 'domain_choice' => 'scalar', - 'inststatus_choice' => 'scalar'}); - # + &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype); my ($cid,$crstype,$setting); if ($context eq 'domain') { $setting = $env{'form.roleaction'}; @@ -3806,19 +4190,30 @@ sub upfile_drop_add { $amode = ''; # This causes the loop below to be skipped } } - my ($defaultsec,$defaultrole); + my ($defaultsec,$defaultrole,$defaultcredits,$commoncredits); if ($context eq 'domain') { if ($setting eq 'domain') { $defaultrole = $env{'form.defaultrole'}; } elsif ($setting eq 'course') { $defaultrole = $env{'form.courserole'}; $defaultsec = $env{'form.sections'}; - } + if ($showcredits) { + $commoncredits = $env{'form.credits'}; + if ($crstype ne 'Community') { + my %coursehash=&Apache::lonnet::coursedescription($cid); + $defaultcredits = $coursehash{'internal.defaultcredits'}; + } + } + } } elsif ($context eq 'author') { $defaultrole = $env{'form.defaultrole'}; } elsif ($context eq 'course') { $defaultrole = $env{'form.defaultrole'}; $defaultsec = $env{'form.sections'}; + if ($showcredits) { + $commoncredits = $env{'form.credits'}; + $defaultcredits = $env{'course.'.$cid.'.internal.defaultcredits'}; + } } # Check to see if user information can be changed my @userinfo = ('firstname','middlename','lastname','generation', @@ -3920,15 +4315,25 @@ sub upfile_drop_add { $r->print($groupwarn.'
'); } } - my (%curr_rules,%got_rules,%alerts); + my (%curr_rules,%got_rules,%alerts,%cancreate); my %customroles = &my_custom_roles($crstype); my @permitted_roles = - &roles_on_upload($context,$setting,$crstype,%customroles); + &roles_on_upload($context,$setting,$crstype,%customroles); + my %longtypes = &Apache::lonlocal::texthash( + official => 'Institutional', + unofficial => 'Non-institutional', + ); + my $newuserdom = $env{'request.role.domain'}; + map { $cancreate{$_} = &can_create_user($newuserdom,$context,$_); } keys(%longtypes); # Get new users list + my (%existinguser,%userinfo,%disallow,%rulematch,%inst_results,%alerts,%checkuname); + my $counter = -1; foreach my $line (@userdata) { + $counter ++; my @secs; my %entries=&Apache::loncommon::record_sep($line); # Determine user name + $entries{$fields{'username'}} =~ s/^\s+|\s+$//g; unless (($entries{$fields{'username'}} eq '') || (!defined($entries{$fields{'username'}}))) { my ($fname, $mname, $lname,$gen) = ('','','',''); @@ -3949,17 +4354,26 @@ sub upfile_drop_add { $gen=$entries{$fields{'gen'}}; } } + if ($entries{$fields{'username'}} ne &LONCAPA::clean_username($entries{$fields{'username'}})) { - $r->print('
'. - &mt('[_1]: Unacceptable username for user [_2] [_3] [_4] [_5]', - ''.$entries{$fields{'username'}}.'',$fname,$mname,$lname,$gen)); + my $nowhitespace; + if ($entries{$fields{'username'}} =~ /\s/) { + $nowhitespace = ' - '.&mt('usernames may not contain spaces.'); + } + $disallow{$counter} = + &mt('Unacceptable username [_1] for user [_2] [_3] [_4] [_5]', + '"'.$entries{$fields{'username'}}.'"', + $fname,$mname,$lname,$gen).$nowhitespace; next; } else { + $entries{$fields{'domain'}} =~ s/^\s+|\s+$//g; if ($entries{$fields{'domain'}} ne &LONCAPA::clean_domain($entries{$fields{'domain'}})) { - $r->print('
'. ''.$entries{$fields{'domain'}}. - ': '.&mt('Unacceptable domain for user [_2] [_3] [_4] [_5]',$fname,$mname,$lname,$gen)); + $disallow{$counter} = + &mt('Unacceptable domain [_1] for user [_2] [_3] [_4] [_5]', + '"'.$entries{$fields{'domain'}}.'"', + $fname,$mname,$lname,$gen); next; } my $username = $entries{$fields{'username'}}; @@ -3972,10 +4386,15 @@ sub upfile_drop_add { $entries{$fields{'sec'}} =~ s/\W//g; my $item = $entries{$fields{'sec'}}; if ($item eq "none" || $item eq 'all') { - $r->print('
'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a reserved word.',''.$username.'',$fname,$mname,$lname,$gen,$item)); + $disallow{$counter} = + &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a reserved word.', + ''.$username.'',$fname,$mname,$lname,$gen,$item); next; } elsif (exists($curr_groups{$item})) { - $r->print('
'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a course group.',''.$username.'',$fname,$mname,$lname,$gen,$item).' '.&mt('Section names and group names must be distinct.')); + $disallow{$counter} = + &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a course group.', + ''.$username.'',$fname,$mname,$lname,$gen,$item).' '. + &mt('Section names and group names must be distinct.'); next; } else { push(@secs,$item); @@ -3987,14 +4406,21 @@ sub upfile_drop_add { if (ref($userlist{$username.':'.$userdomain}) eq 'ARRAY') { my $currsec = $userlist{$username.':'.$userdomain}[$secidx]; if ($currsec ne $env{'request.course.sec'}) { - $r->print('
'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".',''.$username.'',$fname,$mname,$lname,$gen,$secs[0]).'
'); + $disallow{$counter} = + &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".', + ''.$username.'',$fname,$mname,$lname,$gen,$secs[0]); if ($currsec eq '') { - $r->print(&mt('This user already has an active/future student role in the course, unaffiliated to any section.')); + $disallow{$counter} .= + &mt('This user already has an active/future student role in the course, unaffiliated to any section.'); } else { - $r->print(&mt('This user already has an active/future role in section "[_1]" of the course.',$currsec)); + $disallow{$counter} .= + &mt('This user already has an active/future role in section "[_1]" of the course.',$currsec); } - $r->print('
'.&mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',$secs[0]).'
'); + $disallow{$counter} .= + '
'. + &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.', + $secs[0]); next; } } @@ -4014,6 +4440,7 @@ sub upfile_drop_add { # determine email address my $email=''; if (defined($fields{'email'})) { + $entries{$fields{'email'}} =~ s/^\s+|\s+$//g; if (defined($entries{$fields{'email'}})) { $email=$entries{$fields{'email'}}; unless ($email=~/^[^\@]+\@[^\@]+$/) { $email=''; } @@ -4045,13 +4472,12 @@ sub upfile_drop_add { } if ($role eq '') { my $rolestr = join(', ',@permitted_roles); - $r->print('
' - .&mt('[_1]: You do not have permission to add the requested role [_2] for the user.' - ,''.$entries{$fields{'username'}}.'' - ,$entries{$fields{'role'}}) - .'
' - .&mt('Allowable role(s) is/are: [_1].',$rolestr)."\n" - ); + $disallow{$counter} = + &mt('[_1]: You do not have permission to add the requested role [_2] for the user.' + ,''.$entries{$fields{'username'}}.'' + ,$entries{$fields{'role'}}) + .'
' + .&mt('Allowable role(s) is/are: [_1].',$rolestr); next; } } @@ -4060,29 +4486,57 @@ sub upfile_drop_add { $role = $defaultrole; } # Clean up whitespace - foreach (\$id,\$fname,\$mname,\$lname,\$gen) { + foreach (\$id,\$fname,\$mname,\$lname,\$gen,\$inststatus) { $$_ =~ s/(\s+$|^\s+)//g; } + my $credits; + if ($showcredits) { + if (($role eq 'st') && ($crstype ne 'Community')) { + $credits = $entries{$fields{'credits'}}; + if ($credits ne '') { + $credits =~ s/[^\d\.]//g; + } + if ($credits eq '') { + $credits = $commoncredits; + } + if ($credits eq $defaultcredits) { + undef($credits); + } + } + } # check against rules my $checkid = 0; my $newuser = 0; - my (%rulematch,%inst_results,%idinst_results); my $uhome=&Apache::lonnet::homeserver($username,$userdomain); if ($uhome eq 'no_host') { - next if ($userdomain ne $domain); - $checkid = 1; - $newuser = 1; - my $checkhash; - my $checks = { 'username' => 1 }; - $checkhash->{$username.':'.$domain} = { 'newuser' => 1, }; - &Apache::loncommon::user_rule_check($checkhash,$checks, - \%alerts,\%rulematch,\%inst_results,\%curr_rules, - \%got_rules); - if (ref($alerts{'username'}) eq 'HASH') { - if (ref($alerts{'username'}{$domain}) eq 'HASH') { - next if ($alerts{'username'}{$domain}{$username}); + if ($userdomain ne $newuserdom) { + if ($context eq 'course') { + $disallow{$counter} = + &mt('[_1]: The domain specified ([_2]) is different to that of the course.', + ''.$username.'',$userdomain); + } elsif ($context eq 'author') { + $disallow{$counter} = + &mt('[_1]: The domain specified ([_2]) is different to that of the author.', + ''.$username.'',$userdomain); + } else { + $disallow{$counter} = + &mt('[_1]: The domain specified ([_2]) is different to that of your current role.', + ''.$username.'',$userdomain); + } + $disallow{$counter} .= + &mt('The user does not already exist, and you may not create a new user in a different domain.'); + next; + } else { + unless ($password || $env{'form.login'} eq 'loc') { + $disallow{$counter} = + &mt('[_1]: This is a new user but no default password was provided, and the authentication type requires one.', + ''.$username.''); + next; } } + $checkid = 1; + $newuser = 1; + $checkuname{$username.':'.$newuserdom} = { 'newuser' => $newuser, 'id' => $id }; } else { if ($context eq 'course' || $context eq 'author') { if ($userdomain eq $domain ) { @@ -4115,72 +4569,205 @@ sub upfile_drop_add { } } } + if ($id) { + $existinguser{$userdomain}{$username} = $id; + } } - if ($id ne '') { - if (!$newuser) { - my %idhash = &Apache::lonnet::idrget($userdomain,($username)); - if ($idhash{$username} ne $id) { - $checkid = 1; + $userinfo{$counter} = { + username => $username, + domain => $userdomain, + fname => $fname, + mname => $mname, + lname => $lname, + gen => $gen, + email => $email, + id => $id, + password => $password, + inststatus => $inststatus, + role => $role, + sections => \@secs, + credits => $credits, + newuser => $newuser, + checkid => $checkid, + }; + } + } + } # end of foreach (@userdata) + if ($counter > -1) { + my $total = $counter + 1; + my %checkids; + if ((keys(%existinguser)) || (keys(%checkuname))) { + $r->print(&mt('Please be patient -- checking for institutional data ...')); + $r->rflush(); + if (keys(%existinguser)) { + foreach my $dom (keys(%existinguser)) { + if (ref($existinguser{$dom}) eq 'HASH') { + my %idhash = &Apache::lonnet::idrget($dom,keys(%{$existinguser{$dom}})); + foreach my $username (keys(%{$existinguser{$dom}})) { + if ($idhash{$username} ne $existinguser{$dom}{$username}) { + $checkids{$username.':'.$dom} = { + 'id' => $existinguser{$dom}{$username}, + }; + } + } + if (keys(%checkids)) { + &Apache::loncommon::user_rule_check(\%checkids,{ 'id' => 1 }, + \%alerts,\%rulematch, + \%inst_results,\%curr_rules, + \%got_rules); + } + } + } + } + if (keys(%checkuname)) { + &Apache::loncommon::user_rule_check(\%checkuname,{ 'username' => 1, 'id' => 1, }, + \%alerts,\%rulematch,\%inst_results, + \%curr_rules,\%got_rules); + } + $r->print(' '.&mt('done').'

'); + $r->rflush(); + } + my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,$total); + $r->print('
    '); + for (my $i=0; $i<=$counter; $i++) { + if ($disallow{$i}) { + $r->print('
  • '.$disallow{$i}.'
  • '); + } elsif (ref($userinfo{$i}) eq 'HASH') { + my $password = $userinfo{$i}{'password'}; + my $newuser = $userinfo{$i}{'newuser'}; + my $checkid = $userinfo{$i}{'checkid'}; + my $id = $userinfo{$i}{'id'}; + my $role = $userinfo{$i}{'role'}; + my @secs; + if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') { + @secs = @{$userinfo{$i}{'sections'}}; + } + my $fname = $userinfo{$i}{'fname'}; + my $mname = $userinfo{$i}{'mname'}; + my $lname = $userinfo{$i}{'lname'}; + my $gen = $userinfo{$i}{'gen'}; + my $email = $userinfo{$i}{'email'}; + my $inststatus = $userinfo{$i}{'inststatus'}; + my $credits = $userinfo{$i}{'credits'}; + my $username = $userinfo{$i}{'username'}; + my $userdomain = $userinfo{$i}{'domain'}; + my $user = $username.':'.$userdomain; + if ($newuser) { + if (ref($alerts{'username'}) eq 'HASH') { + if (ref($alerts{'username'}{$userdomain}) eq 'HASH') { + if ($alerts{'username'}{$userdomain}{$username}) { + $r->print('
  • '. + &mt('[_1]: matches the username format at your institution, but is not known to your directory service.',''.$username.'').'
    '. + &mt('Consequently, the user was not created.').'
  • '); + next; + } + } + } + if (ref($inst_results{$user}) eq 'HASH') { + if ($inst_results{$user}{'firstname'} ne '') { + $fname = $inst_results{$user}{'firstname'}; + } + if ($inst_results{$user}{'middlename'} ne '') { + $mname = $inst_results{$user}{'middlename'}; + } + if ($inst_results{$user}{'lasttname'} ne '') { + $lname = $inst_results{$user}{'lastname'}; + } + if ($inst_results{$user}{'permanentemail'} ne '') { + $email = $inst_results{$user}{'permanentemail'}; + } + if ($inst_results{$user}{'id'} ne '') { + $id = $inst_results{$user}{'id'}; + $checkid = 0; + } + if (ref($inst_results{$user}{'inststatus'}) eq 'ARRAY') { + $inststatus = join(':',@{$inst_results{$user}{'inststatus'}}); + } + } + if (($checkid) && ($id ne '')) { + if (ref($alerts{'id'}) eq 'HASH') { + if (ref($alerts{'id'}{$userdomain}) eq 'HASH') { + if ($alerts{'id'}{$userdomain}{$username}) { + $r->print('
  • '. + &mt('[_1]: has a student/employee ID matching the format at your institution, but the ID is not found by your directory service.', + ''.$username.'').'
    '. + &mt('Consequently, the user was not created.').'
  • '); + next; + } + } } } - if ($checkid) { - my $checkhash; - my $checks = { 'id' => 1 }; - $checkhash->{$username.':'.$userdomain} = { 'newuser' => $newuser, - 'id' => $id }; - &Apache::loncommon::user_rule_check($checkhash,$checks, - \%alerts,\%rulematch,\%idinst_results,\%curr_rules, - \%got_rules); + my $usertype = 'unofficial'; + if (ref($rulematch{$user}) eq 'HASH') { + if ($rulematch{$user}{'username'}) { + $usertype = 'official'; + } + } + unless ($cancreate{$usertype}) { + my $showtype = $longtypes{$usertype}; + $r->print('
  • '. + &mt('[_1]: The user does not exist, and you are not permitted to create users of type: [_2].',''.$username.'',$showtype).'
  • '); + next; + } + } elsif ($id ne '') { + if (exists($checkids{$user})) { + $checkid = 1; if (ref($alerts{'id'}) eq 'HASH') { if (ref($alerts{'id'}{$userdomain}) eq 'HASH') { - next if ($alerts{'id'}{$userdomain}{$id}); + if ($alerts{'id'}{$userdomain}{$username}) { + $r->print('
  • '. + &mt('[_1]: has a student/employee ID matching the format at your institution, but the ID is not found by your directory service.', + ''.$username.'').'
    '. + &mt('Consequently, the ID was not changed.').'
  • '); + $id = ''; + } } } } } - if ($password || $env{'form.login'} eq 'loc') { - my $multiple = 0; - my ($userresult,$authresult,$roleresult,$idresult); - my (%userres,%authres,%roleres,%idres); - my $singlesec = ''; - if ($role eq 'st') { - my $sec; + my $multiple = 0; + my ($userresult,$authresult,$roleresult,$idresult); + my (%userres,%authres,%roleres,%idres); + my $singlesec = ''; + if ($role eq 'st') { + my $sec; + if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') { if (@secs > 0) { $sec = $secs[0]; } - &modifystudent($userdomain,$username,$cid,$sec, - $desiredhost,$context); - $roleresult = - &Apache::lonnet::modifystudent - ($userdomain,$username,$id,$amode,$password, - $fname,$mname,$lname,$gen,$sec,$enddate, - $startdate,$env{'form.forceid'}, - $desiredhost,$email,'manual','',$cid, - '',$context,$inststatus); - $userresult = $roleresult; - } else { - if ($role ne '') { - if ($context eq 'course' || $setting eq 'course') { - if ($customroles{$role}) { - $role = 'cr_'.$env{'user.domain'}.'_'. - $env{'user.name'}.'_'.$role; - } - if (($role ne 'cc') && ($role ne 'co')) { - if (@secs > 1) { - $multiple = 1; - foreach my $sec (@secs) { - ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) = - &modifyuserrole($context,$setting, - $changeauth,$cid,$userdomain,$username, - $id,$amode,$password,$fname, - $mname,$lname,$gen,$sec, - $env{'form.forceid'},$desiredhost, - $email,$role,$enddate, - $startdate,$checkid,$inststatus); - } - } elsif (@secs > 0) { - $singlesec = $secs[0]; + } + &modifystudent($userdomain,$username,$cid,$sec, + $desiredhost,$context); + $roleresult = + &Apache::lonnet::modifystudent + ($userdomain,$username,$id,$amode,$password, + $fname,$mname,$lname,$gen,$sec,$enddate, + $startdate,$env{'form.forceid'}, + $desiredhost,$email,'manual','',$cid, + '',$context,$inststatus,$credits); + $userresult = $roleresult; + } else { + if ($role ne '') { + if ($context eq 'course' || $setting eq 'course') { + if ($customroles{$role}) { + $role = 'cr_'.$env{'user.domain'}.'_'. + $env{'user.name'}.'_'.$role; + } + if (($role ne 'cc') && ($role ne 'co')) { + if (@secs > 1) { + $multiple = 1; + foreach my $sec (@secs) { + ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) = + &modifyuserrole($context,$setting, + $changeauth,$cid,$userdomain,$username, + $id,$amode,$password,$fname, + $mname,$lname,$gen,$sec, + $env{'form.forceid'},$desiredhost, + $email,$role,$enddate, + $startdate,$checkid,$inststatus); } + } elsif (@secs > 0) { + $singlesec = $secs[0]; } } } @@ -4195,40 +4782,29 @@ sub upfile_drop_add { $checkid,$inststatus); } } - if ($multiple) { - foreach my $sec (sort(keys(%userres))) { - $flushc = + } + if ($multiple) { + foreach my $sec (sort(keys(%userres))) { + $flushc = &user_change_result($r,$userres{$sec},$authres{$sec}, $roleres{$sec},$idres{$sec},\%counts,$flushc, $username,$userdomain,\%userchg); - } - } else { - $flushc = - &user_change_result($r,$userresult,$authresult, - $roleresult,$idresult,\%counts,$flushc, - $username,$userdomain,\%userchg); } } else { - if ($context eq 'course') { - $r->print('
    '. - &mt('[_1]: Unable to enroll. No password specified.',''.$username.'') - ); - } elsif ($context eq 'author') { - $r->print('
    '. - &mt('[_1]: Unable to add co-author. No password specified.',''.$username.'') - ); - } else { - $r->print('
    '. - &mt('[_1]: Unable to add user. No password specified.',''.$username.'') - ); - } + $flushc = + &user_change_result($r,$userresult,$authresult, + $roleresult,$idresult,\%counts,$flushc, + $username,$userdomain,\%userchg); } } - } - } # end of foreach (@userdata) + &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,'last user'); + } # end of loop + $r->print('
'); + &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state); + } # Flush the course logs so reverse user roles immediately updated - &Apache::lonnet::flushcourselogs(); + $r->register_cleanup(\&Apache::lonnet::flushcourselogs); $r->print("

\n

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

\n"); if ($counts{'role'} > 0) { @@ -4251,9 +4827,9 @@ sub upfile_drop_add { # Get current classlist my $classlist = &Apache::loncoursedata::get_classlist(); if (! defined($classlist)) { - $r->print(''. + $r->print(''. ''. - &mt('There are no students with current/future access to the course.'). + '

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

'. ''."\n"); } elsif (ref($classlist) eq 'HASH') { # Remove the students we just added from the list of students. @@ -4319,11 +4895,12 @@ sub user_change_result { my ($r,$userresult,$authresult,$roleresult,$idresult,$counts,$flushc, $username,$userdomain,$userchg) = @_; my $okresult = 0; + my @status; if ($userresult ne 'ok') { if ($userresult =~ /^error:(.+)$/) { my $error = $1; - $r->print('
'. - &mt('[_1]: Unable to add/modify: [_2]',''.$username.':'.$userdomain.'',$error)); + push(@status, + &mt('[_1]: Unable to add/modify: [_2]',''.$username.':'.$userdomain.'',$error)); } } else { $counts->{'user'} ++; @@ -4332,8 +4909,8 @@ sub user_change_result { if ($authresult ne 'ok') { if ($authresult =~ /^error:(.+)$/) { my $error = $1; - $r->print('
'. - &mt('[_1]: Unable to modify authentication: [_2]',''.$username.':'.$userdomain.'',$error)); + push(@status, + &mt('[_1]: Unable to modify authentication: [_2]',''.$username.':'.$userdomain.'',$error)); } } else { $counts->{'auth'} ++; @@ -4342,8 +4919,8 @@ sub user_change_result { if ($roleresult ne 'ok') { if ($roleresult =~ /^error:(.+)$/) { my $error = $1; - $r->print('
'. - &mt('[_1]: Unable to add role: [_2]',''.$username.':'.$userdomain.'',$error)); + push(@status, + &mt('[_1]: Unable to add role: [_2]',''.$username.':'.$userdomain.'',$error)); } } else { $counts->{'role'} ++; @@ -4352,14 +4929,16 @@ sub user_change_result { if ($okresult) { $flushc++; $userchg->{$username.':'.$userdomain}=1; - $r->print('. '); if ($flushc>15) { $r->rflush; $flushc=0; } } if ($idresult) { - $r->print($idresult); + push(@status,$idresult); + } + if (@status) { + $r->print('
  • '.join('
    ',@status).'
  • '); } return $flushc; } @@ -4374,28 +4953,29 @@ sub print_drop_menu { $heading = &mt("Drop Students"); } $r->print('

    '.$heading.'

    '."\n". - ''."\n"); + ''."\n"); my $classlist = &Apache::loncoursedata::get_classlist(); if (! defined($classlist)) { + my $msg = ''; if ($crstype eq 'Community') { - $r->print(&mt('There are no members currently enrolled.')."\n"); + $msg = &mt('There are no members currently enrolled.'); } else { - $r->print(&mt('There are no students currently enrolled.')."\n"); + $msg = &mt('There are no students currently enrolled.'); } + $r->print('

    '.$msg."

    \n"); } else { &show_drop_list($r,$classlist,'nosort',$permission,$crstype); } - $r->print(''. &Apache::loncommon::end_page()); + $r->print(''); return; } # ================================================================== Phase four sub update_user_list { - my ($r,$context,$setting,$choice) = @_; + my ($r,$context,$setting,$choice,$crstype) = @_; my $now = time; my $count=0; - my $crstype; if ($context eq 'course') { $crstype = &Apache::loncommon::course_type(); } @@ -4410,7 +4990,7 @@ sub update_user_list { 'reenable' => 'Re-enabled', 'activate' => 'Activated', 'chgdates' => 'Changed Access Dates for', - 'chgsec' => 'Changed section for', + 'chgsec' => 'Changed section(s) for', 'drop' => 'Dropped', }, error => {'revoke' => 'revoking', @@ -4427,8 +5007,9 @@ sub update_user_list { ($startdate,$enddate) = &get_dates_from_form(); } foreach my $item (@changelist) { - my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype,@sections, - $scopestem); + my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype, + @sections,$scopestem,$singlesec,$showsecs,$warn_singlesec, + $nothingtodo,$keepnosection,$credits,$instsec); if ($choice eq 'drop') { ($uname,$udom,$sec) = split(/:/,$item,-1); $role = 'st'; @@ -4441,7 +5022,9 @@ sub update_user_list { $scope = $scopestem.'/'.$sec; } } elsif ($context eq 'course') { - ($uname,$udom,$role,$sec,$type,$locktype) = split(/\:/,$item,-1); + ($uname,$udom,$role,$sec,$type,$locktype,$credits,$instsec) = + split(/\:/,$item,8); + $instsec = &unescape($instsec); $cid = $env{'request.course.id'}; $scopestem = '/'.$cid; $scopestem =~s/\_/\//g; @@ -4460,8 +5043,9 @@ sub update_user_list { } elsif ($setting eq 'author') { ($uname,$udom,$role,$scope) = split(/\:/,$item); } elsif ($setting eq 'course') { - ($uname,$udom,$role,$cid,$sec,$type,$locktype) = - split(/\:/,$item); + ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits,$instsec) = + split(/\:/,$item,9); + $instsec = &unescape($instsec); $scope = '/'.$cid; $scope =~s/\_/\//g; if ($sec ne '') { @@ -4483,7 +5067,7 @@ sub update_user_list { $end = $now; if ($role eq 'st') { $result = - &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context); + &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { $result = &Apache::lonnet::revokerole($udom,$uname,$scope,$role, @@ -4491,7 +5075,7 @@ sub update_user_list { } } elsif ($choice eq 'delete') { if ($role eq 'st') { - &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid,'',$context); + &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$now, @@ -4504,7 +5088,7 @@ sub update_user_list { } if ($choice eq 'reenable') { if ($role eq 'st') { - $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context); + $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end, @@ -4512,14 +5096,14 @@ sub update_user_list { } } elsif ($choice eq 'activate') { if ($role eq 'st') { - $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context); + $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end, $now,'','',$context); } } elsif ($choice eq 'chgdates') { if ($role eq 'st') { - $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context); + $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end, $start,'','',$context); @@ -4527,14 +5111,23 @@ sub update_user_list { } elsif ($choice eq 'chgsec') { my (@newsecs,$revresult,$nochg,@retained); if (($role ne 'cc') && ($role ne 'co')) { - @newsecs = split(/,/,$env{'form.newsecs'}); + my @secs = sort(split(/,/,$env{'form.newsecs'})); + if (@secs) { + my %curr_groups = &Apache::longroup::coursegroups(); + foreach my $sec (@secs) { + next if (($sec =~ /\W/) || ($sec eq 'none') || + (exists($curr_groups{$sec}))); + push(@newsecs,$sec); + } + } } # remove existing section if not to be retained. - if (!$env{'form.retainsec'}) { + if (!$env{'form.retainsec'} || ($role eq 'st')) { if ($sec eq '') { if (@newsecs == 0) { - $result = &mt('No change in section assignment (none)'); + $result = 'ok'; $nochg = 1; + $nothingtodo = 1; } else { $revresult = &Apache::lonnet::revokerole($udom,$uname, @@ -4561,37 +5154,83 @@ sub update_user_list { } else { if ($sec eq '') { $nochg = 1; - } else { + $keepnosection = 1; + } else { push(@retained,$sec); } } # add new sections + my (@diffs,@shownew); + if (@retained) { + @diffs = &Apache::loncommon::compare_arrays(\@retained,\@newsecs); + } else { + @diffs = @newsecs; + } if (@newsecs == 0) { - if (!$nochg) { + if ($nochg) { + $result = 'ok'; + $nothingtodo = 1; + } else { if ($role eq 'st') { $result = - &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid,'',$context); + &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { my $newscope = $scopestem; $result = &Apache::lonnet::assignrole($udom,$uname,$newscope,$role,$end,$start,'','',$context); } } + $showsecs = &mt('No section'); + } elsif (@diffs == 0) { + $result = 'ok'; + $nothingtodo = 1; } else { - foreach my $newsec (@newsecs) { + foreach my $newsec (@newsecs) { if (!grep(/^\Q$newsec\E$/,@retained)) { if ($role eq 'st') { - $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid,'',$context); + $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); + if (@newsecs > 1) { + my $showsingle; + if ($newsec eq '') { + $showsingle = &mt('No section'); + } else { + $showsingle = $newsec; + } + if ($crstype eq 'Community') { + $warn_singlesec = &mt('Although more than one section was indicated, a role was only added for the first section - [_1], as each community member may only be in one section at a time.',''.$showsingle.''); + } else { + $warn_singlesec = &mt('Although more than one section was indicated, a role was only added for the first section - [_1], as each student may only be in one section of a course at a time.',''.$showsingle.''); + } + $showsecs = $showsingle; + last; + } else { + if ($newsec eq '') { + $showsecs = &mt('No section'); + } else { + $showsecs = $newsec; + } + } } else { my $newscope = $scopestem; if ($newsec ne '') { $newscope .= '/'.$newsec; + push(@shownew,$newsec); } $result = &Apache::lonnet::assignrole($udom,$uname, $newscope,$role,$end,$start); + } } } } + unless ($role eq 'st') { + unless ($showsecs) { + my @tolist = sort(@shownew,@retained); + if ($keepnosection) { + push(@tolist,&mt('No section')); + } + $showsecs = join(', ',@tolist); + } + } } } my $extent = $scope; @@ -4602,13 +5241,48 @@ sub update_user_list { } } if ($result eq 'ok' || $result eq 'ok:') { - $r->print(&mt("$result_text{'ok'}{$choice} role of '[_1]' in [_2] for [_3]", - $plrole,$extent,$uname.':'.$udom).'
    '); - $count++; + my $dates; + if (($choice eq 'chgsec') || ($choice eq 'chgdates')) { + $dates = &dates_feedback($start,$end,$now); + } + if ($choice eq 'chgsec') { + if ($nothingtodo) { + $r->print(&mt("Section assignment for role of '[_1]' in [_2] for '[_3]' unchanged.",$plrole,$extent,''. + &Apache::loncommon::plainname($uname,$udom). + '').' '); + if ($sec eq '') { + $r->print(&mt('[_1]No section[_2] - [_3]','','',$dates)); + } else { + $r->print(&mt('Section(s): [_1] - [_2]', + ''.$showsecs.'',$dates)); + } + $r->print('
    '); + } else { + $r->print(&mt("$result_text{'ok'}{$choice} role of '[_1]' in [_2] for '[_3]' to [_4] - [_5]",$plrole,$extent, + ''.&Apache::loncommon::plainname($uname,$udom).'', + ''.$showsecs.'',$dates).'
    '); + $count ++; + } + if ($warn_singlesec) { + $r->print('
    '.$warn_singlesec.'
    '); + } + } elsif ($choice eq 'chgdates') { + $r->print(&mt("$result_text{'ok'}{$choice} role of '[_1]' in [_2] for '[_3]' - [_4]",$plrole,$extent, + ''.&Apache::loncommon::plainname($uname,$udom).'', + $dates).'
    '); + $count ++; + } else { + $r->print(&mt("$result_text{'ok'}{$choice} role of '[_1]' in [_2] for '[_3]'.",$plrole,$extent, + ''.&Apache::loncommon::plainname($uname,$udom).''). + '
    '); + $count ++; + } } else { $r->print( - &mt("Error $result_text{'error'}{$choice} [_1] in [_2] for [_3]: [_4].", - $plrole,$extent,$uname.':'.$udom,$result).'
    '); + &mt("Error $result_text{'error'}{$choice} [_1] in [_2] for '[_3]': [_4].", + $plrole,$extent, + ''.&Apache::loncommon::plainname($uname,$udom).'', + $result).'
    '); } } $r->print(''."\n"); @@ -4624,13 +5298,13 @@ sub update_user_list { } } } - $r->print('

    '.&mt("$result_text{'ok'}{$choice} role(s) for [quant,_1,user,users,no users].",$count).'

    '); + $r->print('

    '.&mt("$result_text{'ok'}{$choice} [quant,_1,user role,user roles,no user roles].",$count).'

    '); if ($count > 0) { if ($choice eq 'revoke' || $choice eq 'drop') { $r->print('

    '.&mt('Re-enabling will re-activate data for the role.').'

    '); } # Flush the course logs so reverse user roles immediately updated - &Apache::lonnet::flushcourselogs(); + $r->register_cleanup(\&Apache::lonnet::flushcourselogs); } if ($env{'form.makedatesdefault'}) { if ($choice eq 'chgdates' || $choice eq 'reenable' || $choice eq 'activate') { @@ -4641,7 +5315,31 @@ sub update_user_list { if ($choice eq 'drop') { $linktext = &mt('Display current class roster'); } - $r->print(''.$linktext.''."\n"); + $r->print( + &Apache::lonhtmlcommon::actionbox( + [''.$linktext.'']) + .''."\n"); +} + +sub dates_feedback { + my ($start,$end,$now) = @_; + my $dates; + if ($start < $now) { + if ($end == 0) { + $dates = &mt('role(s) active now; no end date'); + } elsif ($end > $now) { + $dates = &mt('role(s) active now; ends [_1].',&Apache::lonlocal::locallocaltime($end)); + } else { + $dates = &mt('role(s) expired: [_1].',&Apache::lonlocal::locallocaltime($end)); + } + } else { + if ($end == 0 || $end > $now) { + $dates = &mt('future role(s); starts: [_1].',&Apache::lonlocal::locallocaltime($start)); + } else { + $dates = &mt('role(s) expired: [_1].',&Apache::lonlocal::locallocaltime($end)); + } + } + return $dates; } sub classlist_drop { @@ -4667,18 +5365,25 @@ sub active_student_roles { sub section_check_js { my $groupslist= &get_groupslist(); + my %js_lt = &Apache::lonlocal::texthash( + mayn => 'may not be used as the name for a section, as it is a reserved word.', + plch => 'Please choose a different section name.', + mnot => 'may not be used as a section name, as it is the name of a course group.', + secn => 'Section names and group names must be distinct. Please choose a different section name.', + ); + &js_escape(\%js_lt); return <<"END"; function validate(caller) { var groups = new Array($groupslist); var secname = caller.value; if ((secname == 'all') || (secname == 'none')) { - alert("'"+secname+"' may not be used as the name for a section, as it is a reserved word.\\nPlease choose a different section name."); + alert("'"+secname+"' $js_lt{'mayn'}\\n$js_lt{'plch'}"); return 'error'; } if (secname != '') { for (var k=0; k $b} keys %{$sections_count}); + my @sections = (sort {$a <=> $b} keys(%{$sections_count})); my $numsec = scalar(@sections); my $is_selected = ' selected="selected"'; if ($numsec <= 1) { - $output = ''."\n". ' '."\n"; if ($current_sec eq 'none') { $output .= @@ -4746,7 +5451,7 @@ sub course_sections { my $multiple = 4; if (scalar(@sections) < 4) { $multiple = scalar(@sections); } if ($role eq 'st') { - $output .= '>'."\n". + $output .= $disabled.'>'."\n". ' '."\n"; if ($current_sec eq 'none') { $output .= @@ -4756,7 +5461,7 @@ sub course_sections { ' \n"; } } else { - $output .= 'multiple="multiple" size="'.$multiple.'">'."\n"; + $output .= 'multiple="multiple" size="'.$multiple.'"'.$disabled.'>'."\n"; } foreach my $sec (@sections) { if ($current_sec eq $sec) { @@ -4781,14 +5486,18 @@ sub get_groupslist { } sub setsections_javascript { - my ($formname,$groupslist,$mode,$checkauth,$crstype) = @_; + my ($formname,$groupslist,$mode,$checkauth,$crstype,$showcredits) = @_; my ($checkincluded,$finish,$rolecode,$setsection_js); if ($mode eq 'upload') { $checkincluded = 'formname.name == "'.$formname.'"'; $finish = "return 'ok';"; $rolecode = "var role = formname.defaultrole.options[formname.defaultrole.selectedIndex].value;\n"; } elsif ($formname eq 'cu') { - $checkincluded = 'formname.elements[i-1].checked == true'; + if (($crstype eq 'Course') && ($showcredits)) { + $checkincluded = "((role == 'st') && (formname.elements[i-2].checked == true)) || ((role != 'st') && (formname.elements[i-1].checked == true))"; + } else { + $checkincluded = 'formname.elements[i-1].checked == true'; + } if ($checkauth) { $finish = "var authcheck = auth_check();\n". " if (authcheck == 'ok') {\n". @@ -4799,7 +5508,7 @@ sub setsections_javascript { } $rolecode = "var match = str.split('_'); var role = match[3];\n"; - } elsif ($formname eq 'enrollstudent') { + } elsif (($formname eq 'enrollstudent') || ($formname eq 'selfenroll')) { $checkincluded = 'formname.name == "'.$formname.'"'; if ($checkauth) { $finish = "var authcheck = auth_check();\n". @@ -4824,8 +5533,8 @@ sub setsections_javascript { accr => 'A course coordinator role will be added with access to all sections.', acor => 'A coordinator role will be added with access to all sections', inea => 'In each course, each user may only have one student role at a time.', - inec => 'In each community, each user may only have on member role at a time.', - youh => 'You had selected ', + inco => 'In each community, each user may only have one member role at a time.', + youh => 'You had selected', secs => 'sections.', plmo => 'Please modify your selections so they include no more than one section.', mayn => 'may not be used as the name for a section, as it is a reserved word.', @@ -4833,19 +5542,26 @@ sub setsections_javascript { mnot => 'may not be used as a section name, as it is the name of a course group.', secn => 'Section names and group names must be distinct. Please choose a different section name.', nonw => 'Section names may only contain letters or numbers.', - ); + ); + &js_escape(\%alerts); $setsection_js .= <<"ENDSECCODE"; function setSections(formname,crstype) { var re1 = /^currsec_/; var re2 =/\\W/; + var trimleading = /^\\s+/; + var trimtrailing = /\\s+\$/; var groups = new Array($groupslist); for (var i=0;i 0) { - if (formname.elements[i+1].value != "" && formname.elements[i+1].value != null) { - sections = sections + "," + formname.elements[i+1].value; - } - } - else { - sections = formname.elements[i+1].value; - } - var newsecs = formname.elements[i+1].value; - var numsplit; + var newsecs = formname.elements[num+1].value; var validsecs = new Array(); + var validsecstr = ''; var badsecs = new Array(); if (newsecs != null && newsecs != "") { - numsplit = newsecs.split(/,/g); - for (var i=0; i 0) { @@ -4899,7 +5625,6 @@ function setSections(formname,crstype) { } numsec = numsec + validsecs.length; } - if ((role == 'st') && (numsec > 1)) { if (crstype == 'Community') { alert("$alerts{'inea'} $alerts{'youh'} "+numsec+" $alerts{'secs'}\\n$alerts{'plmo'}"); @@ -4907,25 +5632,36 @@ function setSections(formname,crstype) { alert("$alerts{'inco'} $alerts{'youh'} "+numsec+" $alerts{'secs'}\\n$alerts{'plmo'}"); } return; - } - else { - if (numsplit != null) { - for (var j=0; j 0) { - my %rule_check = &Apache::lonnet::inst_rulecheck($dom,$uname,undef,'username',\@user_rules); - if (keys(%rule_check) > 0) { - $usertype = 'unofficial'; - foreach my $item (keys(%rule_check)) { - if ($rule_check{$item}) { - $usertype = 'official'; - last; + if ((ref($got_rules) eq 'HASH') && (ref($curr_rules) eq 'HASH')) { + if (!$got_rules->{$dom}) { + my %domconfig = &Apache::lonnet::get_dom('configuration', + ['usercreation'],$dom); + if (ref($domconfig{'usercreation'}) eq 'HASH') { + foreach my $item ('username','id') { + if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') { + $curr_rules->{$dom}{$item} = + $domconfig{'usercreation'}{$item.'_rule'}; + } + } + } + $got_rules->{$dom} = 1; + } + if (ref($rules) eq 'HASH') { + my @user_rules; + if (ref($curr_rules->{$dom}{'username'}) eq 'ARRAY') { + foreach my $rule (keys(%{$rules})) { + if (grep(/^\Q$rule\E/,@{$curr_rules->{$dom}{'username'}})) { + push(@user_rules,$rule); + } + } + } + if (@user_rules > 0) { + my %rule_check = &Apache::lonnet::inst_rulecheck($dom,$uname,undef,'username',\@user_rules); + if (keys(%rule_check) > 0) { + $usertype = 'unofficial'; + foreach my $item (keys(%rule_check)) { + if ($rule_check{$item}) { + $usertype = 'official'; + last; + } } } } @@ -5062,7 +5823,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','sc','au','dc'); } return @allroles; } @@ -5104,6 +5865,22 @@ sub get_permission { if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) { $permission{'grp_manage'} = 1; } + if ($permission{'cusr'}) { + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my %coursehash = ( + 'internal.selfenrollmgrdc' => $env{'course.'.$env{'request.course.id'}.'.internal.selfenrollmgrdc'}, + 'internal.selfenrollmgrcc' => $env{'course.'.$env{'request.course.id'}.'.internal.selfenrollmgrcc'}, + 'internal.coursecode' => $env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}, + 'internal.textbook' =>$env{'course.'.$env{'request.course.id'}.'.internal.textbook'}, + ); + my ($managed_by_cc,$managed_by_dc) = &selfenrollment_administration($cdom,$cnum,$crstype,\%coursehash); + if (ref($managed_by_cc) eq 'ARRAY') { + if (@{$managed_by_cc}) { + $permission{'selfenrolladmin'} = 1; + } + } + } } elsif ($context eq 'author') { $permission{'cusr'} = &authorpriv($env{'user.name'},$env{'request.role.domain'}); $permission{'view'} = $permission{'cusr'}; @@ -5123,7 +5900,12 @@ 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; + } } my $allowed = 0; foreach my $perm (values(%permission)) { @@ -5176,7 +5958,7 @@ sub get_course_identity { } sub dc_setcourse_js { - my ($formname,$mode,$context) = @_; + my ($formname,$mode,$context,$showcredits) = @_; my ($dc_setcourse_code,$authen_check); my $cctext = &Apache::lonnet::plaintext('cc'); my $cotext = &Apache::lonnet::plaintext('co'); @@ -5262,7 +6044,7 @@ function setCourse() { } SCRIPTTOP if ($mode ne 'upload') { - $dc_setcourse_code .= (<<"ENDSCRIPT"); + $dc_setcourse_code .= (<<"SCRIPTMID"); var coursename = "_$env{'request.role.domain'}"+"_"+course+"_"+userrole var numcourse = getIndex(document.$formname.dccourse); if (numcourse == "-1") { @@ -5288,6 +6070,16 @@ SCRIPTTOP if (numend != "-1") { document.$formname.elements[numend].name = "end"+coursename } +SCRIPTMID + if ($showcredits) { + $dc_setcourse_code .= < 'There was a problem with your course selection', thwc => 'There was a problem with your community selection', ); + &js_escape(\%alerts); return %alerts; } @@ -5406,8 +6199,478 @@ sub authcheck_alerts { krb => 'You need to specify the Kerberos domain.', ipass => 'You need to specify the initial password.', ); + &js_escape(\%alerts); return %alerts; } +sub is_courseowner { + my ($thiscourse,$courseowner) = @_; + if ($courseowner eq '') { + if ($env{'request.course.id'} eq $thiscourse) { + $courseowner = $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'}; + } + } + if ($courseowner ne '') { + if ($courseowner eq $env{'user.name'}.':'.$env{'user.domain'}) { + return 1; + } + } + return; +} + +sub get_selfenroll_titles { + my @row = ('types','registered','enroll_dates','access_dates','section', + 'approval','limit'); + my %lt = &Apache::lonlocal::texthash ( + types => 'Users allowed to self-enroll', + registered => 'Registration status (official courses)' , + enroll_dates => 'Dates self-enrollment available', + access_dates => 'Access dates for self-enrolling users', + section => "Self-enrolling users' section", + approval => 'Processing of requests', + limit => 'Enrollment limit', + ); + return (\@row,\%lt); +} + +sub selfenroll_default_descs { + my %desc = ( + types => { + dom => &mt('Course domain'), + all => &mt('Any domain'), + '' => &mt('None'), + }, + limit => { + none => &mt('No limit'), + allstudents => &mt('Limit by total students'), + selfenrolled => &mt('Limit by total self-enrolled'), + }, + approval => { + '0' => &mt('Processed automatically'), + '1' => &mt('Queued for approval'), + '2' => &mt('Queued, pending validation'), + }, + registered => { + 0 => 'No registration required', + 1 => 'Registered students only', + }, + ); + return %desc; +} + +sub selfenroll_validation_types { + my @items = ('url','fields','button','markup'); + my %names = &Apache::lonlocal::texthash ( + url => 'Web address of validation server/script', + fields => 'Form fields to send to validator', + button => 'Text for validation button', + markup => 'Validation description (HTML)', + ); + my @fields = ('username','domain','uniquecode','course','coursetype','description'); + return (\@items,\%names,\@fields); +} + +sub get_extended_type { + my ($cdom,$cnum,$crstype,$current) = @_; + my $type = 'unofficial'; + my %settings; + if (ref($current) eq 'HASH') { + %settings = %{$current}; + } else { + %settings = &Apache::lonnet::get('environment',['internal.coursecode','internal.textbook'],$cdom,$cnum); + } + if ($crstype eq 'Community') { + $type = 'community'; + } elsif ($crstype eq 'Placement') { + $type = 'placement'; + } elsif ($settings{'internal.coursecode'}) { + $type = 'official'; + } elsif ($settings{'internal.textbook'}) { + $type = 'textbook'; + } + return $type; +} + +sub selfenrollment_administration { + my ($cdom,$cnum,$crstype,$coursehash) = @_; + my %settings; + if (ref($coursehash) eq 'HASH') { + %settings = %{$coursehash}; + } else { + %settings = &Apache::lonnet::get('environment', + ['internal.selfenrollmgrdc','internal.selfenrollmgrcc', + 'internal.coursecode','internal.textbook'],$cdom,$cnum); + } + my ($possconfigs) = &get_selfenroll_titles(); + my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom); + my $selfenrolltype = &get_extended_type($cdom,$cnum,$crstype,\%settings); + + my (@in_course,@in_domain); + if ($settings{'internal.selfenrollmgrcc'} ne '') { + @in_course = split(/,/,$settings{'internal.selfenrollmgrcc'}); + my @diffs = &Apache::loncommon::compare_arrays($possconfigs,\@in_course); + unless (@diffs) { + return (\@in_course,\@in_domain); + } + } + if ($settings{'internal.selfenrollmgrdc'} ne '') { + my @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'}); + my @diffs = &Apache::loncommon::compare_arrays(\@in_domain,$possconfigs); + unless (@diffs) { + return (\@in_course,\@in_domain); + } + } + my @combined = @in_course; + push(@combined,@in_domain); + my @diffs = &Apache::loncommon::compare_arrays(\@combined,$possconfigs); + unless (@diffs) { + return (\@in_course,\@in_domain); + } + if ($domdefaults{$selfenrolltype.'selfenrolladmdc'} eq '') { + push(@in_course,@diffs); + } else { + my @defaultdc = split(/,/,$domdefaults{$selfenrolltype.'selfenrolladmdc'}); + foreach my $item (@diffs) { + if (grep(/^\Q$item\E$/,@defaultdc)) { + push(@in_domain,$item); + } else { + push(@in_course,$item); + } + } + } + return (\@in_course,\@in_domain); +} + +sub custom_role_header { + my ($context,$crstype,$templaterolerefs,$prefix) = @_; + my %lt = &Apache::lonlocal::texthash( + sele => 'Select a Template', + ); + my ($context_code,$button_code); + if ($context eq 'domain') { + $context_code = &custom_coursetype_switch($crstype,$prefix); + } + if (ref($templaterolerefs) eq 'ARRAY') { + foreach my $role (@{$templaterolerefs}) { + my $display = 'inline'; + if (($context eq 'domain') && ($role eq 'co')) { + $display = 'none'; + } + $button_code .= &make_button_code($role,$crstype,$display,$prefix).' '; + } + } + return <<"END"; +
    +
    +$lt{'sele'} +$button_code +
    +$context_code +
    +END +} + +sub custom_coursetype_switch { + my ($crstype,$prefix) = @_; + my ($checkedcourse,$checkedcommunity); + if ($crstype eq 'Community') { + $checkedcommunity = ' checked="checked"'; + } else { + $checkedcourse = ' checked="checked"'; + } + my %lt = &Apache::lonlocal::texthash( + cont => 'Context', + cour => 'Course', + comm => 'Community', + ); + return <<"END"; +
    +
    +$lt{'cont'} +   + +
    +
    +END +} + +sub custom_role_table { + my ($crstype,$full,$levels,$levelscurrent,$prefix) = @_; + 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(). + &Apache::loncommon::start_data_table_header_row(). + '
    '. + &Apache::loncommon::end_data_table_header_row(); + foreach my $priv (sort(keys(%{$full}))) { + my $privtext = &Apache::lonnet::plaintext($priv,$crstype); + $output .= &Apache::loncommon::start_data_table_row(). + ''; + foreach my $type ('course','domain','system') { + if (($type eq 'system') && ($priv eq 'bre') && ($crstype eq 'Community')) { + $output .= ''; + } else { + $output .= ''; + } + } + $output .= &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::end_data_table(); + return $output; +} + +sub custom_role_privs { + my ($privs,$full,$levels,$levelscurrent)= @_; + return unless ((ref($privs) eq 'HASH') && (ref($full) eq 'HASH') && + (ref($levels) eq 'HASH') && (ref($levelscurrent) eq 'HASH')); + my %cr = ( + course => 'cr:c', + domain => 'cr:d', + system => 'cr:s', + ); + foreach my $type ('course','domain','system') { + foreach my $item (split(/\:/,$Apache::lonnet::pr{$cr{$type}})) { + my ($priv,$restrict)=split(/\&/,$item); + if (!$restrict) { $restrict='F'; } + $levels->{$type}->{$priv}=$restrict; + if ($privs->{$type}=~/\:$priv/) { + $levelscurrent->{$type}->{$priv}=1; + } + $full->{$priv}=1; + } + } + return; +} + +sub custom_template_roles { + my ($context,$crstype) = @_; + my @template_roles = ("in","ta","ep"); + if (($context eq 'domain') || ($context eq 'domprefs')) { + push(@template_roles,"ad"); + } + push(@template_roles,"st"); + if ($context eq 'domain') { + unshift(@template_roles,('co','cc')); + } else { + if ($crstype eq 'Community') { + unshift(@template_roles,'co'); + } else { + unshift(@template_roles,'cc'); + } + } + return @template_roles; +} + +sub custom_roledefs_js { + my ($context,$crstype,$formname,$full,$templaterolesref,$jsback) = @_; + my $button_code = "\n"; + my $head_script = "\n"; + my (%roletitlestr,$rolenamestr); + my %role_titles = ( + Course => [], + Community => [], + ); + $head_script .= ''."\n"; + return $head_script; +} + +# -------------------------------------------------------- +sub make_script_template { + my ($role,$crstype,$formname) = @_; + my $return_script = 'function set_'.$role.'(prefix) {'."\n"; + my (%full_by_level,%role_priv); + foreach my $level ('c','d','s') { + foreach my $item (split(/\:/,$Apache::lonnet::pr{'cr:'.$level})) { + next if (($level eq 's') && ($crstype eq 'Community') && ($item eq 'bre&S')); + my ($priv,$restrict)=split(/\&/,$item); + $full_by_level{$level}{$priv}=1; + } + $role_priv{$level} = {}; + my @temp = split(/:/,$Apache::lonnet::pr{$role.':'.$level}); + foreach my $priv (@temp) { + my ($priv_item, $dummy) = split(/\&/,$priv); + $role_priv{$level}{$priv_item} = 1; + } + } + my %to_check = ( + c => ['c','d','s'], + d => ['d','s'], + s => ['s'], + ); + foreach my $level ('c','d','s') { + if (ref($full_by_level{$level}) eq 'HASH') { + foreach my $priv (keys(%{$full_by_level{$level}})) { + my $value = 'false'; + if (ref($to_check{$level}) eq 'ARRAY') { + foreach my $lett (@{$to_check{$level}}) { + if (exists($role_priv{$lett}{$priv})) { + $value = 'true'; + last; + } + } + $return_script .= "document.$formname.elements[prefix+'".$priv."_".$level."'].checked = $value;\n"; + } + } + } + } + $return_script .= '}'."\n"; + return ($return_script); +} +# ---------------------------------------------------------- +sub make_button_code { + my ($role,$crstype,$display,$prefix) = @_; + my $label = &Apache::lonnet::plaintext($role,$crstype); + my $button_code = ''; + return ($button_code); +} + +sub custom_role_update { + my ($rolename,$prefix) = @_; +# ------------------------------------------------------- What can be assigned? + my %privs = ( + c => '', + d => '', + s => '', + ); + foreach my $level (keys(%privs)) { + foreach my $item (split(/\:/,$Apache::lonnet::pr{'cr:'.$level})) { + my ($priv,$restrict)=split(/\&/,$item); + if (!$restrict) { $restrict=''; } + if ($env{'form.'.$prefix.$priv.'_'.$level}) { + $privs{$level} .=':'.$item; + } + } + } + return %privs; +} + 1;
    '.&mt('manual').'
    '; + $cellentry = '
    '.&mt('manual').'
    '; $manualcount ++; if ($in{'lockedtype'}) { - $cellentry .= ''; + $cellentry .= ''; $unlockcount ++; } else { - $cellentry .= ''; + $cellentry .= ''; $lockcount ++; } $cellentry .= '
    '; @@ -2711,17 +3073,28 @@ 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('
      '.&print_username_link($mode,\%in).''.$in{$item}.''.$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"':'').' />':' '). + '