--- loncom/interface/lonuserutils.pm 2010/01/20 18:22:35 1.97.2.5 +++ loncom/interface/lonuserutils.pm 2012/08/21 15:43:27 1.141 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Utility functions for managing LON-CAPA user accounts # -# $Id: lonuserutils.pm,v 1.97.2.5 2010/01/20 18:22:35 raeburn Exp $ +# $Id: lonuserutils.pm,v 1.141 2012/08/21 15:43:27 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -91,7 +91,7 @@ sub modifyuserrole { if ($setting eq 'course' || $context eq 'course') { $scope = '/'.$cid; $scope =~ s/\_/\//g; - if ($role ne 'cc' && $sec ne '') { + if (($role ne 'cc') && ($role ne 'co') && ($sec ne '')) { $scope .='/'.$sec; } } elsif ($context eq 'domain') { @@ -295,7 +295,8 @@ sub hidden_input { } sub print_upload_manager_header { - my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission)=@_; + my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission,$crstype, + $can_assign)=@_; my $javascript; # if (! exists($env{'form.upfile_associate'})) { @@ -309,9 +310,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 @@ -332,7 +333,7 @@ sub print_upload_manager_header { my $javascript_validations = &javascript_validations('upload',$krbdefdom,$password_choice,undef, $env{'request.role.domain'},$context, - $groupslist); + $groupslist,$crstype); my $checked=(($env{'form.noFirstLine'})?' checked="checked"':''); $r->print('

