--- loncom/enrollment/Enrollment.pm 2006/02/08 23:47:26 1.31 +++ loncom/enrollment/Enrollment.pm 2021/09/08 12:13:13 1.55 @@ -1,5 +1,5 @@ # Automated Enrollment manager -# $Id: Enrollment.pm,v 1.31 2006/02/08 23:47:26 raeburn Exp $ +# $Id: Enrollment.pm,v 1.55 2021/09/08 12:13:13 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -27,17 +27,22 @@ package LONCAPA::Enrollment; use Apache::loncoursedata; use Apache::lonnet; +use Apache::loncommon(); use Apache::lonmsg; use Apache::lonlocal; use HTML::Entities; +use HTML::Parser; use LONCAPA::Configuration; +use Math::Random; use Time::Local; use lib '/home/httpd/lib/perl'; use strict; sub update_LC { - my ($dom,$crs,$adds,$drops,$startdate,$enddate,$authtype,$autharg,$classesref,$groupref,$logmsg,$newusermsg,$context,$phototypes) = @_; + my ($dom,$crs,$adds,$drops,$startdate,$enddate,$authtype,$autharg, + $showcredits,$defaultcredits,$autofailsafe,$classesref,$groupref, + $logmsg,$newusermsg,$context,$phototypes) = @_; # Get institutional code and title of this class my %courseinfo = (); &get_courseinfo($dom,$crs,\%courseinfo); @@ -52,11 +57,14 @@ sub update_LC { my $status=&Apache::loncoursedata::CL_STATUS; my $type=&Apache::loncoursedata::CL_TYPE; my $lockedtype=&Apache::loncoursedata::CL_LOCKEDTYPE; + my $credidx=&Apache::loncoursedata::CL_CREDITS; + my $instidx = &Apache::loncoursedata::CL_INSTSEC; my @localstudents = (); my @futurestudents = (); my @activestudents = (); my @excludedstudents = (); my $currlist; + my $now = time; foreach my $uname (keys %{$roster} ) { if ($uname =~ m/^(.+):$dom$/) { if ($$roster{$uname}[$status] eq "Active") { @@ -91,9 +99,17 @@ sub update_LC { open(FILE,"<$$configvars{'lonTabDir'}.'/rolesplain.tab"); my @rolesplain = ; close(FILE); - foreach (@rolesplain) { - if ($_ =~ /^(st|ta|ex|ad|in|cc):([\w\s]+)$/) { - $longroles{$1} = $2; + foreach my $item (@rolesplain) { + if ($_ =~ /^(st|ta|ex|ad|in|cc|co):([\w\s]+):?([\w\s]*)/) { + if ($courseinfo{'type'} eq 'Community') { + unless($1 eq 'cc') { + $longroles{$1} = $3; + } + } else { + unless($1 eq 'co') { + $longroles{$1} = $2; + } + } } } @@ -114,23 +130,14 @@ sub update_LC { # Get latest institutional enrollment for this class. my %allenrolled = (); my @reg_students = (); - my %place = (); - $place{'autharg'} = &CL_autharg(); - $place{'authtype'} = &CL_authtype(); - $place{'email'} = &CL_email(); - $place{'enddate'} = &CL_enddate(); - $place{'firstname'} = &CL_firstname(); - $place{'generation'} = &CL_generation(); - $place{'groupID'} = &CL_groupID(); - $place{'lastname'} = &CL_lastname(); - $place{'middlename'} = &CL_middlename(); - $place{'startdate'} = &CL_startdate(); - $place{'studentID'} = &CL_studentID(); + my %place = &place_hash(); my %ucount = (); my %enrollinfo = (); + my %classcount; foreach my $class (@{$classesref}) { my %enrolled = (); &parse_classlist($$configvars{'lonDaemons'},$dom,$crs,$class,\%place,$$groupref{$class},\%enrolled); + $classcount{$class} = scalar(keys(%enrolled)); foreach my $uname (sort keys %enrolled ) { if (!grep/^$uname$/,@reg_students) { push @reg_students,$uname; @@ -146,7 +153,7 @@ sub update_LC { my @okusers = (); foreach my $uname (@reg_students) { if (grep/^$uname$/,@excludedstudents) { - $$logmsg .= "No re-enrollment for $uname - user was previously manually unenrolled and locked.".$linefeed; + $$logmsg .= &mt('No re-enrollment for [_1] - user was previously manually unenrolled and locked.',$uname).$linefeed; } elsif (@{$allenrolled{$uname}} > 1) { my @sections = (); my $saved; @@ -169,19 +176,19 @@ sub update_LC { push @okusers, $uname; } elsif (@sections > 1) { - $$logmsg .= "$uname appears in classlists for more than one section of this course, i.e. in sections: "; + $$logmsg .= &mt('[_1] appears in classlists for more than one section of this course, i.e. in sections: ',$uname); foreach (@sections) { $$logmsg .= " $_,"; } chop($$logmsg); - $$logmsg .= ". Because of this ambiguity, no enrollment action was taken for this student.".$linefeed; + $$logmsg .= '. '.&mt('Because of this ambiguity, no enrollment action was taken for this student.').$linefeed; } } else { @{$enrollinfo{$uname}} = @{$allenrolled{$uname}[0]}; push @okusers, $uname; } } -# Get mapping of student IDs to usernames for users in institutional data for this class +# Get mapping of student/employee IDs to usernames for users in institutional data for this class my @allINids = (); my %unameFromINid = (); foreach my $uname (@okusers) { @@ -195,9 +202,11 @@ sub update_LC { } } -# Explicitly allow access to creation/modification of students if called as an automated process. +# Explicitly allow access to creation/modification of students and group membership changes +# when called as an automated process. if ($context eq 'automated') { $env{'allowed.cst'}='F'; + $env{'allowed.mdg'}='F'; } # Compare IDs with existing LON-CAPA enrollment for this class @@ -205,47 +214,71 @@ sub update_LC { unless ($uname eq '') { my %uidhash=&Apache::lonnet::idrget($dom,$uname); my @stuinfo = @{$enrollinfo{$uname}}; - my $access = ''; + my ($access,$added,$inststatus,$instsec); + my $credits; + if ($showcredits) { + $credits = $stuinfo[$place{'credits'}]; + $credits =~ s/[^\d\.]//g; + if ($credits eq $defaultcredits) { + undef($credits); + } + } + $inststatus = $stuinfo[$place{inststatus}]; + $instsec = $stuinfo[$place{instsec}]; if (grep/^$uname$/,@localstudents) { # Check for studentID changes if ( ($uidhash{$uname}) && ($uidhash{$uname} !~ /error\:/) ) { unless ( ($uidhash{$uname}) eq ($stuinfo[ $place{studentID} ]) ) { - $$logmsg .= "Change in ID for $uname. StudentID in LON-CAPA system is $uidhash{$uname}; StudentID in institutional data is $stuinfo[ $place{studentID} ]".$linefeed; + $$logmsg .= &mt('Change in ID for [_1]. StudentID in LON-CAPA system is [_2]; StudentID in institutional data is [_3].',$uname,$uidhash{$uname},$stuinfo[ $place{studentID} ]).$linefeed; } } # Check for switch from manual to auto unless (($$currlist{$uname}[$type] eq "auto") || ($$currlist{$uname}[$lockedtype] eq "1") || (!$adds) ) { # drop manually added student - my $drop_reply = &Apache::lonnet::modifystudent($dom,$uname,'','','',undef,undef,undef,undef,$$currlist{$uname}[$sec],time,undef,undef,undef,undef,'auto','',$cid); + my $drop_reply = &Apache::lonnet::modifystudent($dom,$uname,'','','',undef,undef,undef,undef,$$currlist{$uname}[$sec],time,undef,undef,undef,undef,'auto','',$cid,'',$context); # re-enroll as auto student if ($drop_reply !~ /^ok/) { - $$logmsg .= "An error occured during the attempt to convert $uname from a manual type to an auto type student - $drop_reply.".$linefeed; + $$logmsg .= &mt('An error occurred during the attempt to convert [_1] from a manual type to an auto type student - [_2].',$uname,$drop_reply).$linefeed; } else { # re-enroll as auto student my ($auth,$authparam,$first,$middle,$last,$gene,$usec,$end,$start,$emailaddr,$pid,$emailenc); &prepare_add($authtype,$autharg,$enddate,$startdate,\@stuinfo,\%place,\$dom,\$uname,\$auth,\$authparam,\$first,\$middle,\$last,\$gene,\$usec,\$end,\$start,\$emailaddr,\$pid,\$emailenc); if ($$currlist{$uname}[$sec] ne $usec) { - $switchresult .= "Section for $uname switched from $$currlist{$uname}[$sec] to ".$usec.$linefeed; + my $showoldsec = $$currlist{$uname}[$sec]; + if ($$currlist{$uname}[$sec] eq '') { + $showoldsec = &mt('none'); + } + my $showsec = $usec; + if ($usec eq '') { + $showsec = &mt('none'); + } + $switchresult .= &mt('Section for [_1] switched from [_2] to [_3].',$uname,$showoldsec,$showsec).$linefeed; if ($context eq 'automated') { - $$logmsg .= "Section switch for $uname from $$currlist{$uname}[$sec] to ".$usec.$linefeed; ; + $$logmsg .= &mt('Section switch for [_1] from [_2] to [_3].',$uname,$showoldsec,$usec).$linefeed; } $switchcount ++; } - &execute_add($context,'switchtype',$uname,$dom,$auth,$authparam,$first,$middle,$last,$gene,$pid,$usec,$end,$start,$emailenc,$cid,\$addresult,\$enrollcount,$linefeed,$logmsg); + &execute_add($context,'switchtype',$uname,$dom,$auth, + $authparam,$first,$middle,$last,$gene, + $pid,$usec,$end,$start,$emailenc, + $credits,$instsec,$cid,\$addresult,\$enrollcount, + $linefeed,$logmsg); + $added = 1; } - } + } # Check for section changes if ($$currlist{$uname}[$sec] eq $stuinfo[ $place{groupID} ]) { # Check for access date changes for students with access starting in the future. if ( (grep/^$uname$/,@futurestudents) && ($$currlist{$uname}[$type] eq "auto") && ($adds == 1) ) { my $datechange = &datechange_check($$currlist{$uname}[$cstart],$$currlist{$uname}[$cend],$startdate,$enddate); if ($datechange) { - my $modify_access_result = &Apache::lonnet::modify_student_enrollment($dom,$uname,undef,undef,undef,undef,undef,$stuinfo[ $place{groupID} ],$enddate,$startdate,'auto','',$cid); + my $modify_access_result = &Apache::lonnet::modify_student_enrollment($dom,$uname,undef,undef,undef,undef,undef,$stuinfo[ $place{groupID} ],$enddate,$startdate,'auto','',$cid,'',$context,$credits,$instsec); $access = &showaccess($enddate,$startdate); if ($modify_access_result =~ /^ok/) { - $$logmsg .= "Change in access dates for $uname.".$access.$linefeed; + $$logmsg .= &mt('Change in access dates for [_1].',$uname).$access.$linefeed; + $added = 1; } else { - $$logmsg .= "Error when attempting to change start and/or end access dates for $uname in section: ".$stuinfo[ $place{groupID} ]." -error $modify_access_result".$linefeed; + $$logmsg .= &mt('Error when attempting to change start and/or end access dates for [_1] in section: [_2] -error [_3].',$uname,$stuinfo[$place{groupID}],$modify_access_result).$linefeed; } } } @@ -258,47 +291,74 @@ sub update_LC { if ($$currlist{$uname}[$sec]) { $uurl.='/'.$$currlist{$uname}[$sec]; } - my $expire_role_result = &Apache::lonnet::assignrole($dom,$uname,$uurl,'st',$expiretime); + my $expire_role_result = &Apache::lonnet::assignrole($dom,$uname,$uurl,'st',$expiretime,'','','',$context); if ($expire_role_result eq 'ok') { my $modify_section_result; if (grep/^$uname$/,@activestudents) { - $modify_section_result = &Apache::lonnet::modify_student_enrollment($dom,$uname,undef,undef,undef,undef,undef,$stuinfo[ $place{groupID} ],$$currlist{$uname}[$cend],$$currlist{$uname}[$cstart],'auto','',$cid); + $modify_section_result = &Apache::lonnet::modify_student_enrollment($dom,$uname,undef,undef,undef,undef,undef,$stuinfo[ $place{groupID} ],$$currlist{$uname}[$cend],$$currlist{$uname}[$cstart],'auto','',$cid,'',$context,$credits,$instsec); } else { - $modify_section_result = &Apache::lonnet::modify_student_enrollment($dom,$uname,undef,undef,undef,undef,undef,$stuinfo[ $place{groupID} ],$enddate,$startdate,'auto','',$cid); + $modify_section_result = &Apache::lonnet::modify_student_enrollment($dom,$uname,undef,undef,undef,undef,undef,$stuinfo[ $place{groupID} ],$enddate,$startdate,'auto','',$cid,'',$context,$credits,$instsec); $access = &showaccess($enddate,$startdate); } if ($modify_section_result =~ /^ok/) { - $switchresult .= "Section for $uname switched from old section: ".$$currlist{$uname}[$sec] ." to new section: ".$stuinfo[ $place{groupID} ].".".$access.$linefeed; + $switchresult .= &mt('Section for [_1] switched from old section: [_2] to new section: [_3].',$uname,$$currlist{$uname}[$sec],$stuinfo[ $place{groupID} ]).$access.$linefeed; + $added = 1; if ($context eq 'automated') { - $$logmsg .= "Section switch for $uname from $$currlist{$uname}[$sec] to $stuinfo[ $place{groupID} ]".$linefeed; + $$logmsg .= &mt('Section switch for [_1] from [_2] to [_3].',$uname,$$currlist{$uname}[$sec],$stuinfo[ $place{groupID} ]).$linefeed; } $switchcount ++; } else { - $$logmsg .= "Error when attempting section change for $uname from old section ".$$currlist{$uname}[$sec]." to new section: ".$stuinfo[ $place{groupID} ]." -error: $modify_section_result".$linefeed; + $$logmsg .= &mt("Error when attempting section change for [_1], from old section: '[_2]' to new section: '[_3]' -error: [_4]",$uname,$$currlist{$uname}[$sec],$stuinfo[ $place{groupID} ],$modify_section_result).$linefeed; } } else { - $$logmsg .= "Error when attempting to expire role for $uname in old section" .$$currlist{$uname}[$sec]." -error: $expire_role_result".$linefeed; + $$logmsg .= &mt("Error when attempting to expire role for [_1] in old section: '[_2]' -error: '[_3]'.",$uname,$$currlist{$uname}[$sec],$expire_role_result).$linefeed; } } } +# Check for credits changes + if (($showcredits) && + ($$currlist{$uname}[$credidx] ne $credits) && (!$added)) { + my $modify_credits_result = + &Apache::lonnet::modify_student_enrollment($dom,$uname,undef,undef,undef,undef,undef,$stuinfo[ $place{groupID} ],$enddate,$startdate,'auto','',$cid,'',$context,$credits,$instsec); + if ($modify_credits_result =~ /^ok/) { + if ($credits ne '') { + $$logmsg .= &mt('Credits change for [_1] from [_2] to [_3].',$uname,$$currlist{$uname}[$credidx],$credits).$linefeed; + } else { + $$logmsg .= &mt('Credits change for [_1] from [_2] to course default [_3].',$uname,$$currlist{$uname}[$credidx],$defaultcredits).$linefeed; + } + } else { + $$logmsg .= &mt('Error when attempting to change credits for [_1] in section: [_2] -error [_3].',$uname,$stuinfo[$place{groupID}],$modify_credits_result).$linefeed; + } + } +# Check for institutional section change + if (($$currlist{$uname}[$instidx] ne $instsec) && (!$added) && ($$currlist{$uname}[$type] eq "auto")) { + my $modify_instsec_result = + &Apache::lonnet::modify_student_enrollment($dom,$uname,undef,undef,undef,undef,undef,$stuinfo[ $place{groupID} ],$enddate,$startdate,'auto','',$cid,'',$context,$credits,$instsec); + if ($modify_instsec_result =~ /^ok/) { + $$logmsg .= &mt('Institutional section change for [_1] from [_2] to [_3].',$uname,$$currlist{$uname}[$instidx],$instsec).$linefeed; + } else { + $$logmsg .= &mt('Error when attempting to change institutional section for [_1] in section: [_2] -error [_3].',$uname,$stuinfo[$place{groupID}],$modify_instsec_result).$linefeed; + } + } } else { # Check for changed usernames by checking studentIDs if ( ($stuinfo[ $place{studentID} ] ne '') && (grep/^$stuinfo[ $place{studentID} ]$/,@LCids) ) { foreach my $match ( @{ $unameFromLCid{ $stuinfo[ $place{studentID} ] } } ) { - $$logmsg .= "A possible change in username has been detected for a student enrolled in this course. The existing LON-CAPA classlist contains user: $match and student ID: ".$stuinfo[ $place{studentID} ].". "; + $$logmsg .= &mt('A possible change in username has been detected for a student enrolled in this course.').' '.&mt('The existing LON-CAPA classlist contains user: [_1] and student/employee ID: [_2].',$match,$stuinfo[ $place{studentID} ]); if (grep/^$match$/,@okusers) { - $$logmsg .= "The username $match remains in the institutional classlist, but the same student ID is used for new user: $uname now found in the institutional classlist. You may need to contact your Domain Coordinator to determine how to reolve this issue and whether to move student data files for user: $match to $uname. "; + $$logmsg .= &mt('The username [_1] remains in the institutional classlist, but the same student/employee ID is used for new user: [_2] now found in the institutional classlist.',$match,$uname).' '.&mt('You may need to contact your Domain Coordinator to determine how to resolve this issue and whether to move student data files for user: [_1] to [_2].',$match,$uname).' '; } else { unless ($drops == 1) { - $$logmsg .= "This username - $match - has been dropped from the institutional classlist, but the student ID of this user is also used by $uname who now appears in the institutional classlist. You may need to contact your Domain Coordinator to request a move of the student data files for user: $match to $uname. "; + $$logmsg .= &mt('This username - [_1] - has been dropped from the institutional classlist, but the student/employee ID of this user is also used by [_2] who now appears in the institutional classlist.',$match,$uname).' '.&mt('You may need to contact your Domain Coordinator to request a move of the student data files for user: [_1] to [_2].',$match,$uname).' '; } } - $$logmsg .= "Because of this student ID conflict, the new username - $uname - has not been added to the LON-CAPA classlist.".$linefeed; + $$logmsg .= &mt('Because of this student/employee ID conflict, the new username - [_1] - has not been added to the LON-CAPA classlist',$uname).$linefeed; } } elsif ($adds == 1) { - my ($auth,$authparam,$first,$middle,$last,$gene,$usec,$end,$start,$emailaddr,$pid,$emailenc); + my ($auth,$authparam,$first,$middle,$last,$gene,$usec,$end,$start,$emailaddr,$pid,$emailenc,$credithours); &prepare_add($authtype,$autharg,$enddate,$startdate,\@stuinfo,\%place,\$dom,\$uname,\$auth,\$authparam,\$first,\$middle,\$last,\$gene,\$usec,\$end,\$start,\$emailaddr,\$pid,\$emailenc); # Check for existing account in this LON-CAPA domain for this username + next if (($end) && ($end < $now)); my $uhome=&Apache::lonnet::homeserver($uname,$dom); if ($uhome eq 'no_host') { # User does not exist my $args = {'auth' => $auth, @@ -320,11 +380,20 @@ sub update_LC { 'cdom' => $dom, 'context' => $context, 'linefeed' => $linefeed, - 'role' => 'st' + 'inststatus' => $inststatus, + 'instsec' => $instsec, + 'role' => 'st', }; - my $outcome = &create_newuser($args,$logmsg,$newusermsg,\$enrollcount,\$addresult,\%longroles,\%courseinfo); + if ($credits) { + $args->{'credits'} = $credits; + } + my $outcome = &create_newuser($args,$logmsg,$newusermsg,\$enrollcount,\$addresult,\%longroles,\%courseinfo,$context); } else { - &execute_add($context,'newstudent',$uname,$dom,$auth,$authparam,$first,$middle,$last,$gene,$pid,$usec,$end,$start,$emailenc,$cid,\$addresult,\$enrollcount,$linefeed,$logmsg); + &execute_add($context,'newstudent',$uname,$dom,$auth, + $authparam,$first,$middle,$last,$gene,$pid, + $usec,$end,$start,$emailenc,$credits,$instsec, + $cid,\$addresult,\$enrollcount,$linefeed, + $logmsg); } if ($courseinfo{'showphoto'}) { my ($result,$resulttype) = @@ -348,7 +417,7 @@ sub update_LC { &mt('For [_1] students, photos ',$numphoto). $lt{$type}.'