# The LearningOnline Network with CAPA
# Utility functions for managing LON-CAPA user accounts
#
# $Id: lonuserutils.pm,v 1.169 2014/12/15 01:11:49 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
#
###############################################################
###############################################################
package Apache::lonuserutils;
use strict;
use Apache::lonnet;
use Apache::loncommon();
use Apache::lonhtmlcommon;
use Apache::lonlocal;
use Apache::longroup;
use LONCAPA qw(:DEFAULT :match);
###############################################################
###############################################################
# Drop student from all sections of a course, except optional $csec
sub modifystudent {
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
my ($cnum,$cdom) = &get_course_identity($courseid);
my %roles = &Apache::lonnet::dump('roles',$udom,$unam);
my ($tmp) = keys(%roles);
# Bail out if we were unable to get the students roles
return "$1" if ($tmp =~ /^(con_lost|error|no_such_host)/i);
# Go through the roles looking for enrollment in this course
my $result = '';
foreach my $course (keys(%roles)) {
if ($course=~m{^/\Q$cdom\E/\Q$cnum\E(?:\/)*(?:\s+)*(\w+)*\_st$}) {
# We are in this course
my $section=$1;
$section='' if ($course eq "/$cdom/$cnum".'_st');
if (defined($csec) && $section eq $csec) {
$result .= 'ok:';
} elsif ( ((!$section) && (!$csec)) || ($section ne $csec) ) {
my (undef,$end,$start)=split(/\_/,$roles{$course});
my $now=time;
# if this is an active role
if (!($start && ($now<$start)) || !($end && ($now>$end))) {
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,'','manual',
'',$courseid,'',$context);
$result .= $reply.':';
}
}
}
}
if ($result eq '') {
$result = &mt('Unable to find section for this student');
} else {
$result =~ s/(ok:)+/ok/g;
}
return $result;
}
sub modifyuserrole {
my ($context,$setting,$changeauth,$cid,$udom,$uname,$uid,$umode,$upass,
$first,$middle,$last,$gene,$sec,$forceid,$desiredhome,$email,$role,
$end,$start,$checkid,$inststatus) = @_;
my ($scope,$userresult,$authresult,$roleresult,$idresult);
if ($setting eq 'course' || $context eq 'course') {
$scope = '/'.$cid;
$scope =~ s/\_/\//g;
if (($role ne 'cc') && ($role ne 'co') && ($sec ne '')) {
$scope .='/'.$sec;
}
} elsif ($context eq 'domain') {
$scope = '/'.$env{'request.role.domain'}.'/';
} elsif ($context eq 'author') {
$scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'};
}
if ($context eq 'domain') {
my $uhome = &Apache::lonnet::homeserver($uname,$udom);
if ($uhome ne 'no_host') {
if (($changeauth eq 'Yes') && (&Apache::lonnet::allowed('mau',$udom))) {
if ((($umode =~ /^krb4|krb5|internal$/) && $upass ne '') ||
($umode eq 'localauth')) {
$authresult = &Apache::lonnet::modifyuserauth($udom,$uname,$umode,$upass);
}
}
if (($forceid) && (&Apache::lonnet::allowed('mau',$udom)) &&
($env{'form.recurseid'}) && ($checkid)) {
my %userupdate = (
lastname => $last,
middlename => $middle,
firstname => $first,
generation => $gene,
id => $uid,
);
$idresult = &propagate_id_change($uname,$udom,\%userupdate);
}
}
}
$userresult =
&Apache::lonnet::modifyuser($udom,$uname,$uid,$umode,$upass,$first,
$middle,$last,$gene,$forceid,$desiredhome,
$email,$inststatus);
if ($userresult eq 'ok') {
if ($role ne '') {
$role =~ s/_/\//g;
$roleresult = &Apache::lonnet::assignrole($udom,$uname,$scope,
$role,$end,$start,'',
'',$context);
}
}
return ($userresult,$authresult,$roleresult,$idresult);
}
sub propagate_id_change {
my ($uname,$udom,$user) = @_;
my (@types,@roles);
@types = ('active','future');
@roles = ('st');
my $idresult;
my %roleshash = &Apache::lonnet::get_my_roles($uname,
$udom,'userroles',\@types,\@roles);
my %args = (
one_time => 1,
);
foreach my $item (keys(%roleshash)) {
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);
my %coursehash =
&Apache::lonnet::coursedescription($cdom.'_'.$cnum,\%args);
my $cdesc = $coursehash{'description'};
if ($cdesc eq '') {
$cdesc = $cdom.'_'.$cnum;
}
if ($result eq 'ok') {
$idresult .= &mt('Classlist update for "[_1]" in "[_2]".',$uname.':'.$udom,$cdesc).'
'."\n";
} else {
$idresult .= &mt('Error: "[_1]" during classlist update for "[_2]" in "[_3]".',$result,$uname.':'.$udom,$cdesc).'
'."\n";
}
}
}
return $idresult;
}
sub update_classlist {
my ($cdom,$cnum,$udom,$uname,$user,$newend) = @_;
my ($uid,$classlistentry);
my $fullname =
&Apache::lonnet::format_name($user->{'firstname'},$user->{'middlename'},
$user->{'lastname'},$user->{'generation'},
'lastname');
my %classhash = &Apache::lonnet::get('classlist',[$uname.':'.$udom],
$cdom,$cnum);
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 == $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) {
if (defined($user->{'lastname'})) {
$classlistentry .= $fullname.':';
} else {
$classlistentry .= $classinfo[$i].':';
}
} else {
$classlistentry .= $classinfo[$i].':';
}
}
$classlistentry =~ s/:$//;
my $reply=&Apache::lonnet::cput('classlist',
{"$uname:$udom" => $classlistentry},
$cdom,$cnum);
if (($reply eq 'ok') || ($reply eq 'delayed')) {
return 'ok';
} else {
return 'error: '.$reply;
}
}
###############################################################
###############################################################
# build a role type and role selection form
sub domain_roles_select {
# Set up the role type and role selection boxes when in
# domain context
#
# 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
my %select_menus;
if ($env{'form.roletype'} eq '') {
$env{'form.roletype'} = 'domain';
}
foreach my $roletype (@roletypes) {
# set up the text for this domain
$select_menus{$roletype}->{'text'}= $lt{$roletype};
my $crstype;
if ($roletype eq 'community') {
$crstype = 'Community';
}
# we want a choice of 'default' as the default in the second menu
if ($env{'form.roletype'} ne '') {
$select_menus{$roletype}->{'default'} = $env{'form.showrole'};
} else {
$select_menus{$roletype}->{'default'} = 'Any';
}
# Now build up the other items in the second menu
my @roles;
if ($roletype eq 'domain') {
@roles = &domain_roles();
} elsif ($roletype eq 'author') {
@roles = &construction_space_roles();
} else {
my $custom = 1;
@roles = &course_roles('domain',undef,$custom,$roletype);
}
my $order = ['Any',@roles];
$select_menus{$roletype}->{'order'} = $order;
foreach my $role (@roles) {
if ($role eq 'cr') {
$select_menus{$roletype}->{'select2'}->{$role} =
&mt('Custom role');
} else {
$select_menus{$roletype}->{'select2'}->{$role} =
&Apache::lonnet::plaintext($role,$crstype);
}
}
$select_menus{$roletype}->{'select2'}->{'Any'} = &mt('Any');
}
my $result = &Apache::loncommon::linked_select_forms
('studentform',(' 'x3).&mt('Role: '),$env{'form.roletype'},
'roletype','showrole',\%select_menus,
['domain','author','course','community'],$onchangefirst,
$onchangesecond);
return $result;
}
###############################################################
###############################################################
sub hidden_input {
my ($name,$value) = @_;
return ''."\n";
}
sub print_upload_manager_header {
my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission,$crstype,
$can_assign)=@_;
my $javascript;
#
if (! exists($env{'form.upfile_associate'})) {
$env{'form.upfile_associate'} = 'forward';
}
if ($env{'form.associate'} eq 'Reverse Association') {
if ( $env{'form.upfile_associate'} ne 'reverse' ) {
$env{'form.upfile_associate'} = 'reverse';
} else {
$env{'form.upfile_associate'} = 'forward';
}
}
if ($env{'form.upfile_associate'} eq 'reverse') {
$javascript=&upload_manager_javascript_reverse_associate($can_assign);
} else {
$javascript=&upload_manager_javascript_forward_associate($can_assign);
}
#
# Deal with restored settings
my $password_choice = '';
if (exists($env{'form.ipwd_choice'}) &&
$env{'form.ipwd_choice'} ne '') {
# If a column was specified for password, assume it is for an
# internal password. This is a bug waiting to be filed (could be
# local or krb auth instead of internal) but I do not have the
# time to mess around with this now.
$password_choice = 'int';
}
#
my $groupslist;
if ($context eq 'course') {
$groupslist = &get_groupslist();
}
my $javascript_validations =
&javascript_validations('upload',$krbdefdom,$password_choice,undef,
$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" ); 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.','
').
"
' .&mt('Change authentication for existing users in domain "[_1]" to these settings?' ,$defdom) .' ' .' ' .'
'; } else { $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 .= &Apache::lonhtmlcommon::row_closure() .&Apache::lonhtmlcommon::row_title( &mt('LON-CAPA Home Server for New Users')) .&mt('LON-CAPA domain: [_1] with home server:','"'.$defdom.'"') .$home_server_pick .&Apache::lonhtmlcommon::row_closure(); } else { $Str .= $home_server_pick. &Apache::lonhtmlcommon::row_closure(); } $Str .= &Apache::lonhtmlcommon::row_title(&mt('Default domain')) .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1) .&Apache::lonhtmlcommon::row_closure(); $Str .= &Apache::lonhtmlcommon::row_title(&mt('Starting and Ending Dates')) ."\n".$date_table."
\n" .&Apache::lonhtmlcommon::row_closure(); if ($context eq 'domain') { $Str .= &Apache::lonhtmlcommon::row_title( &mt('Settings for assigning roles')) .&mt('Pick the action to take on roles for these users:').''
.''.&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 $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; if ($crstype eq 'Community') { %lt = &Apache::lonlocal::texthash ( disp => 'Display members with current/future access who are not in the uploaded file', stus => 'Members selected from this list can be dropped.' ); } else { %lt = &Apache::lonlocal::texthash ( disp => 'Display students with current/future access who are not in the uploaded file', stus => 'Students selected from this list can be dropped.' ); } $Str .= &Apache::lonhtmlcommon::row_title(&mt('Full Update')) .''. &list_submit_button(&mt('Update Display')). "\n".'
'.$warning.''."\n"); $clearcoursepick = 0; if (($env{'form.origroletype'} ne '') && ($env{'form.origroletype'} ne $env{'form.roletype'})) { $clearcoursepick = 1; } if (($env{'form.coursepick'}) && (!$clearcoursepick)) { $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,'', $showcredits); } else { ($usercount) = &show_users_list($r,$context,$env{'form.output'}, $permission,$env{'form.Status'},\%userlist, $keylist,'',$showcredits,$needauthorquota,$needauthorusage); } if (!$usercount) { $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; } # # 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') { # Create the excel spreadsheet ($excel_workbook,$excel_filename,$format) = &Apache::loncommon::create_workbook($r); return if (! defined($excel_workbook)); $excel_sheet = $excel_workbook->addworksheet('userlist'); $excel_sheet->write($row++,0,$results_description,$format->{'h2'}); # my @colnames = map {$lt{$_}} (@cols); $excel_sheet->write($row++,0,\@colnames,$format->{'bold'}); } # Done with header lines in all formats my %index; my $i; foreach my $idx (@$keylist) { $index{$idx} = $i++; } my $usercount = 0; my ($secfilter,$grpfilter); if ($context eq 'course') { $secfilter = $env{'form.secfilter'}; $grpfilter = $env{'form.grpfilter'}; if ($secfilter eq '') { $secfilter = 'all'; } if ($grpfilter eq '') { $grpfilter = 'all'; } } my %ltstatus = &Apache::lonlocal::texthash( Active => 'Active', 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})) { if ($user eq '' ) { delete($userlist->{$user}); next; } if ($context eq 'domain' && $user eq $env{'request.role.domain'}.'-domainconfig:'.$env{'request.role.domain'}) { delete($userlist->{$user}); next; } my ($uname,$udom,$role,$groups,$email); if (($statusmode ne 'Any') && ($userlist->{$user}->[$index{'status'}] ne $statusmode)) { delete($userlist->{$user}); next; } if ($context eq 'domain') { if ($env{'form.roletype'} eq 'domain') { ($role,$uname,$udom) = split(/:/,$user); if (($uname eq $env{'request.role.domain'}.'-domainconfig') && ($udom eq $env{'request.role.domain'})) { delete($userlist->{$user}); next; } } elsif ($env{'form.roletype'} eq 'author') { ($uname,$udom,$role) = split(/:/,$user,-1); } elsif (($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')) { ($uname,$udom,$role) = split(/:/,$user); } } else { ($uname,$udom,$role) = split(/:/,$user,-1); if (($context eq 'course') && $role eq '') { $role = 'st'; } } $userlist->{$user}->[$index{'role'}] = $role; if (($env{'form.showrole'} ne 'Any') && (!($env{'form.showrole'} eq 'cr' && $role =~ /^cr\//)) && ($role ne $env{'form.showrole'})) { delete($userlist->{$user}); next; } if ($context eq 'course') { my @ac_groups; if (ref($classgroups) eq 'HASH') { $groups = $classgroups->{$user}; } if (ref($groups->{'active'}) eq 'HASH') { @ac_groups = keys(%{$groups->{'active'}}); $userlist->{$user}->[$index{'groups'}] = join(', ',@ac_groups); } if ($mode ne 'autoenroll') { my $section = $userlist->{$user}->[$index{'section'}]; if (($env{'request.course.sec'} ne '') && ($section ne $env{'request.course.sec'})) { if ($role eq 'st') { delete($userlist->{$user}); next; } } if ($secfilter eq 'none') { if ($section ne '') { delete($userlist->{$user}); next; } } elsif ($secfilter ne 'all') { if ($section ne $secfilter) { delete($userlist->{$user}); next; } } if ($grpfilter eq 'none') { if (@ac_groups > 0) { delete($userlist->{$user}); next; } } elsif ($grpfilter ne 'all') { if (!grep(/^\Q$grpfilter\E$/,@ac_groups)) { delete($userlist->{$user}); next; } } if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) { if ((grep/^photo$/,@cols) && ($role eq 'st')) { $userlist->{$user}->[$index{'photo'}] = &Apache::lonnet::retrievestudentphoto($udom,$uname,'jpg'); $userlist->{$user}->[$index{'thumbnail'}] = &Apache::lonnet::retrievestudentphoto($udom,$uname, '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; my $manualcount = 0; my $lockcount = 0; my $unlockcount = 0; if ($usercount) { $r->print($output); } else { if ($mode eq 'autoenroll') { return ($usercount,$autocount,$manualcount,$lockcount,$unlockcount); } else { return; } } # # Sort the users my $index = $index{$sortby}; my $second = $index{'username'}; my $third = $index{'domain'}; 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; foreach my $user (@sorted_users) { my %in; my $sdata = $userlist->{$user}; $rowcount ++; foreach my $item (@{$keylist}) { $in{$item} = $sdata->[$index{$item}]; } my $clickers = (&Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers'))[1]; if ($clickers!~/\w/) { $clickers='-'; } $in{'clicker'} = $clickers; my $role = $in{'role'}; $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 ($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()); my $checkval; if ($mode eq 'autoenroll') { my $cellentry; if ($in{'type'} eq 'auto') { $cellentry = ''.&mt('auto').' '; $autocount ++; } else { $cellentry = ''.&mt('manual').' | |
'; $manualcount ++; if ($in{'lockedtype'}) { $cellentry .= ''; $unlockcount ++; } else { $cellentry .= ''; $lockcount ++; } $cellentry .= ' |
'.&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->rflush(); } if ($mode eq 'autoenroll') { return ($usercount,$autocount,$manualcount,$lockcount,$unlockcount); } else { return ($usercount); } } 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,$in) = @_; my $output; if ($mode eq 'autoenroll') { $output = $in->{'username'}; } else { $output = '{'username'}','$in->{'domain'}'".')">'. $in->{'username'}.''; } return $output; } sub role_type_names { my %lt = &Apache::lonlocal::texthash ( 'domain' => 'Domain Roles', 'author' => 'Co-Author Roles', 'course' => 'Course Roles', 'community' => 'Community Roles', ); return %lt; } sub select_actions { my ($context,$setting,$statusmode,$formname) = @_; my %lt = &Apache::lonlocal::texthash( revoke => "Revoke user roles", delete => "Delete user roles", reenable => "Re-enable expired user roles", activate => "Make future user roles active now", 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') { return; } if ($context eq 'course') { if ($env{'form.showrole'} ne 'Any') { 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; } } } } if ($statusmode eq 'Any') { $options .= ' '; $choices{'dates'} = 1; } else { if ($statusmode eq 'Future') { $options .= ' '; $choices{'dates'} = 1; } elsif ($statusmode eq 'Expired') { $options .= ' '; $choices{'dates'} = 1; } if ($statusmode eq 'Active' || $statusmode eq 'Future') { $options .= ' '; $choices{'dates'} = 1; } } if ($context eq 'domain') { $options .= ' '; } if (($context eq 'course') || ($context eq 'domain' && $setting eq 'course')) { if (($statusmode ne 'Expired') && ($env{'request.course.sec'} eq '')) { $options .= ' '; $choices{'sections'} = 1; } } if ($options) { $output = ''.&mt('Existing sections')."\n".
' '.$sections_select.' | '.
&mt('New section').' '."\n". ''."\n". ''."\n". ' |
'.$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", 'start' => "start date", 'end' => "end date", 'groups' => "active groups", ); my $nametitle = $lt{'sn'}; if ($crstype eq 'Community') { $nametitle = $lt{'mn'}; } if ($nosort) { $r->print(&Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row()); $r->print(<
END return; } # # Print out the initial form to get the file containing a list of users # sub print_first_users_upload_form { my ($r,$context) = @_; my $str; $str = ''; $str .= ''; $str .= ''; $str .= &Apache::grades::checkforfile_js(); $str .= '
'."\n" .&mt('Please upload an UTF8 encoded file to ensure a correct character encoding in your classlist.')."\n" .'
'."\n"; } } $str .= &Apache::loncommon::upfile_select_html() .&Apache::lonhtmlcommon::row_closure() .&Apache::lonhtmlcommon::row_title( '') .'' .&Apache::lonhtmlcommon::row_closure(1) .&Apache::lonhtmlcommon::end_pick_box(); $str .= '' .'' .'
'; $r->print($str); return; } # ================================================= Drop/Add from uploaded file sub upfile_drop_add { my ($r,$context,$permission,$showcredits) = @_; &Apache::loncommon::load_tmp_file($r); my @userdata=&Apache::loncommon::upfile_record_sep(); if($env{'form.noFirstLine'}){shift(@userdata);} my @keyfields = split(/\,/,$env{'form.keyfields'}); my %fields=(); for (my $i=0; $i<=$env{'form.nfields'}; $i++) { if ($env{'form.upfile_associate'} eq 'reverse') { if ($env{'form.f'.$i} ne 'none') { $fields{$keyfields[$i]}=$env{'form.f'.$i}; } } else { $fields{$env{'form.f'.$i}}=$keyfields[$i]; } } if ($env{'form.fullup'} ne 'yes') { $r->print(''."\n"); } elsif (ref($classlist) eq 'HASH') { # Remove the students we just added from the list of students. foreach my $line (@userdata) { my %entries=&Apache::loncommon::record_sep($line); unless (($entries{$fields{'username'}} eq '') || (!defined($entries{$fields{'username'}}))) { delete($classlist->{$entries{$fields{'username'}}. ':'.$domain}); } } # Print out list of dropped students. &show_drop_list($r,$classlist,'nosort',$permission); } } } # end of unless if ($env{'form.fullup'} ne 'yes') { $r->print(''); } } sub print_namespacing_alerts { my ($domain,$alerts,$curr_rules) = @_; my $output; if (ref($alerts) eq 'HASH') { if (keys(%{$alerts}) > 0) { if (ref($alerts->{'username'}) eq 'HASH') { foreach my $dom (sort(keys(%{$alerts->{'username'}}))) { my $count; if (ref($alerts->{'username'}{$dom}) eq 'HASH') { $count = keys(%{$alerts->{'username'}{$dom}}); } my $domdesc = &Apache::lonnet::domain($domain,'description'); if (ref($curr_rules->{$dom}) eq 'HASH') { $output .= &Apache::loncommon::instrule_disallow_msg( 'username',$domdesc,$count,'upload'); } $output .= &Apache::loncommon::user_rule_formats($dom, $domdesc,$curr_rules->{$dom}{'username'}, 'username'); } } if (ref($alerts->{'id'}) eq 'HASH') { foreach my $dom (sort(keys(%{$alerts->{'id'}}))) { my $count; if (ref($alerts->{'id'}{$dom}) eq 'HASH') { $count = keys(%{$alerts->{'id'}{$dom}}); } my $domdesc = &Apache::lonnet::domain($domain,'description'); if (ref($curr_rules->{$dom}) eq 'HASH') { $output .= &Apache::loncommon::instrule_disallow_msg( 'id',$domdesc,$count,'upload'); } $output .= &Apache::loncommon::user_rule_formats($dom, $domdesc,$curr_rules->{$dom}{'id'},'id'); } } } } } sub user_change_result { my ($r,$userresult,$authresult,$roleresult,$idresult,$counts,$flushc, $username,$userdomain,$userchg) = @_; my $okresult = 0; if ($userresult ne 'ok') { if ($userresult =~ /^error:(.+)$/) { my $error = $1; $r->print('