' .&mt('Total number of records found in file: [_1]' @@ -365,7 +366,7 @@ sub print_upload_manager_header { ############################################################### sub javascript_validations { my ($mode,$krbdefdom,$curr_authtype,$curr_authfield,$domain, - $context,$groupslist)=@_; + $context,$groupslist,$crstype)=@_; my %param = ( kerb_def_dom => $krbdefdom, curr_authtype => $curr_authtype, @@ -386,10 +387,10 @@ sub javascript_validations { if (($context eq 'course') || ($context eq 'domain')) { if ($context eq 'course') { if ($env{'request.course.sec'} eq '') { - $setsection_call = 'setSections(document.'.$param{'formname'}.');'; + $setsection_call = 'setSections(document.'.$param{'formname'}.",'$crstype'".');'; $setsections_js = &setsections_javascript($param{'formname'},$groupslist, - $mode); + $mode,'',$crstype); } else { $setsection_call = "'ok'"; } @@ -532,6 +533,7 @@ END if (message!='') { message+='\\n'; } + message+='$alert{'section'}'; } if (foundemail==0) { if (message!='') { @@ -585,6 +587,46 @@ END ############################################################### ############################################################### sub upload_manager_javascript_forward_associate { + my ($can_assign) = @_; + my ($auth_update,$numbuttons,$argreset); + if (ref($can_assign) eq 'HASH') { + if ($can_assign->{'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.'); + $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.'); + $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) { @@ -830,7 +898,7 @@ sub print_upload_manager_footer { .' '.&mt('Add a domain role').'' .'   ' + .' '.&mt('Add a course/community role').'' .''; } elsif ($context eq 'author') { $Str .= &Apache::lonhtmlcommon::row_title( @@ -899,7 +967,7 @@ sub print_upload_manager_footer { .'


'; if ($context eq 'course') { $Str .= '

' - .&mt('Note: For large courses, this operation may be time consuming.') + .&mt('Note: This operation may be time consuming when adding several users.') .'

'; } $Str .= '

=0) { @@ -1141,7 +1210,7 @@ sub date_setting_table { } sub make_dates_default { - my ($startdate,$enddate,$context,$crstype = @_; + my ($startdate,$enddate,$context,$crstype) = @_; my $result = ''; if ($context eq 'course') { my ($cnum,$cdom) = &get_course_identity(); @@ -1176,7 +1245,7 @@ sub default_role_selector { my %customroles; my ($options,$coursepick,$cb_jscript); if ($context ne 'author') { - %customroles = &my_custom_roles(); + %customroles = &my_custom_roles($crstype); } my %lt=&Apache::lonlocal::texthash( @@ -1202,16 +1271,16 @@ sub default_role_selector { $options .= ' '; } my $courseform = &Apache::loncommon::selectcourse_link - ('studentform','dccourse','dcdomain','coursedesc',"$env{'request.role.domain'}",undef,'Course'); + ('studentform','dccourse','dcdomain','coursedesc',"$env{'request.role.domain'}",undef,'Course/Community'); $cb_jscript = - &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'},'currsec','studentform'); + &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'},'currsec','studentform','courserole','Course/Community'); $coursepick = &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(). ''.$courseform.''.$lt{'rol'}.''. ''.$lt{'grs'}.''. &Apache::loncommon::end_data_table_header_row(). &Apache::loncommon::start_data_table_row()."\n". - ''."\n". + ''."\n". ''. @@ -1229,6 +1298,7 @@ sub default_role_selector { $env{'request.role.domain'}.'" />'. ''. ''. + ''. ''. &Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table()."\n"; @@ -1349,10 +1419,15 @@ sub curr_role_permissions { # ======================================================= Existing Custom Roles sub my_custom_roles { + my ($crstype) = @_; my %returnhash=(); + my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1}); my %rolehash=&Apache::lonnet::dump('roles'); - foreach my $key (keys %rolehash) { + foreach my $key (keys(%rolehash)) { if ($key=~/^rolesdef\_(\w+)$/) { + if ($crstype eq 'Community') { + next if ($rolehash{$key} =~ /bre\&S/); + } $returnhash{$1}=$1; } } @@ -1369,8 +1444,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') { @@ -1403,12 +1479,12 @@ sub print_userlist { $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). + '

'); 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(' '.&list_submit_button(&mt('Update Display')). - "\n

\n"); + (($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')))) { + $r->print(&list_submit_button(&mt('Update Display'))."\n"); + } + + my @cols = &infocolumns($context,$mode); + if (!@cols) { + $r->print('
'. + &mt('No user information selected for display.').''. + ''."\n"); + return; } my ($indexhash,$keylist) = &make_keylist_array(); my (%userlist,%userinfo,$clearcoursepick); if (($context eq 'domain') && - ($env{'form.roletype'} eq 'course') || + ($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')) { my ($crstype,$numcodes,$title,$warning); if ($env{'form.roletype'} eq 'course') { @@ -1463,9 +1548,11 @@ 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); + $codetitles,$idlist,$idlist_titles,$crstype, + \@standardnames); $r->print('

'.&Apache::lonhtmlcommon::start_pick_box()."\n". &Apache::lonhtmlcommon::start_pick_box()."\n". &Apache::lonhtmlcommon::row_title($title,'LC_oddrow_value')."\n". @@ -1484,7 +1571,7 @@ sub print_userlist { $r->print('


'.&mt('Searching').' ...
 
'); } } else { - $r->print('
'.&mt('Searching').' ...
 
'); + $r->print('
'.&mt('Searching').' ...
'); } $r->rflush(); if ($context eq 'course') { @@ -1553,7 +1640,8 @@ sub print_userlist { } } } - } elsif ($env{'form.roletype'} eq 'course') { + } elsif (($env{'form.roletype'} eq 'course') || + ($env{'form.roletype'} eq 'community')) { if (($env{'form.coursepick'}) && (!$clearcoursepick)) { my %courses = &process_coursepick(); my %allusers; @@ -1637,6 +1725,7 @@ sub print_userlist { } $r->print(''); + return; } sub role_filter { @@ -1649,11 +1738,11 @@ sub role_filter { my ($role_select); if ($context eq 'domain') { $role_select = &domain_roles_select(); - $output = ''; + .''; } else { - $role_select = ''."\n". ''; my ($roletype,$crstype); @@ -1680,9 +1769,9 @@ sub role_filter { $role_select .= ''; } $role_select .= ''; - $output = ''; + .''; } return $output; } @@ -1711,7 +1800,7 @@ sub section_group_filter { $env{'form.'.$name{$item}} = 'all'; } if ($item eq 'sec') { - if ($env{'form.showrole'} eq 'cc') { + if (($env{'form.showrole'} eq 'cc') || ($env{'form.showrole'} eq 'co')) { $env{'form.'.$name{$item}} = 'none'; } my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum); @@ -1722,7 +1811,7 @@ sub section_group_filter { } if (@options > 0) { my $currsel; - $markup = ''."\n"; foreach my $option ('all','none',@options) { $currsel = ''; if ($env{'form.'.$name{$item}} eq $option) { @@ -1737,9 +1826,135 @@ sub section_group_filter { $markup .= ''."\n"; } $markup .= ''."\n"; - $output .= (' 'x3).''; + $output .= (' 'x3).'' + .'' + .' '; + } + } + return $output; +} + +sub infocolumns { + my ($context,$mode) = @_; + my @cols; + if (($mode eq 'pickauthor') || ($mode eq 'autoenroll')) { + @cols = &get_cols_array($context,$mode); + } else { + my @posscols = &get_cols_array($context,$mode); + 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) = @_; + 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')); + if ($context eq 'domain') { + push (@cols,'extent'); + } + 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')) { + push(@cols,'lastlogin','clicker'); + } + if (($context eq 'course') && ($mode ne 'autoenroll') && + ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'})) { + push(@cols,'photos'); + } + } + return @cols; +} + +sub column_checkboxes { + my ($context,$mode,$formname) = @_; + my @cols = &get_cols_array($context,$mode); + 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; + $unchecked{'start'} = 1; + $unchecked{'end'} = 1; + } else { + if ($env{'form.Status'} ne 'Any') { + $disabledchk{'status'} = 1; + } + if ($env{'form.showrole'} ne 'Any') { + $disabledchk{'role'} = 1; } } + my $numposs = scalar(@cols); + my $numinrow = 8; + 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 .= ''; + } + $output .= '
'; return $output; } @@ -1748,6 +1963,38 @@ sub list_submit_button { 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", + 'type' => "enroll type/action", + 'email' => "e-mail address", + 'photo' => "photo", + 'lastlogin' => "last login", + 'extent' => "extent", + '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('Communities: description, section(s), status'); + } elsif ($context eq 'author') { + $lt{'extent'} = &mt('Author'); + } + return %lt; +} + sub gather_userinfo { my ($context,$format,$userlist,$indexhash,$userinfo,$rolehash,$permission) = @_; my $viewablesec; @@ -1911,7 +2158,7 @@ function setCourseCat(formname) { if (formname.Year.options[formname.Year.selectedIndex].value == -1) { return; } - courseSet('Year'); + courseSet('$codetitles[0]'); for (var j=0; j 1) { my @course_ids = split(/&&/,$env{'form.courselist'}); @@ -2107,7 +2358,7 @@ sub show_users_list { $sortby = 'username'; } my $setting = $env{'form.roletype'}; - my ($cid,$cdom,$cnum,$classgroups,$displayphotos,$displayclickers,$crstype); + my ($cid,$cdom,$cnum,$classgroups,$crstype); if ($context eq 'course') { $cid = $env{'request.course.id'}; $crstype = &Apache::loncommon::course_type(); @@ -2117,14 +2368,6 @@ sub show_users_list { 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') { $crstype = 'Community'; - } elsif ($crstype eq 'course') { + } elsif ($setting eq 'course') { $crstype = 'Course'; } } 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); + 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'); } elsif ($env{'form.showrole'} ne 'Any') { - $rolefilter = &Apache::lonnet::plaintext($env{'form.showrole'}); + $rolefilter = &Apache::lonnet::plaintext($env{'form.showrole'},$crstype); } my $results_description; if ($mode ne 'autoenroll') { $results_description = &results_header_row($rolefilter,$statusmode, $context,$permission,$mode,$crstype); - - $r->print(''.$results_description.'

'); + $r->print(''.$results_description.'
'); } my ($output,$actionselect,%canchange,%canchangesec); if ($mode eq 'html' || $mode eq 'view' || $mode eq 'autoenroll' || $mode eq 'pickauthor') { if ($mode ne 'autoenroll' && $mode ne 'pickauthor') { if ($permission->{'cusr'}) { - $actionselect = &select_actions($context,$setting,$statusmode,$formname); + unless (($context eq 'domain') && + (($setting eq 'course') || ($setting eq 'community'))) { + $actionselect = + &select_actions($context,$setting,$statusmode,$formname); + } } $r->print(< @@ -2311,7 +2498,7 @@ END END if ($actionselect) { $output .= <<"END"; -
$lt{'ac'} +
$lt{'ac'} $actionselect

 
@@ -2352,11 +2539,17 @@ END if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'}.'/'.$env{'request.course.sec'})) { $canchangesec{$role} = $env{'request.course.sec'}; } + } elsif ((($role eq 'co') && ($crstype eq 'Community')) || + (($role eq 'cc') && ($crstype eq 'Course'))) { + if (&is_courseowner($env{'request.course.id'}, + $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'})) { + $canchange{$role} = 1; + } } } } } - $output .= '
'.$lt{'link'}.''. + $output .= '
'.$lt{'link'}.''. ''; my @linkdests = ('aboutme'); if ($permission->{'cusr'}) { @@ -2367,6 +2560,7 @@ END $env{'request.course.sec'})) { push(@linkdests,'track'); } + $output .= '
'; my $usernamelink = $env{'form.usernamelink'}; if ($usernamelink eq '') { @@ -2383,9 +2577,9 @@ END if ($env{'form.userwin'}) { $checkwin = ' checked="checked"'; } - $output .= ''.$lt{'owin'}.'
'; + $output .= ''.$lt{'owin'}.'
'; } - $output .= "\n".''."\n". + $output .= "\n".'
'."\n". &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(); if ($mode eq 'autoenroll') { @@ -2393,11 +2587,7 @@ END $lt{'type'} "; } else { - if ($mode eq 'pickauthor') { - $output .= "\n".' '."\n"; - } else { - $output .= "\n".''.&mt('Count').''."\n"; - } + $output .= "\n".' '."\n"; if ($actionselect) { $output .= ''.&mt('Select').''."\n"; } @@ -2406,42 +2596,6 @@ END $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 .= &Apache::loncommon::end_data_table_header_row(); # Done with the HTML header line } elsif ($mode eq 'csv') { @@ -2452,20 +2606,22 @@ END time.'_'.rand(1000000000).'.csv'; unless ($CSVfile = Apache::File->new('>/home/httpd'.$CSVfilename)) { $r->log_error("Couldn't open $CSVfilename for output $!"); - $r->print(&mt('Problems occurred in writing the CSV file. ' - .'This error has been logged. ' - .'Please alert your LON-CAPA administrator.')); + $r->print( + '

