Annotation of loncom/enrollment/Enrollment.pm, revision 1.2

1.1       raeburn     1: package LONCAPA::Enrollment;
                      2: 
                      3: use Apache::loncoursedata;
                      4: use Apache::lonnet;
                      5: use HTML::Entities;
                      6: use XML::Simple;
                      7: use LONCAPA::Configuration;
                      8: 
                      9: use strict;
                     10: 
                     11: sub update_LC {
                     12:     my ($dom,$crs,$adds,$drops,$startdate,$enddate,$authtype,$autharg,$classesref,$groupref,$logmsg,$context) = @_; 
                     13: # Get current LON-CAPA student enrollment for this class
                     14:     my $configvars = &LONCAPA::Configuration::read_conf('loncapa.conf');
                     15:     my $cid = $dom."_".$crs;
                     16:     my $roster = &Apache::loncoursedata::get_classlist($cid,$dom,$crs);
                     17:     my $cend = &Apache::loncoursedata::CL_END;
                     18:     my $cstart = &Apache::loncoursedata::CL_START; 
                     19:     my $stuid=&Apache::loncoursedata::CL_ID;
                     20:     my $sec=&Apache::loncoursedata::CL_SECTION;
                     21:     my $status=&Apache::loncoursedata::CL_STATUS;
                     22:     my $type=&Apache::loncoursedata::CL_TYPE;
                     23:     my @localstudents = ();
                     24:     my $currlist;
                     25:     foreach my $uname (keys %{$roster} ) {
                     26:         if ($uname =~ m/^(.+):$dom$/) {
                     27:             if ($$roster{$uname}[$status] eq "Active") {
                     28:                 push @localstudents, $1;
                     29:                 @{$$currlist{$1}} = @{$$roster{$uname}};
                     30:             }
                     31:         }
                     32:     }
                     33:     my $linefeed = '';
                     34:     my $addresult = '';
                     35:     my $dropresult = '';
                     36:     if ($context eq "updatenow") {
                     37:         $linefeed = "</li>\n<li>"; 
                     38:     } elsif ($context eq "automated") {
                     39:         $linefeed = "\n";
                     40:     }
                     41:     my $enrollcount = 0;
                     42:     my $dropcount = 0;
                     43: 
                     44: # Get mapping of IDs to usernames for current LON-CAPA student enrollment for this class 
                     45:     my @LCids = ();
                     46:     my %unameFromLCid = ();
                     47:     foreach my $uname (sort keys %{$currlist}) {
                     48:         my $stuID = $$currlist{$uname}[$stuid];
                     49:         if (!grep/^$stuID$/,@LCids) {
                     50:             push @LCids, $stuID;
                     51:             @{$unameFromLCid{$stuID}} = ();
                     52:         }
                     53:         push @{$unameFromLCid{$stuID}},$uname;
                     54:     }
                     55:  
                     56: # Get latest institutional enrollment for this class.
                     57:     my %allenrolled = ();
                     58:     my @reg_students = ();
                     59:     my %place = ();
                     60:     $place{'autharg'} = &CL_autharg();
                     61:     $place{'authtype'} = &CL_authtype();
                     62:     $place{'email'} = &CL_email();
                     63:     $place{'enddate'} = &CL_enddate();
                     64:     $place{'firstname'} = &CL_firstname();
                     65:     $place{'generation'} = &CL_generation();
                     66:     $place{'groupID'} = &CL_groupID();
                     67:     $place{'lastname'} = &CL_lastname();
                     68:     $place{'middlename'} = &CL_middlename();
                     69:     $place{'startdate'} = &CL_startdate();
                     70:     $place{'studentID'} = &CL_studentID();
                     71:     my %ucount = ();
                     72:     my %enrollinfo = ();
                     73:     foreach my $class (@{$classesref}) {
                     74:         my %enrolled = ();
                     75:         &parse_classlist($$configvars{'lonDaemons'},$dom,$crs,$class,\%place,$$groupref{$class},\%enrolled);
                     76:         foreach my $uname (sort keys %enrolled ) {
                     77:             if (!grep/^$uname$/,@reg_students) {
                     78:                 push @reg_students,$uname;
                     79:                 $ucount{$uname} = 0;
                     80:                 @{$allenrolled{$uname}} = ();
                     81:             }
                     82:             @{$allenrolled{$uname}[$ucount{$uname}]} = @{$enrolled{$uname}};
                     83:             $ucount{$uname} ++;
                     84:         }
                     85:     }
                     86: 
                     87: # Check for multiple sections for a single student 
                     88:     my @okusers = ();
                     89:     foreach my $uname (@reg_students)  {
                     90:         if (@{$allenrolled{$uname}} > 1) {
                     91:             my @sections = ();
                     92:             my $saved;
                     93:             for (my $i=0; $i<@{$allenrolled{$uname}}; $i++) {
                     94:                 my @stuinfo = @{$allenrolled{$uname}[$i]};
                     95:                 my $secnum = $stuinfo[ $place{'groupID'} ];
                     96:                 unless ($secnum eq '') {
                     97:                     unless (grep/^$secnum$/,@sections) {
                     98:                         $saved = $i; 
                     99:                         push @sections,$secnum;
                    100:                     }
                    101:                 }
                    102:             }
                    103:             if (@sections == 0) {
                    104:                 @{$enrollinfo{$uname}} = @{$allenrolled{$uname}[0]};
                    105:                 push @okusers, $uname;
                    106:             }
                    107:             elsif (@sections == 1) {
                    108:                 @{$enrollinfo{$uname}} = @{$allenrolled{$uname}[$saved]};
                    109:                 push @okusers, $uname;
                    110:             }
                    111:             elsif (@sections > 1) {
                    112:                 $logmsg =  "$uname appears in classlists for multiple sections of $crs -";
                    113:                 foreach (@sections) {
                    114:                     $logmsg .= " $_,";
                    115:                 }
                    116:                 chop($logmsg);
                    117:                 $logmsg .= " No automated enrollment action taken for this student.\n";
                    118:             }
                    119:         } else {
                    120:             @{$enrollinfo{$uname}} = @{$allenrolled{$uname}[0]};
                    121:             push @okusers, $uname;
                    122:         }
                    123:     }
                    124: # Get mapping of student IDs to usernames for users in institutional data for this class  
                    125:     my @allINids = ();
                    126:     foreach my $uname (@okusers) {
                    127:         $enrollinfo{$uname}[ $place{'studentID'} ] =~ tr/A-Z/a-z/;
                    128:         my $stuID = $enrollinfo{$uname}[ $place{'studentID'} ];
                    129:         if (grep/^$stuID$/,@allINids)  {
                    130:             push @{$unameFromINid{$stuID}},$uname;
                    131:         } else {
                    132:             push @allINids, $stuID;
                    133:             @{$unameFromINid{$stuID}} = $uname; 
                    134:         }
                    135:     }
                    136: # Compare IDs with existing LON-CAPA enrollment for this class
                    137:     foreach my $uname (@okusers) {
                    138:         my %uidhash=&Apache::lonnet::idrget($dom,$uname);
                    139:         my @stuinfo = @{$enrollinfo{$uname}};
                    140:         if (grep/^$uname$/,@localstudents) {
                    141: # Check for studentID changes
                    142:             if ( ($uidhash{$uname}) && ($uidhash{$uname} !~ /error\:/) )  {
                    143:                 unless ( ($uidhash{$uname}) eq ($stuinfo[ $place{studentID} ]) ) {
                    144:                     $logmsg .= "Change in ID for $uname in class: $crs. StudentID in LON-CAPA system is $uidhash{$uname}, StudentID in institutional data is $stuinfo[ $place{studentID} ]\n"; 
                    145:                 }
                    146:             }
                    147: 
                    148: # Check for section changes
                    149:             unless ($$currlist{$uname}[$sec] eq $stuinfo[ $place{groupID} ]) {
                    150:                 $logmsg .= "Found a section difference for $uname - ".$$currlist{$uname}[$sec] ."versus ".$stuinfo[ $place{groupID} ]." in class $crs\n";
                    151:                 if ($$currlist{$uname}[$type] eq "auto") {
                    152:                     my $modify_section_result = &Apache::lonnet::modifystudent($dom,$uname,'','','',undef,undef,undef,undef,$$currlist{$uname}[$sec],$nowtime,undef,undef,undef,undef,'auto',$cid);
                    153:                     if ($modify_section_result !~ /^ok/) {
                    154:                         $logmsg .= "An error occured during the attempt to expire the $uname from the old section $$currlist{$uname}[$sec] - $modify_section_result\n";
                    155:                     }
                    156: 
                    157: # Assign the role of student in the new section
                    158:                     my $uurl='/'.$cid;
                    159:                     $uurl=~s/\_/\//g;
                    160:                     if ($stuinfo[ $place{groupID} ]) {
                    161:                         $uurl.='/'.$stuinfo[ $place{groupID} ];
                    162:                     }
                    163:                     my $newend = $stuinfo[ $place{enddate} ];
1.2     ! albertel  164:                     my $newstart = $stuinfo[ $place{startdate} ];
1.1       raeburn   165:                     if ($newend eq '') {
                    166:                         $end = $enddate;
                    167:                     }
                    168:                     if ($newstart eq '') {
                    169:                         $start = $startdate;
                    170:                     }
                    171:                     &Apache::lonnet::assignrole($dom,$uname,$uurl,"st",$newend,$newstart); 
                    172:                 }
                    173:             }
                    174:         }
                    175:         elsif ($uname ne '') {
                    176: # Check for changed usernames by checking studentIDs
                    177:             if ( ($stuinfo[ $place{studentID} ] ne '') && (grep/^$stuinfo[ $place{studentID} ]$/,@LCids) ) {
                    178:                 if (grep/^$$currlist{$uname}[ $place{'studentID'} ]$/,@allINids) {
                    179:                     foreach my $match ( @{ $unameFromLCid{ $stuinfo[ $place{studentID} ] } }  ) {
                    180:                         if (grep/^$match$/,@okusers) {
                    181:                             $logmsg .= "A possible change in username has been detected for a student enrolled in $crs. The existing LON-CAPA classlist contains user: $uname and student ID: ".$$currlist{$uname}[ $place{studentID} ].".  This username has been dropped from the institutional classlist, but the same student ID is used for user: $match who still appears in the institutional classlist. You may need to move the student data files for user: $uname to $match\n";
                    182:                         }
                    183:                     }
                    184:                 }
                    185:             } elsif ($adds == 1) {
                    186: # Add student to LON-CAPA classlist
                    187:                 my $auth = $stuinfo[ $place{'authtype'} ];
                    188:                 my $authparam = $stuinfo[ $place{'autharg'} ];
                    189:                 my $first = $stuinfo[ $place{'firstname'} ];
                    190:                 my $middle = $stuinfo[ $place{'middlename'} ];
                    191:                 my $last = $stuinfo[ $place{'lastname'} ];
                    192:                 my $gene = $stuinfo[ $place{'generation'} ];
                    193:                 my $usec = $stuinfo[ $place{'groupID'} ];
                    194:                 my $end = $stuinfo[ $place{'enddate'} ];
                    195:                 my $start = $stuinfo[ $place{'startdate'} ];
                    196:                 my $emailaddr = $stuinfo[ $place{'email'} ];
                    197:                 my $pid = $stuinfo[ $place{'studentID'} ];
                    198: 
                    199: # remove non alphanumeric values from section
                    200:                 $usec =~ s/\W//g;
                    201: 
                    202:                 unless ($emailaddr =~/^[^\@]+\@[^\@]+$/) { $emailaddr =''; }
                    203:                 my $emailenc = &HTML::Entities::encode($emailaddr); 
                    204: 
                    205: # Use course defaults where entry is absent
                    206:                 if ($auth eq '') {
                    207:                     $auth =  $authtype;
                    208:                 }
                    209:                 if ($authparam eq '') {
                    210:                     $authparam = $autharg;
                    211:                 }
                    212:                 if ($end eq '') {
                    213:                     $end = $enddate;
                    214:                 }
                    215:                 if ($start eq '') {
                    216:                     $start = $startdate;
                    217:                 }
                    218: # Clean up whitespace
                    219:                 foreach (\$dom,\$uname,\$pid,\$first,\$middle,\$last,\$gene,\$usec) {
                    220:                     $$_ =~ s/(\s+$|^\s+)//g;
                    221:                 }
                    222: 
                    223: # Check for existing account in this LON-CAPA domain for this username
                    224:                 my $uhome=&Apache::lonnet::homeserver($uname,$dom);
                    225:                 if ($uhome eq 'no_host') { # User does not exist
                    226:                     $create_passwd = 0;
                    227:                     if ($passwd eq '') {
                    228: # If no account exists and passwords should be generated
                    229:                         if (($authtype eq "int") || ($authtype eq "loc")) {
                    230:                             ($passwd,$create_passwd) = &create_password($authtype); }
                    231:                         } elsif ($authtype =~ m/^krb/) {
                    232:                             $passwd = $autharg;
                    233:                         } else {
                    234:                             $logmsg .= "Invalid authentication type for $uname in $crs\n";
                    235:                         }  
                    236:                     }
                    237: # Now create user.
                    238:                     my $reply=&Apache::lonnet::modifystudent($dom,$uname,$pid,$auth,$authparam,$first,$middle,$last,$gene,$usec,$end,$start,'',undef,$emailaddr,'auto',$cid);
                    239:                     if ($reply eq 'ok') {
                    240:                         $enrollcount ++;
                    241:                         $addresult .= "$first $last ($pid) - $uname enrolled in section/group $usec.".$linefeed;
                    242:                         $logmsg .= "New user $uname added successfully. ";
                    243:                         unless ($emailenc eq '') {
                    244:                             my %emailHash;
                    245:                             $emailHash{'critnotification'}  = $emailenc;
                    246:                             $emailHash{'notification'} = $emailenc;
                    247:                             my $putresult = &Apache::lonnet::put('environment',\%emailHash,$dom,$uname);
                    248:                         }
                    249:                         if ($create_passwd) {
                    250: # Send e-mail with inital password to new user at $emailaddr
                    251:                             $logmsg .= "Initial password -  - sent to $emailaddr\n";
                    252:                         } else {
                    253:                             $logmsg .= "\n";
                    254:                         }
                    255:                     } else {
                    256:                        $logmsg .= "An error occurred adding new user $uname - $reply\n";
                    257:                     }
                    258:                 } else {
                    259: # Get the user's information and authentication
                    260:                     my %userenv = &Apache::lonnet::get('environment',['firstname','middlename','lastname','generation','id','critnotification','notification'],$dom,$uname);
                    261:                     my ($tmp) = keys(%userenv);
                    262:                     if ($tmp =~ /^(con_lost|error)/i) {
                    263:                         %userenv = ();
                    264:                     }
                    265: # Get the user's e-mail address
                    266:                     if ($userenv{critnotification} =~ m/%40/) {
                    267:                         unless ($emailenc eq $userenv{critnotification}) {
                    268:                         $logmsg .= "Current critical notification e-mail - ".$userenv{critnotification}." for $uname is different to e-mail address in Institutional classlist - $emailenc\n";
                    269:                     }
                    270:                     if ($userenv{notification} =~ m/%40/) {
                    271:                         unless ($emailenc eq $userenv{critnotification}) {
                    272:                             $logmsg .= "Current standard notification e-mail - ".$userenv{notification}." for $uname is different to e-mail address in Institutional classlist - $emailenc\n";
                    273:                         }
                    274:                     }                            
                    275:                     my $krbdefdom = '';
                    276:                     my $currentauth=&Apache::lonnet::queryauthenticate($uname,$dom);
                    277:                     if ($currentauth=~/^krb(4|5):/) {
                    278:                         $currentauth=~/^krb(4|5):(.*)/;
                    279:                         $krbdefdom=$1;
                    280:                     }
                    281:                     if ($currentauth=~/^krb(4|5):/ || 
                    282:                         $currentauth=~/^unix:/ ||
                    283:                         $currentauth=~/^internal:/ ||
                    284:                         $currentauth=~/^localauth:/) {
                    285:                                
                    286:                     } else {
                    287:                         $logmsg .= "Invalid authentication method $currentauth for $uname.\n";  
                    288:                     }
                    289: # Report if authentication methods are different.
                    290:                     if ($currentauth ne $auth ) {
                    291:                          $logmsg .= "Authentication mismatch for $uname - $currentauth in system, $auth for class $crs\n";
                    292:                     }
                    293: # Check user data
                    294:                     if ($first  ne $userenv{'firstname'}  ||
                    295:                         $middle ne $userenv{'middlename'} ||
                    296:                         $last   ne $userenv{'lastname'}   ||
                    297:                         $gene   ne $userenv{'generation'} ||
                    298:                         $pid    ne $userenv{'id'} ) {         
                    299: # Make the change(s)
                    300:                         my %changeHash;
                    301:                         $changeHash{'firstname'}  = $first;
                    302:                         $changeHash{'middlename'} = $middle;
                    303:                         $changeHash{'lastname'}   = $last;
                    304:                         $changeHash{'generation'} = $gene;
                    305:                         $changeHash{'id'} = $pid;
                    306:                         my $putresult = &Apache::lonnet::put('environment',\%changeHash,$dom,$uname);
                    307:                         if ($putresult eq 'ok') {
                    308:                             $logmsg .= "User: $uname enrolled in $crs\n"; 
                    309: # Assign the role of student
                    310:                             $classlist_reply = &modify_student_enrollment($$configvars{'lonHostID'},$dom,$cid,$crs,$uname,$pid,$first,$middle,$last,$gene,$usec,$end,$start,'auto');
                    311:                             if ($classlist_reply eq 'ok') {
                    312:                                 my $uurl='/'.$cid;
                    313:                                 $uurl=~s/\_/\//g;
                    314:                                 if ($usec) {
                    315:                                     $uurl.='/'.$usec;
                    316:                                 }
                    317:                                 &Apache::lonnet::assignrole($dom,$uname,$uurl,"st",$enddate,$startdate);
                    318:                                 $addresult .=  "$first $last ($pid) - $uname enrolled in section/group $usec.".$linefeed;
                    319:                                 $enrollcount ++;
                    320:                                 $addresult .= "$first $last ($pid) - $uname enrolled in section/group $usec.".$linefeed;
                    321:                                 $logmsg .= "Existing user $uname enrolled successfully in $crs\n";
                    322: 
                    323:                             } else {
                    324:                                 $logmsg .= "There was a problem updating the classlist db file for user $uname to show the new enrollment, so no enrollment occurred in $crs\n";
                    325:                             }
                    326:                         } else {
                    327:                             $logmsg .= "There was a problem modifying user data for existing user - $uname, so no enrollment occurred in $crs.\n";
                    328:                         }
                    329:                     }
                    330:                 }
                    331:             }
                    332:         }
                    333:     }
                    334: # Do drops
                    335:     if ( ($drops == 1) && (@reg_students > 0) ) {
                    336:         foreach my $uname (@localstudents) {
                    337:             if ($$currlist{$uname}[$type] eq "auto") {
                    338:                 my @saved = ();
                    339:                 if (!grep/^$uname$/,@reg_students) {
                    340: # Check for changed usernames by checking studentIDs
                    341:                     if (grep/^$$currlist{$uname}[ $stuid ]$/,@allINids) {
                    342:                         foreach my $match (@{$unameFromINid{$$currlist{$uname}[ $stuid ]}} ) {
                    343:                             $logmsg .= "A possible change in username has been detected for a student enrolled in $crs. The existing LON-CAPA classlist contains user: $uname and student ID: $$currlist{$uname}[ $place{studentID} ].  This username has been dropped from the institutional classlist, but the same student ID is used for user: $match who still appears in the institutional classlist. You may need to move the student data files for user: $uname to $match\n";
                    344:                             push @saved,$uname;
                    345:                         }
                    346:                     } elsif (@saved == 0) {
                    347:                         my $drop_reply = &Apache::lonnet::modifystudent($dom,$uname,'','','',undef,undef,undef,undef,$$currlist{$uname}[$sec],time,undef,undef,undef,undef,undef,$cid);
                    348:                         if ($drop_reply !~ /^ok/) {
                    349:                             $logmsg .= "An error occured during the attempt to expire the $uname from the old section $$currlist{$uname}[$sec] - $drop_reply\n";
                    350:                         } else {
                    351:                             $dropcount ++;
                    352:                             my %userenv = &Apache::lonnet::get('environment',['firstname','lastname','id'],$dom,$uname);
                    353:                             $dropresult .= $userenv{'firstname'}." ".$userenv{'lastname'}." (".$userenv{'id'}.") - ".$uname." dropped from section/group ".$$currlist{$uname}[$sec].$linefeed; 
                    354:                         }
                    355:                     }
                    356:                 }
                    357:             }
                    358:         }
                    359:     }
                    360:     if ($enrollcount > 0) {
                    361:         if ($context eq "updatenow") {
                    362:             $addresult = "The following $enrollcount student(s) was/were added to this LON-CAPA course:<br/><ul><li>".$addresult."</li></ul><br/><br/>";
                    363:         } else {
                    364:             $addresult = "The following $enrollcount student(s) was/were added to this LON-CAPA course:\n\n".$addresult."\n\n";    
                    365:         }      
                    366:     }
                    367:     if ($dropcount > 0) {
                    368:         if ($context eq "updatenow") {
                    369:             $dropresult = "The following $dropcount student(s) was/were expired from this LON-CAPA course:<br/><ul><li>".$dropresult."</li></ul><br/><br/>";
                    370:         } else {
                    371:             $dropresult = "The following $dropcount student(s) was/were expired from this LON-CAPA course:\n\n".$dropresult."\n\n";
                    372:         }
                    373:     }
                    374:     if ( ($adds) && ($enrollcount == 0) ) {
                    375:         $addresult = "There were no new students to add to the course.";
                    376:         if ($context eq "updatenow") {
                    377:             $addresult .="<br/><br/>";
                    378:         } else {
                    379:             $addresult .="\n";
                    380:         }
                    381:     }
                    382:     if ( ($drops) && ($dropcount == 0) ) {
                    383:         $dropresult = "There were no students with roles to expire because all active students previously added to the course from institutional classlist(s) are still officially registered.";
                    384:         if ($context eq "updatenow") {
                    385:             $dropresult .="<br/>";
                    386:         } else {
                    387:             $dropresult .="\n";
                    388:         }
                    389:     }
                    390:     print STDERR $logmsg;
                    391:     return $addresult.$dropresult; 
                    392: } 
                    393: 
                    394: sub parse_classlist {
                    395:   my ($tmpdir,$dom,$crs,$class,$placeref,$groupID,$studentsref) = @_;            
                    396:   my $configvars = &LONCAPA::Configuration::read_conf();
                    397:   my $xmlfile = $tmpdir."/tmp/".$dom."_".$crs."_classlist.xml";
                    398:   my $enrolled = XMLin( $xmlfile, KeyAttr => ['username'] );
                    399:   foreach my $uname ( sort keys %{$$enrolled{'student'}} ) {
                    400:       @{ $$studentsref{$uname} } = ();
                    401:       foreach my $key (sort keys %{$$enrolled{'student'}{$uname}} ) {
                    402:           my $value = $$enrolled{'student'}{$uname}{$key};
                    403:           if (ref($value)) {
                    404:               $$studentsref{$uname}[ $$placeref{$key} ] = '';
                    405:           } else {
                    406:               if ($key eq 'groupID') {
                    407:                   $$studentsref{$uname}[ $$placeref{$key} ] = $groupID;
                    408:               } else {
                    409:                   $$studentsref{$uname}[ $$placeref{$key} ] = $value;
                    410:               }
                    411:           }
                    412:       }
                    413:   }
                    414: #  if (-e "$xmlfile") {
                    415: #      unlink $xmlfile;
                    416: #  }
                    417:   return;
                    418: }
                    419: 
                    420: sub create_password {
                    421: 
                    422: 
                    423: }
                    424: 
                    425: sub CL_autharg { return 0; }
                    426: sub CL_authtype { return 1;}
                    427: sub CL_email { return 2;}
                    428: sub CL_enddate { return 3;}
                    429: sub CL_firstname { return 4;}
                    430: sub CL_generation { return 5;}
                    431: sub CL_groupID { return 6;}
                    432: sub CL_lastname { return 7;}
                    433: sub CL_middlename { return 8;}
                    434: sub CL_startdate { return 9; }
                    435: sub CL_studentID { return 10; }
                    436: 
                    437: 1;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>