--- loncom/interface/lonuserutils.pm 2007/12/21 15:22:01 1.19
+++ loncom/interface/lonuserutils.pm 2009/09/12 17:10:44 1.97.2.3
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Utility functions for managing LON-CAPA user accounts
#
-# $Id: lonuserutils.pm,v 1.19 2007/12/21 15:22:01 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.97.2.3 2009/09/12 17:10:44 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -42,7 +42,7 @@ use LONCAPA qw(:DEFAULT :match);
###############################################################
# Drop student from all sections of a course, except optional $csec
sub modifystudent {
- my ($udom,$unam,$courseid,$csec,$desiredhost)=@_;
+ my ($udom,$unam,$courseid,$csec,$desiredhost,$context)=@_;
# if $csec is undefined, drop the student from all the courses matching
# this one. If $csec is defined, drop them from all other sections of
# this course and add them to section $csec
@@ -68,14 +68,15 @@ sub modifystudent {
my $reply=&Apache::lonnet::modifystudent
# dom name id mode pass f m l g
($udom,$unam,'', '', '',undef,undef,undef,undef,
- $section,time,undef,undef,$desiredhost);
+ $section,time,undef,undef,$desiredhost,'','manual',
+ '',$courseid,'',$context);
$result .= $reply.':';
}
}
}
}
if ($result eq '') {
- $result = 'Unable to find section for this student';
+ $result = &mt('Unable to find section for this student');
} else {
$result =~ s/(ok:)+/ok/g;
}
@@ -85,7 +86,7 @@ sub modifystudent {
sub modifyuserrole {
my ($context,$setting,$changeauth,$cid,$udom,$uname,$uid,$umode,$upass,
$first,$middle,$last,$gene,$sec,$forceid,$desiredhome,$email,$role,
- $end,$start,$checkid) = @_;
+ $end,$start,$checkid,$inststatus) = @_;
my ($scope,$userresult,$authresult,$roleresult,$idresult);
if ($setting eq 'course' || $context eq 'course') {
$scope = '/'.$cid;
@@ -123,11 +124,13 @@ sub modifyuserrole {
$userresult =
&Apache::lonnet::modifyuser($udom,$uname,$uid,$umode,$upass,$first,
$middle,$last,$gene,$forceid,$desiredhome,
- $email,$role,$start,$end);
+ $email,$inststatus);
if ($userresult eq 'ok') {
if ($role ne '') {
+ $role =~ s/_/\//g;
$roleresult = &Apache::lonnet::assignrole($udom,$uname,$scope,
- $role,$end,$start);
+ $role,$end,$start,'',
+ '',$context);
}
}
return ($userresult,$authresult,$roleresult,$idresult);
@@ -145,7 +148,7 @@ sub propagate_id_change {
one_time => 1,
);
foreach my $item (keys(%roleshash)) {
- my ($cnum,$cdom,$role) = split(/:/,$item);
+ my ($cnum,$cdom,$role) = split(/:/,$item,-1);
my ($start,$end) = split(/:/,$roleshash{$item});
if (&Apache::lonnet::is_course($cdom,$cnum)) {
my $result = &update_classlist($cdom,$cnum,$udom,$uname,$user);
@@ -166,7 +169,7 @@ sub propagate_id_change {
}
sub update_classlist {
- my ($cdom,$cnum,$udom,$uname,$user) = @_;
+ my ($cdom,$cnum,$udom,$uname,$user,$newend) = @_;
my ($uid,$classlistentry);
my $fullname =
&Apache::lonnet::format_name($user->{'firstname'},$user->{'middlename'},
@@ -177,15 +180,37 @@ sub update_classlist {
my @classinfo = split(/:/,$classhash{$uname.':'.$udom});
my $ididx=&Apache::loncoursedata::CL_ID() - 2;
my $nameidx=&Apache::loncoursedata::CL_FULLNAME() - 2;
+ my $endidx = &Apache::loncoursedata::CL_END() - 2;
+ my $startidx = &Apache::loncoursedata::CL_START() - 2;
for (my $i=0; $i<@classinfo; $i++) {
- if ($i == $ididx) {
+ if ($i == $endidx) {
+ if ($newend ne '') {
+ $classlistentry .= $newend.':';
+ } else {
+ $classlistentry .= $classinfo[$i].':';
+ }
+ } elsif ($i == $startidx) {
+ if ($newend ne '') {
+ if ($classinfo[$i] > $newend) {
+ $classlistentry .= $newend.':';
+ } else {
+ $classlistentry .= $classinfo[$i].':';
+ }
+ } else {
+ $classlistentry .= $classinfo[$i].':';
+ }
+ } elsif ($i == $ididx) {
if (defined($user->{'id'})) {
$classlistentry .= $user->{'id'}.':';
} else {
$classlistentry .= $classinfo[$i].':';
}
} elsif ($i == $nameidx) {
- $classlistentry .= $fullname.':';
+ if (defined($user->{'lastname'})) {
+ $classlistentry .= $fullname.':';
+ } else {
+ $classlistentry .= $classinfo[$i].':';
+ }
} else {
$classlistentry .= $classinfo[$i].':';
}
@@ -265,7 +290,7 @@ sub hidden_input {
}
sub print_upload_manager_header {
- my ($r,$datatoken,$distotal,$krbdefdom,$context)=@_;
+ my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission)=@_;
my $javascript;
#
if (! exists($env{'form.upfile_associate'})) {
@@ -295,12 +320,19 @@ sub print_upload_manager_header {
$password_choice = 'int';
}
#
+ my $groupslist;
+ if ($context eq 'course') {
+ $groupslist = &get_groupslist();
+ }
my $javascript_validations =
- &javascript_validations('auth',$krbdefdom,$password_choice,undef,
- $env{'request.role.domain'});
- my $checked=(($env{'form.noFirstLine'})?' checked="checked" ':'');
- $r->print(&mt('Total number of records found in file: [_1].',$distotal).
- "
\n");
+ &javascript_validations('upload',$krbdefdom,$password_choice,undef,
+ $env{'request.role.domain'},$context,
+ $groupslist);
+ my $checked=(($env{'form.noFirstLine'})?' checked="checked"':'');
+ $r->print('
' + .&mt('Total number of records found in file: [_1]' + ,''.$distotal.'') + ."
\n"); $r->print(''.&mt('Change authentication for existing users to these settings?').'
'; + $Str .= '' + .&mt('Change authentication for existing users in domain "[_1]" to these settings?' + ,$defdom) + .' ' + .' ' + .'
'; } else { - $Str .= "\n". - &mt('Note: this will not take effect if the user already exists'). + $Str .= '
'."\n". + &mt('This will not take effect if the user already exists.'). &Apache::loncommon::help_open_topic('Auth_Options'). "
\n"; } $Str .= &set_login($defdom,$krbform,$intform,$locform); + my ($home_server_pick,$numlib) = &Apache::loncommon::home_server_form_item($defdom,'lcserver', 'default','hide'); if ($numlib > 1) { - $Str .= '\n".$date_table."
\n"; - if ($context eq 'domain') { - $Str .= '\n".$date_table."
\n" + .&Apache::lonhtmlcommon::row_closure(); + if ($context eq 'domain') { - $Str .= ''.&mt('Domain Level').''.&mt('role').': '. - $options.' | '. - ''.&mt('section').': |
'
+ .''.&mt('Domain Level').'
'
+ .$options
+ .'
' + .''.&mt('Course Level').'' + .'
' + .$cb_script.$coursepick + .&Apache::lonhtmlcommon::row_closure(); + } elsif ($context eq 'author') { + $Str .= $options + .&Apache::lonhtmlcommon::row_closure(1); # last row in pick_box + } + } else { + my ($cnum,$cdom) = &get_course_identity(); + my $rowtitle = &mt('section'); + my $secbox = §ion_picker($cdom,$cnum,'Any',$rowtitle, + $permission,$context,'upload'); + $Str .= $secbox + .&Apache::lonhtmlcommon::row_closure(); + + $Str .= &Apache::lonhtmlcommon::row_title(&mt('Full Update')) + .'\n".'
'."\n".
- &mt('(only do if you know what you are doing.)')."
\n";
+ &Apache::lonhtmlcommon::row_title(&mt('Student/Employee ID'))
+ .'
'."\n"
+ .&mt('(only do if you know what you are doing.)')."\n";
if ($context eq 'domain') {
- $output .= '
'.
- $lt{'exs'}.' | '.
''. ' | '.$lt{'new'}.' '. ''. - ' | '.
- '
'.&list_submit_button(&mt('Update Display')). - "\n
\n"); + "\n".''.&mt('Warning: data retrieval for multiple courses can take considerable time, as this operation is not currently optimized.').''."\n"); if ($env{'form.coursepick'}) { $r->print(''; + if ($actionselect) { + $output .= <<"END"; +
+END + my @allroles; + if ($env{'form.showrole'} eq 'Any') { + my $custom = 1; + if ($context eq 'domain') { + @allroles = &roles_by_context($setting,$custom); + } else { + @allroles = &roles_by_context($context,$custom); + } + } else { + @allroles = ($env{'form.showrole'}); + } + foreach my $role (@allroles) { + if ($context eq 'domain') { + if ($setting eq 'domain') { + if (&Apache::lonnet::allowed('c'.$role, + $env{'request.role.domain'})) { + $canchange{$role} = 1; + } + } elsif ($setting eq 'author') { + if (&Apache::lonnet::allowed('c'.$role, + $env{'request.role.domain'})) { + $canchange{$role} = 1; + } + } + } elsif ($context eq 'author') { + if (&Apache::lonnet::allowed('c'.$role, + $env{'user.domain'}.'/'.$env{'user.name'})) { + $canchange{$role} = 1; + } + } elsif ($context eq 'course') { + if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'})) { + $canchange{$role} = 1; + } elsif ($env{'request.course.sec'} ne '') { + if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'}.'/'.$env{'request.course.sec'})) { + $canchangesec{$role} = $env{'request.course.sec'}; + } + } + } + } + } + $output .= ''; } - $output .= "\n\n". + $output .= "\n".'
'."\n". &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(); if ($mode eq 'autoenroll') { $output .= " -'.&mt('manual').' | |||
|
'. - &mt('Your Excel spreadsheet').' '.&mt('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('Your CSV file').' is ready for download.'. - "\n"); + $r->print(&mt('[_1]Your CSV file[_2] is ready for download.', '','')."
\n"); $r->rflush(); } if ($mode eq 'autoenroll') { @@ -2281,15 +2715,130 @@ END } } +sub bulkaction_javascript { + my ($formname,$caller) = @_; + my $docstart = 'document'; + if ($caller eq 'popup') { + $docstart = 'opener.document'; + } + my %lt = &Apache::lonlocal::texthash( + acwi => 'Access will be set to start immediately', + asyo => 'as you did not select an end date in the pop-up window', + accw => 'Access will be set to continue indefinitely', + asyd => 'as you did not select an end date in the pop-up window', + sewi => "Sections will be switched to 'No section'", + ayes => "as you either selected the 'No section' option", + oryo => 'or you did not select a section in the pop-up window', + arol => 'A role with no section will be added', + swbs => 'Sections will be switched to:', + rwba => 'Roles will be added for section(s):', + ); + my $alert = &mt("You must select at least one user by checking a user's 'Select' checkbox"); + 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?'); + my $output = <<"ENDJS"; +function verify_action (field) { + var numchecked = 0; + var singconf = '$singconfirm'; + var multconf = '$multconfirm'; + if ($docstart.$formname.elements[field].length > 0) { + for (i=0; i<$docstart.$formname.elements[field].length; i++) { + if ($docstart.$formname.elements[field][i].checked == true) { + numchecked ++; + } + } + } else { + if ($docstart.$formname.elements[field].checked == true) { + numchecked ++; + } + } + if (numchecked == 0) { + alert("$alert"); + return; + } else { + var message = $docstart.$formname.bulkaction[$docstart.$formname.bulkaction.selectedIndex].text; + var choice = $docstart.$formname.bulkaction[$docstart.$formname.bulkaction.selectedIndex].value; + if (choice == '') { + alert("$noaction"); + return; + } else { + if (numchecked == 1) { + message += singconf; + } else { + message += multconf; + } +ENDJS + if ($caller ne 'popup') { + $output .= <<"NEWWIN"; + if (choice == 'chgdates' || choice == 'reenable' || choice == 'activate' || choice == 'chgsec') { + opendatebrowser(document.$formname,'$formname','go'); + return; + + } else { + if (confirm(message)) { + document.$formname.phase.value = 'bulkchange'; + document.$formname.submit(); + return; + } + } +NEWWIN + } else { + $output .= <<"POPUP"; + if (choice == 'chgdates' || choice == 'reenable' || choice == 'activate') { + var datemsg = ''; + if (($docstart.$formname.startdate_month.value == '') && + ($docstart.$formname.startdate_day.value == '') && + ($docstart.$formname.startdate_year.value == '')) { + datemsg = "\\n$lt{'acwi'},\\n$lt{'asyo'}.\\n"; + } + if (($docstart.$formname.enddate_month.value == '') && + ($docstart.$formname.enddate_day.value == '') && + ($docstart.$formname.enddate_year.value == '')) { + datemsg += "\\n$lt{'accw'},\\n$lt{'asyd'}.\\n"; + } + if (datemsg != '') { + message += "\\n"+datemsg; + } + } + if (choice == 'chgsec') { + var rolefilter = $docstart.$formname.showrole.options[$docstart.$formname.showrole.selectedIndex].value; + var retained = $docstart.$formname.retainsec.value; + var secshow = $docstart.$formname.newsecs.value; + if (secshow == '') { + if (rolefilter == 'st' || retained == 0 || retained == "") { + message += "\\n\\n$lt{'sewi'},\\n$lt{'ayes'},\\n$lt{'oryo'}.\\n"; + } else { + message += "\\n\\n$lt{'arol'}\\n$lt{'ayes'},\\n$lt{'oryo'}.\\n"; + } + } else { + if (rolefilter == 'st' || retained == 0 || retained == "") { + message += "\\n\\n$lt{'swbs'} "+secshow+".\\n"; + } else { + message += "\\n\\n$lt{'rwba'} "+secshow+".\\n"; + } + } + } + if (confirm(message)) { + $docstart.$formname.phase.value = 'bulkchange'; + $docstart.$formname.submit(); + window.close(); + } +POPUP + } + $output .= ' + } + } +} +'; + return $output; +} + sub print_username_link { - my ($mode,$permission,$in) = @_; + my ($mode,$in) = @_; my $output; if ($mode eq 'autoenroll') { $output = $in->{'username'}; - } elsif (!$permission->{'cusr'}) { - $output = &Apache::loncommon::aboutmewrapper($in->{'username'}, - $in->{'username'}, - $in->{'domain'}); } else { $output = '{'username'}','$in->{'domain'}'".')" />'. @@ -2308,7 +2857,7 @@ sub role_type_names { } sub select_actions { - my ($context,$setting,$statusmode) = @_; + my ($context,$setting,$statusmode,$formname) = @_; my %lt = &Apache::lonlocal::texthash( revoke => "Revoke user roles", delete => "Delete user roles", @@ -2318,6 +2867,24 @@ sub select_actions { chgsec => "Change section associated with user roles", ); my ($output,$options,%choices); + # FIXME Disable actions for now for roletype=course in domain context + if ($context eq 'domain' && $setting eq 'course') { + return; + } + 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; + } + } + } + } + } if ($statusmode eq 'Any') { $options .= ' '; @@ -2344,14 +2911,14 @@ sub select_actions { '; } if (($context eq 'course') || ($context eq 'domain' && $setting eq 'course')) { - if ($statusmode ne 'Expired') { + if (($statusmode ne 'Expired') && ($env{'request.course.sec'} eq '')) { $options .= ' '; $choices{'sections'} = 1; } } if ($options) { - $output = '- + END - -my %lt=&Apache::lonlocal::texthash('usrn' => "username", - 'dom' => "domain", - 'sn' => "student name", - 'sec' => "section", - 'start' => "start date", - 'end' => "end date", - 'groups' => "active groups", - ); + my ($indexhash,$keylist) = &make_keylist_array(); + my $studentcount = 0; + if (ref($classlist) eq 'HASH') { + foreach my $student (keys(%{$classlist})) { + my $sdata = $classlist->{$student}; + my $status = $sdata->[$indexhash->{'status'}]; + my $section = $sdata->[$indexhash->{'section'}]; + if ($status ne 'Active') { + delete($classlist->{$student}); + next; + } + if ($env{'request.course.sec'} ne '') { + if ($section ne $env{'request.course.sec'}) { + delete($classlist->{$student}); + next; + } + } + $studentcount ++; + } + } + if (!$studentcount) { + $r->print(&mt('There are no students to drop.')); + return; + } + my ($classgroups) = &Apache::loncoursedata::get_group_memberships( + $classlist,$keylist,$cdom,$cnum); + my %lt=&Apache::lonlocal::texthash('usrn' => "username", + 'dom' => "domain", + 'sn' => "student name", + 'sec' => "section", + 'start' => "start date", + 'end' => "end date", + 'groups' => "active groups", + ); if ($nosort) { $r->print(&Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row()); @@ -2774,32 +3424,26 @@ END } # # Sort the students - my %index; - my $i; - foreach (@$keylist) { - $index{$_} = $i++; - } - $index{'groups'} = scalar(@$keylist); - my $index = $index{$sortby}; - my $second = $index{'username'}; - my $third = $index{'domain'}; + my $index = $indexhash->{$sortby}; + my $second = $indexhash->{'username'}; + my $third = $indexhash->{'domain'}; my @Sorted_Students = sort { lc($classlist->{$a}->[$index]) cmp lc($classlist->{$b}->[$index]) || lc($classlist->{$a}->[$second]) cmp lc($classlist->{$b}->[$second]) || lc($classlist->{$a}->[$third]) cmp lc($classlist->{$b}->[$third]) - } (keys(%$classlist)); + } (keys(%{$classlist})); foreach my $student (@Sorted_Students) { my $error; my $sdata = $classlist->{$student}; - my $username = $sdata->[$index{'username'}]; - my $domain = $sdata->[$index{'domain'}]; - my $section = $sdata->[$index{'section'}]; - my $name = $sdata->[$index{'fullname'}]; - my $id = $sdata->[$index{'id'}]; - my $start = $sdata->[$index{'start'}]; - my $end = $sdata->[$index{'end'}]; + my $username = $sdata->[$indexhash->{'username'}]; + my $domain = $sdata->[$indexhash->{'domain'}]; + my $section = $sdata->[$indexhash->{'section'}]; + my $name = $sdata->[$indexhash->{'fullname'}]; + my $id = $sdata->[$indexhash->{'id'}]; + my $start = $sdata->[$indexhash->{'start'}]; + my $end = $sdata->[$indexhash->{'end'}]; my $groups = $classgroups->{$student}; my $active_groups; if (ref($groups->{active}) eq 'HASH') { @@ -2815,25 +3459,18 @@ END } else { $end = &Apache::lonlocal::locallocaltime($end); } - my $status = $sdata->[$index{'status'}]; - next if ($status ne 'Active'); - if ($env{'request.course.sec'} ne '') { - if ($section ne $env{'request.course.sec'}) { - next; - } - } my $studentkey = $student.':'.$section; - my $startitem = ''; + my $startitem = ''; # $r->print(&Apache::loncommon::start_data_table_row()); $r->print(<<"END"); -
- - -
+ ++ + +
++ +
END return; } @@ -2860,30 +3501,49 @@ END sub print_first_users_upload_form { my ($r,$context) = @_; my $str; - $str = ''; + $str = ''; $str .= ''; $str .= ''; - $str .= "\n"; - $str .= ''."\n"; - $str .= '
\n"; - $str .= &Apache::loncommon::help_open_topic("Course_Create_Class_List", - &mt("How do I create a users list from a spreadsheet")). - "'
+ .&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",
+ &mt("How do I create a CSV file from a spreadsheet"))
+ ."
'."\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_closure() + .&Apache::lonhtmlcommon::row_title( + '') + .'' + .&Apache::lonhtmlcommon::row_closure(1) + .&Apache::lonhtmlcommon::end_pick_box(); + + $str .= '' + .'' + .'
'; + $str .= &Apache::loncommon::end_page(); + $r->print($str); return; } # ================================================= Drop/Add from uploaded file sub upfile_drop_add { - my ($r,$context) = @_; + my ($r,$context,$permission) = @_; &Apache::loncommon::load_tmp_file($r); my @userdata=&Apache::loncommon::upfile_record_sep(); if($env{'form.noFirstLine'}){shift(@userdata);} @@ -2898,10 +3558,14 @@ sub upfile_drop_add { $fields{$env{'form.f'.$i}}=$keyfields[$i]; } } + if ($env{'form.fullup'} ne 'yes') { + $r->print(''); ##################################### - # Drop students # + # Display list of students to drop # ##################################### if ($env{'form.fullup'} eq 'yes') { - $r->print(''.&mt("$result_text{'ok'}{$choice} role(s) for [quant,_1,user,users,users].",$count).'
'); + $r->print(''."\n"); } sub classlist_drop { - my ($scope,$uname,$udom,$now,$action) = @_; + my ($scope,$uname,$udom,$now) = @_; my ($cdom,$cnum) = ($scope=~m{^/($match_domain)/($match_courseid)}); - my $cid=$cdom.'_'.$cnum; - my $user = $uname.':'.$udom; - if ($action eq 'drop') { + if (&Apache::lonnet::is_course($cdom,$cnum)) { if (!&active_student_roles($cnum,$cdom,$uname,$udom)) { - my $result = - &Apache::lonnet::cput('classlist', - { $user => $now }, - $env{'course.'.$cid.'.domain'}, - $env{'course.'.$cid.'.num'}); + my %user; + my $result = &update_classlist($cdom,$cnum,$udom,$uname,\%user,$now); return &mt('Drop from classlist: [_1]', ''.$result.'').'