' + .&mt('Problems occurred in writing the CSV file.') + .' '.&mt('This error has been logged.') + .' '.&mt('Please alert your LON-CAPA administrator.') + .'

' + ); $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); @@ -2501,6 +2657,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})) { @@ -2584,7 +2745,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'}] = @@ -2636,16 +2797,24 @@ END if ($clickers!~/\w/) { $clickers='-'; } $in{'clicker'} = $clickers; my $role = $in{'role'}; - $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}],$crstype); - if (! defined($in{'start'}) || $in{'start'} == 0) { - $in{'start'} = &mt('none'); - } else { - $in{'start'} = &Apache::lonlocal::locallocaltime($in{'start'}); + $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}],$crstype); + unless ($mode eq 'excel') { + if (! defined($in{'start'}) || $in{'start'} == 0) { + $in{'start'} = &mt('none'); + } else { + $in{'start'} = &Apache::lonlocal::locallocaltime($in{'start'}); + } + if (! defined($in{'end'}) || $in{'end'} == 0) { + $in{'end'} = &mt('none'); + } else { + $in{'end'} = &Apache::lonlocal::locallocaltime($in{'end'}); + } } - if (! defined($in{'end'}) || $in{'end'} == 0) { - $in{'end'} = &mt('none'); - } else { - $in{'end'} = &Apache::lonlocal::locallocaltime($in{'end'}); + if ($context eq 'course') { + my $lastlogin = $crslogins{$in{'username'}.':'.$in{'domain'}.':'.$in{'section'}.':'.$role}; + if ($lastlogin ne '') { + $in{'lastlogin'} = &Apache::lonlocal::locallocaltime($lastlogin); + } } if ($mode eq 'view' || $mode eq 'html' || $mode eq 'autoenroll' || $mode eq 'pickauthor') { $r->print(&Apache::loncommon::start_data_table_row()); @@ -2691,17 +2860,26 @@ 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'}; + } + } + } + if ($showcheckbox) { + $r->print(''); + } else { + $r->print(' '); } - $r->print(''); } else { $r->print(' '); } @@ -2720,43 +2898,34 @@ END $showitem = $ltstatus{$in{$item}}; } $r->print(''.$showitem.''."\n"); - } else { - $r->print(''.$in{$item}.''."\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(''.$clickers.''); - } 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(''.$clickers.''); } else { - $r->print('   '); - } - } + $r->print(' '."\n"); + } + } + } else { + $r->print(''.$in{$item}.''."\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}); @@ -2766,9 +2935,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'); @@ -2923,7 +3092,7 @@ sub print_username_link { $output = $in->{'username'}; } else { $output = '{'username'}','$in->{'domain'}'".')" />'. + "'$in->{'username'}','$in->{'domain'}'".')">'. $in->{'username'}.''; } return $output; @@ -2935,7 +3104,6 @@ sub role_type_names { 'author' => 'Co-Author Roles', 'course' => 'Course Roles', 'community' => 'Community Roles', - ); return %lt; } @@ -2957,15 +3125,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; + } } } } @@ -3097,7 +3270,7 @@ END } else { opener.document.$callingform.retainsec.value = formname.retainsec.value; } - setSections(formname); + setSections(formname,'$crstype'); if (seccheck == 'ok') { opener.document.$callingform.newsecs.value = formname.sections.value; } @@ -3154,10 +3327,10 @@ ENDJS my %lt = &Apache::lonlocal::texthash ( chac => 'Access dates to apply for selected users', chse => 'Changes in section affiliation to apply to selected users', - fors => 'For student roles changing the section, will result in a section switch as students may only be in one section of a course at a time.', - forn => 'For a role in a course that is not a student role, a user may have roles in more than one section of a course at a time.', - reta => "Retain each user's current section affiliations?", - dnap => '(Does not apply to student roles).', + fors => 'For student roles, changing the section will result in a section switch as students may only be in one section of a course at a time.', + forn => 'For a course role that is not "student", users may have roles in more than one section at a time.', + reta => "Retain each user's current section affiliations?", + dnap => '(Does not apply to student roles).', ); my ($date_items,$headertext); if ($env{'form.bulkaction'} eq 'chgsec') { @@ -3174,10 +3347,15 @@ ENDJS $permission,$crstype); } $output .= '

'.$headertext.'

'. - '
'."\n". + ''."\n". $date_items; if ($context eq 'course' && $env{'form.bulkaction'} eq 'chgsec') { my ($cnum,$cdom) = &get_course_identity(); + if ($crstype eq 'Community') { + $lt{'fors'} = &mt('For member roles, changing the section will result in a section switch, as members may only be in one section of a community at a time.'); + $lt{'forn'} = &mt('For a community role that is not "member", users may have roles in more than one section at a time.'); + $lt{'dnap'} = &mt('(Does not apply to member roles).'); + } my $info; if ($env{'form.showrole'} eq 'st') { $output .= '

'.$lt{'fors'}.'

'; @@ -3216,7 +3394,7 @@ sub section_picker { my ($cdom,$cnum,$role,$rowtitle,$permission,$context,$mode,$crstype) = @_; my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum); my $sections_select .= &course_sections(\%sections_count,$role); - my $secbox = '

'.&Apache::lonhtmlcommon::start_pick_box()."\n"; + my $secbox = '

'.&Apache::lonhtmlcommon::start_pick_box()."\n"; if ($mode eq 'upload') { my ($options,$cb_script,$coursepick) = &default_role_selector($context,1,$crstype); @@ -3229,7 +3407,7 @@ sub section_picker { ''.&mt('Existing sections')."\n". '
'.$sections_select.''. &mt('New section').'
'."\n". - ''."\n". + ''."\n". ''."\n". ''."\n"; } else { @@ -3238,7 +3416,7 @@ sub section_picker { $env{'request.course.sec'}; } $secbox .= &Apache::lonhtmlcommon::row_closure(1)."\n". - &Apache::lonhtmlcommon::end_pick_box().'

'; + &Apache::lonhtmlcommon::end_pick_box().'
'; return $secbox; } @@ -3294,7 +3472,7 @@ sub results_header_row { if ($viewablesec ne '') { if ($env{'form.showrole'} eq 'st') { $constraint = &mt('only users in section "[_1]"',$viewablesec); - } elsif ($env{'form.showrole'} ne 'cc') { + } elsif (($env{'form.showrole'} ne 'cc') && ($env{'form.showrole'} ne 'co')) { $constraint = &mt('only users affiliated with no section or section "[_1]"',$viewablesec); } if (($env{'form.grpfilter'} ne 'all') && ($env{'form.grpfilter'} ne '')) { @@ -3379,12 +3557,11 @@ sub results_header_row { if ($rolefilter eq 'Any') { $description .= &mt('All users with co-author roles in domain',$showfilter); } else { - $description .= &mt('All co-authors in domain with [_1] roles',$rolefilter); + $description .= &mt('All co-authors in domain with [_1] roles',$rolefilter); } } } elsif (($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')) { - my $coursefilter = $env{'form.coursepick'}; if ($env{'form.roletype'} eq 'course') { if ($coursefilter eq 'category') { @@ -3637,24 +3814,26 @@ sub print_first_users_upload_form { $str .= ''; $str .= ''; - $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" + .'
'."\n" .&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')) - .'

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

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

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

'."\n"; + } + } + $str .= &Apache::loncommon::upfile_select_html() .&Apache::lonhtmlcommon::row_closure() .&Apache::lonhtmlcommon::row_title( '