[LON-CAPA-cvs] cvs: loncom /enrollment Autoupdate.pl /interface loncommon.pm loncreateuser.pm lonuserutils.pm

raeburn lon-capa-cvs-allow@mail.lon-capa.org
Thu, 15 Nov 2007 21:24:57 -0000


This is a MIME encoded message

--raeburn1195161897
Content-Type: text/plain

raeburn		Thu Nov 15 16:24:57 2007 EDT

  Modified files:              
    /loncom/interface	loncommon.pm lonuserutils.pm loncreateuser.pm 
    /loncom/enrollment	Autoupdate.pl 
  Log:
  Propagating changes in ID made by Domain Coordinator to classlist.db file in any courses in which user has active or future student roles. Update name changes too.
  
  loncommon.pm 
  - Pass ref to %got_rules to &user_rule_check(), so retrieval of rules only occurs once per domain. Retrieve rules for both username and ID
  - &instrule_disallow_msg() takes a fourth argument ($mode) so message is different for messages generated for uploaded CSV file of users and single user modification.
  
  loncreateuser.pm
  - Propagate name changes and ID change to courses if Domain Coordinator is updating user data.
  - Only display permanent e-mail on results page (no personal data changes) if one is defined.
  - &print_user_modification_page() takes additional argument - $context - if domain adds the checkbox to force an ID change.
  
  lonuserutils.pm
  - check for $context was mistakenly checking $setting
  - check whether Domain Coordinator wishes to change authentication for existing users should be $checkauth eq 'Yes'
  - propagate name changes and ID change to courses if Domain Coordinator is updating user data, and had checked boxes for force ID change, and force course changes
  - &update_classlist() moved to lonuserutils.pm from Autoupdate.pl
  - &propagate_id_change() added to propagate ID and name changes to courses
  - include cr (for Custom role) in option for Course roles for DC when setting filters for user lists.
  - summary of filters used (displayed above tabular data) is customized to be an appropriate message for the choice of filters used in all cases.
  - &Apache::lonnet::flushcourselogs() after processing adds/modifications in CSV file of users called in all contexts.
  
  Autoupdate.pl
  - &update_classlist() moved to lonuserutils.pm
  
  
--raeburn1195161897
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20071115162457.txt"

Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.614 loncom/interface/loncommon.pm:1.615
--- loncom/interface/loncommon.pm:1.614	Tue Nov 13 18:05:45 2007
+++ loncom/interface/loncommon.pm	Thu Nov 15 16:24:51 2007
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.614 2007/11/13 23:05:45 albertel Exp $
+# $Id: loncommon.pm,v 1.615 2007/11/15 21:24:51 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -6440,60 +6440,64 @@
 }
 
 sub user_rule_check {
-    my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules) = @_;
+    my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
     my $response;
     if (ref($usershash) eq 'HASH') {
-        my %got_rules;
         foreach my $user (keys(%{$usershash})) {
             my ($uname,$udom) = split(/:/,$user);
             next if ($udom eq '' || $uname eq '');
-            my ($userstatus,$id);
+            my ($id,$newuser);
             if (ref($usershash->{$user}) eq 'HASH') {
-                $userstatus = $usershash->{$user}->{'status'};
+                $newuser = $usershash->{$user}->{'newuser'};
                 $id = $usershash->{$user}->{'id'};
             }
             my $inst_response;
             if (ref($checks) eq 'HASH') {
                 if (defined($checks->{'username'})) {
-                    ($inst_response,%{$inst_results}) = 
+                    ($inst_response,%{$inst_results->{$user}}) = 
                         &Apache::lonnet::get_instuser($udom,$uname);
                 } elsif (defined($checks->{'id'})) {
-                    ($inst_response,%{$inst_results}) =
+                    ($inst_response,%{$inst_results->{$user}}) =
                         &Apache::lonnet::get_instuser($udom,undef,$id);
                 }
+            } else {
+                ($inst_response,%{$inst_results->{$user}}) =
+                    &Apache::lonnet::get_instuser($udom,$uname);
+                return;
             }
-            if (!$got_rules{$udom}) {
+            if (!$got_rules->{$udom}) {
                 my %domconfig = &Apache::lonnet::get_dom('configuration',
                                                   ['usercreation'],$udom);
                 if (ref($domconfig{'usercreation'}) eq 'HASH') {
-                    foreach my $item (keys(%{$checks})) {
+                    foreach my $item ('username','id') {
                         if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
                             $$curr_rules{$udom}{$item} = 
                                 $domconfig{'usercreation'}{$item.'_rule'};
                         }
                     }
                 }
-                $got_rules{$udom} = 1;
+                $got_rules->{$udom} = 1;  
             }
             foreach my $item (keys(%{$checks})) {
                 if (ref($$curr_rules{$udom}) eq 'HASH') {
                     if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') {
                         if (@{$$curr_rules{$udom}{$item}} > 0) {
-                            my %rule_check;
                             my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,$$curr_rules{$udom}{$item});
                             foreach my $rule (@{$$curr_rules{$udom}{$item}}) {
                                 if ($rule_check{$rule}) {
                                     $$rulematch{$user}{$item} = $rule;
                                     if ($inst_response eq 'ok') {
-                                        if (keys(%{$inst_results}) == 0) {
-                                            if ($userstatus eq 'new') {
-                                                $$alerts{$user}{$item} = 1;
+                                        if (ref($inst_results) eq 'HASH') {
+                                            if (ref($inst_results->{$user}) eq 'HASH') {
+                                                if (keys(%{$inst_results->{$user}}) == 0) {
+                                                    $$alerts{$item}{$udom}{$uname} = 1;
+                                                }
                                             }
                                         }
-                                    }  
+                                    }
+                                    last;
                                 }
                             }
-                            last;
                         }
                     }
                 }
@@ -6531,7 +6535,7 @@
 }
 
 sub instrule_disallow_msg {
-    my ($checkitem,$domdesc,$count) = @_;
+    my ($checkitem,$domdesc,$count,$mode) = @_;
     my $response;
     my %text = (
                   item   => 'username',
@@ -6552,12 +6556,24 @@
         $text{'items'} = 'IDs';
         $text{'item'} = 'ID';
         $text{'action'} = 'an ID';
+        if ($count > 1) {
+            $text{'item'} = 'IDs';
+            $text{'action'} = 'IDs';
+        }
     }
     $response = &mt("The $text{'item'} you chose $text{'match'} the format of $text{'items'} defined for <span class=\"LC_cusr_emph\">[_1]</span>, but the $text{'item'} $text{'do'} not exist in the institutional directory.",$domdesc).'<br />';
-    if ($checkitem eq 'username') {
-        $response .= &mt("You must choose $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
-    } elsif ($checkitem eq 'id') {
-       $response .= &mt("You must either choose $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave this field blank.");
+    if ($mode eq 'upload') {
+        if ($checkitem eq 'username') {
+            $response .= &mt("You will need to modify your upload file so it will include $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
+        } elsif ($checkitem eq 'id') {
+            $response .= &mt("Either upload a file which includes $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or when associating fields with data columns, omit an association for the ID/Student Number field.");
+        }
+    } else {
+        if ($checkitem eq 'username') {
+            $response .= &mt("You must choose $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
+        } elsif ($checkitem eq 'id') {
+            $response .= &mt("You must either choose $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave the ID field blank.");
+        }
     }
     return $response;
 }
Index: loncom/interface/lonuserutils.pm
diff -u loncom/interface/lonuserutils.pm:1.4 loncom/interface/lonuserutils.pm:1.5
--- loncom/interface/lonuserutils.pm:1.4	Sat Nov 10 17:18:09 2007
+++ loncom/interface/lonuserutils.pm	Thu Nov 15 16:24:51 2007
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA user accounts
 #
-# $Id: lonuserutils.pm,v 1.4 2007/11/10 22:18:09 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.5 2007/11/15 21:24:51 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -85,28 +85,39 @@
 sub modifyuserrole {
     my ($context,$setting,$changeauth,$cid,$udom,$uname,$uid,$umode,$upass,
         $first,$middle,$last,$gene,$sec,$forceid,$desiredhome,$email,$role,
-        $end,$start) = @_;
-    my ($scope,$userresult,$authresult,$roleresult);
+        $end,$start,$checkid) = @_;
+    my ($scope,$userresult,$authresult,$roleresult,$idresult);
     if ($setting eq 'course' || $context eq 'course') {
         $scope = '/'.$cid;
         $scope =~ s/\_/\//g;
         if ($role ne 'cc' && $sec ne '') {
             $scope .='/'.$sec;
         }
-    } elsif ($setting eq 'domain') {
+    } elsif ($context eq 'domain') {
         $scope = '/'.$env{'request.role.domain'}.'/';
-    } elsif ($setting eq 'construction_space') {
+    } elsif ($context eq 'construction_space') {
         $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) && (&Apache::lonnet::allowed('mau',$udom))) {
+            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 =
@@ -114,14 +125,75 @@
                                     $middle,$last,$gene,$forceid,$desiredhome,
                                     $email,$role,$start,$end);
     if ($userresult eq 'ok') {
-        if ($role ne '') { 
+        if ($role ne '') {
             $roleresult = &Apache::lonnet::assignrole($udom,$uname,$scope,
                                                       $role,$end,$start);
         }
     }
-    return ($userresult,$authresult,$roleresult);
+    return ($userresult,$authresult,$roleresult,$idresult);
 }
 
+sub propagate_id_change {
+    my ($uname,$udom,$user) = @_;
+    my (@types,@roles,@cdoms);
+    @types = ('active','future');
+    @roles = ('st');
+    my $idresult;
+    my %roleshash = &Apache::lonnet::get_my_roles($uname,
+                        $udom,'userroles',\@types,\@roles,\@cdoms);
+    foreach my $item (keys(%roleshash)) {
+        my ($cnum,$cdom,$role) = split(/:/,$item);
+        my ($start,$end) = split(/:/,$roleshash{$item});
+        if (&Apache::lonnet::is_course($cdom,$cnum)) {
+            my %userupdate;
+            my $result = &update_classlist($cdom,$cnum,$udom,$uname,\%userupdate);
+            if ($result eq 'ok') {
+                $idresult .= "Classlist change: $uname:$udom - class -> $cnum:$cdom\n";
+            } else {
+                $idresult .= "Error - $result -during classlist update for $uname:$udom in $cnum:$cdom\n";
+            }
+        }
+    }
+    return $idresult;
+}
+
+sub update_classlist {
+    my ($cdom,$cnum,$udom,$uname,$user) = @_;
+    my ($uid,$fullname,$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;
+    for (my $i=0; $i<@classinfo; $i++) {
+        if ($i == $ididx) {
+            if (defined($user->{'id'})) {
+                $classlistentry .= $user->{'id'}.':';
+            } else {
+                $classlistentry .= $classinfo[$i].':';
+            }
+        } elsif ($i == $nameidx) {
+            $classlistentry .= $fullname.':';
+        } 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
@@ -156,12 +228,18 @@
             @roles = &construction_space_roles();
         } else {
             @roles = &course_roles('domain');
+            unshift(@roles,'cr');
         }
         my $order = ['Any',@roles];
         $select_menus{$roletype}->{'order'} = $order; 
         foreach my $role (@roles) {
-            $select_menus{$roletype}->{'select2'}->{$role} = 
-                          &Apache::lonnet::plaintext($role);
+            if ($role eq 'cr') {
+                $select_menus{$roletype}->{'select2'}->{$role} =
+                              &mt('Custom role');
+            } else {
+                $select_menus{$roletype}->{'select2'}->{$role} = 
+                              &Apache::lonnet::plaintext($role);
+            }
         }
         $select_menus{$roletype}->{'select2'}->{'Any'} = &mt('Any');
     }
@@ -637,8 +715,12 @@
     my ($options,$cb_script,$coursepick) = &default_role_selector($context,'defaultrole',1);
     if ($context eq 'domain') {
         $Str .= '<span class="LC_role_level">'.&mt('Domain Level').'</span><br />'.$options.'<br /><br /><span class="LC_role_level">'.&mt('Course Level').'</span><br />'.$cb_script.$coursepick;
-    } else {
+    } elsif ($context eq 'construction_space') {
         $Str .= $options;
+    } else {
+        $Str .= '<table><tr><td><span class="LC_nobreak"<b>'.&mt('role').':&nbsp;</b>'.
+                $options.'</span></td><td>&nbsp;</td><td><span class="LC_nobreak">'.
+                '<b>'.&mt('section').':&nbsp;</b><input type="text" name="section" value="" size="12" /></span></td></tr></table>';
     }
     if ($context eq 'course') {
         $Str .= "<h3>".&mt('Full Update')."</h3>\n".
@@ -646,12 +728,9 @@
                 ' '.&mt('Full update (also print list of users not enrolled anymore)').
                 "</label></p>\n";
     }
-    $Str .= "<h3>".&mt('ID/Student Number')."</h3>\n";
-    $Str .= "<p>\n".'<label><input type="checkbox" name="forceid" value="yes">';
-    $Str .= &mt('Disable ID/Student Number Safeguard and Force Change '.
-                'of Conflicting IDs').
-                '</label><br />'."\n".
-                &mt('(only do if you know what you are doing.)')."</p><p>\n";
+    if ($context eq 'course' || $context eq 'domain') {
+        $Str .= &forceid_change($context);
+    }
     $Str .= '</div><div class="LC_clear_float_footer"><br /><input type="button"'.
               'onClick="javascript:verify(this.form,this.form.csec)" '.
         'value="Update Users" />'."<br />\n";
@@ -664,6 +743,23 @@
     return;
 }
 
+sub forceid_change {
+    my ($context) = @_;
+    my $output = 
+        "<h3>".&mt('ID/Student Number')."</h3>\n".
+        "<p>\n".'<label><input type="checkbox" name="forceid" value="yes">'.
+        &mt('Disable ID/Student Number Safeguard and Force Change '.
+        'of Conflicting IDs').'</label><br />'."\n".
+        &mt('(only do if you know what you are doing.)')."</br><br />\n";
+    if ($context eq 'domain') {
+        $output .= '<label><input type="checkbox" name="recurseid"'.
+                   ' value="yes">'. 
+  &mt('Update ID/Student Number in courses in which user is an Active or Future student, (if forcing change).').
+                   '</label></p>'."\n";
+    }
+    return $output;
+}
+
 ###############################################################
 ###############################################################
 sub print_upload_manager_form {
@@ -1232,6 +1328,7 @@
                             %users,%statushash);
                         if ($env{'form.showrole'} eq 'Any') {
                             @roles = &course_roles($context);
+                            unshift(@roles,'cr');
                         } else {
                             @roles = ($env{'form.showrole'});
                         }
@@ -1704,7 +1801,9 @@
     push(@cols,'email');
 
     my $rolefilter = $env{'form.showrole'};
-    if ($env{'form.showrole'} ne 'Any') {
+    if ($env{'form.showrole'} eq 'cr') {
+        $rolefilter = &mt('custom');  
+    } elsif ($env{'form.showrole'} ne 'Any') {
         $rolefilter = &Apache::lonnet::plaintext($env{'form.showrole'});
     }
     my $results_description = &results_header_row($rolefilter,$statusmode,
@@ -1817,8 +1916,11 @@
     # necessary.
     foreach my $user (keys(%{$userlist})) {
         my ($uname,$udom,$role,$groups,$email);
-        next if (($statusmode ne 'Any') && 
-                 ($userlist->{$user}->[$index{'status'}] ne $statusmode));
+        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);
@@ -2004,16 +2106,19 @@
 
 sub results_header_row {
     my ($rolefilter,$statusmode,$context) = @_;
-    my $description;
+    my ($description,$showfilter);
+    if ($rolefilter ne 'Any') {
+        $showfilter = $rolefilter;
+    }
     if ($context eq 'course') {
         $description = &mt('Course - ').$env{'course.'.$env{'request.course.id'}.'.description'}.': ';
         if ($statusmode eq 'Expired') {
-            $description .= &mt('Users in course with expired [_1] roles',$rolefilter);
+            $description .= &mt('Users in course with expired [_1] roles',$showfilter);
         }
         if ($statusmode eq 'Future') {
-            $description .= &mt('Users in course with future [_1] roles',$rolefilter);
+            $description .= &mt('Users in course with future [_1] roles',$showfilter);
         } elsif ($statusmode eq 'Active') {
-            $description .= &mt('Users in course with active [_1] roles',$rolefilter);
+            $description .= &mt('Users in course with active [_1] roles',$showfilter);
         } else {
             if ($rolefilter eq 'Any') {
                 $description .= &mt('All users in course');
@@ -2024,14 +2129,14 @@
     } elsif ($context eq 'construction_space') {
         $description = &mt('Author space for [_1].').' ';
         if ($statusmode eq 'Expired') {
-            $description .= &mt('Co-authors with expired [_1] roles',$rolefilter);
+            $description .= &mt('Co-authors with expired [_1] roles',$showfilter);
         } elsif ($statusmode eq 'Future') {
-            $description .= &mt('Co-authors with future [_1] roles',$rolefilter);
+            $description .= &mt('Co-authors with future [_1] roles',$showfilter);
         } elsif ($statusmode eq 'Active') {
-            $description .= &mt('Co-authors with active [_1] roles',$rolefilter);
+            $description .= &mt('Co-authors with active [_1] roles',$showfilter);
         } else {
             if ($rolefilter eq 'Any') {
-                $description .= &mt('All co-authors',$rolefilter);
+                $description .= &mt('All co-authors');
             } else {
                 $description .= &mt('All co-authors with [_1] roles',$rolefilter);
             }
@@ -2041,28 +2146,28 @@
         $description = &mt('Domain - ').$domdesc.': ';
         if ($env{'form.roletype'} eq 'domain') {
             if ($statusmode eq 'Expired') {
-                $description .= &mt('Users in domain with expired [_1] roles',$rolefilter);
+                $description .= &mt('Users in domain with expired [_1] roles',$showfilter);
             } elsif ($statusmode eq 'Future') {
-                $description .= &mt('Users in domain with future [_1] roles',$rolefilter);
+                $description .= &mt('Users in domain with future [_1] roles',$showfilter);
             } elsif ($statusmode eq 'Active') {
-                $description .= &mt('Users in domain with active [_1] roles',$rolefilter);
+                $description .= &mt('Users in domain with active [_1] roles',$showfilter);
             } else {
                 if ($rolefilter eq 'Any') {
-                    $description .= &mt('All users in domain',$rolefilter);
+                    $description .= &mt('All users in domain');
                 } else {
                     $description .= &mt('All users in domain with [_1] roles',$rolefilter);
                 }
             }
         } elsif ($env{'form.roletype'} eq 'construction_space') {
             if ($statusmode eq 'Expired') {
-                $description .= &mt('Co-authors in domain with expired [_1] roles',$rolefilter);
+                $description .= &mt('Co-authors in domain with expired [_1] roles',$showfilter);
             } elsif ($statusmode eq 'Future') {
-                $description .= &mt('Co-authors in domain with future [_1] roles',$rolefilter);
+                $description .= &mt('Co-authors in domain with future [_1] roles',$showfilter);
             } elsif ($statusmode eq 'Active') {
-               $description .= &mt('Co-authors in domain with active [_1] roles',$rolefilter);
+               $description .= &mt('Co-authors in domain with active [_1] roles',$showfilter);
             } else {
                 if ($rolefilter eq 'Any') {
-                    $description .= &mt('All users with co-author roles in domain',$rolefilter);
+                    $description .= &mt('All users with co-author roles in domain',$showfilter);
                 } else {
                     $description .= &mt('All co-authors in domain  with [_1] roles',$rolefilter);
                 }
@@ -2082,11 +2187,11 @@
                 $description .= &mt('All courses in domain').' - ';
             }
             if ($statusmode eq 'Expired') {
-                $description .= &mt('users with expired [_1] roles',$rolefilter);
+                $description .= &mt('users with expired [_1] roles',$showfilter);
             } elsif ($statusmode eq 'Future') {
-                $description .= &mt('users with future [_1] roles',$rolefilter);
+                $description .= &mt('users with future [_1] roles',$showfilter);
             } elsif ($statusmode eq 'Active') {
-                $description .= &mt('users with active [_1] roles',$rolefilter);
+                $description .= &mt('users with active [_1] roles',$showfilter);
             } else {
                 if ($rolefilter eq 'Any') {
                     $description .= &mt('all users');
@@ -2420,6 +2525,7 @@
             # Get information about course groups
             %curr_groups = &Apache::longroup::coursegroups();
         }
+        my (%curr_rules,%got_rules,%alerts);
         # Get new users list
         foreach (@userdata) {
             my %entries=&Apache::loncommon::record_sep($_);
@@ -2451,7 +2557,7 @@
           $entries{$fields{'username'}},$fname,$mname,$lname,$gen).
                               '</b>');
                 } else {
-                    my $username = $entries{$fields{'username'}}; 
+                    my $username = $entries{$fields{'username'}};
                     my $sec;
                     if ($context eq 'course' || $setting eq 'course') {
                         # determine section number
@@ -2522,6 +2628,48 @@
                              \$lname,\$gen,\$sec,\$role) {
                         $$_ =~ s/(\s+$|^\s+)//g;
                     }
+                    # check against rules
+                    my $checkid = 0;
+                    my $newuser = 0;
+                    my (%rulematch,%inst_results,%idinst_results);
+                    my $uhome=&Apache::lonnet::homeserver($username,$domain);
+                    if ($uhome eq 'no_host') {
+                        $checkid = 1;
+                        $newuser = 1;
+                        my $checkhash;
+                        my $checks = { 'username' => 1 };
+                        $checkhash->{$username.':'.$domain} = { 'newuser' => 1, };
+                        &Apache::loncommon::user_rule_check($checkhash,$checks,
+                            \%alerts,\%rulematch,\%inst_results,\%curr_rules,
+                            \%got_rules);
+                        if (ref($alerts{'username'}) eq 'HASH') {
+                            if (ref($alerts{'username'}{$domain}) eq 'HASH') {
+                                next if ($alerts{'username'}{$domain}{$username});
+                            }
+                        }
+                    }
+                    if ($id ne '') {
+                        if (!$newuser) {
+                            my %idhash = &Apache::lonnet::idrget($domain,($username));
+                            if ($idhash{$username} ne $id) {
+                                $checkid = 1;
+                            }
+                        }
+                        if ($checkid) {
+                            my $checkhash;
+                            my $checks = { 'id' => 1 };
+                            $checkhash->{$username.':'.$domain} = { 'newuser' => $newuser,
+                                                                    'id'  => $id };
+                            &Apache::loncommon::user_rule_check($checkhash,$checks,
+                                \%alerts,\%rulematch,\%idinst_results,\%curr_rules,
+                                \%got_rules);
+                            if (ref($alerts{'id'}) eq 'HASH') {
+                                if (ref($alerts{'id'}{$domain}) eq 'HASH') {
+                                    next if ($alerts{'id'}{$domain}{$id});
+                                }
+                            }
+                        }
+                    }
                     if ($password || $env{'form.login'} eq 'loc') {
                         my ($userresult,$authresult,$roleresult);
                         if ($role eq 'st') {
@@ -2540,7 +2688,7 @@
                                     $id,$amode,$password,$fname,
                                     $mname,$lname,$gen,$sec,
                                     $env{'form.forceid'},$desiredhost,
-                                    $email,$role,$enddate,$startdate);
+                                    $email,$role,$enddate,$startdate,$checkid);
                         }
                         $flushc = 
                             &user_change_result($r,$userresult,$authresult,
@@ -2565,9 +2713,7 @@
             }
         } # end of foreach (@userdata)
         # Flush the course logs so reverse user roles immediately updated
-        if ($context eq 'course' || ($context eq 'domain' && $setting eq 'course')) {
-            &Apache::lonnet::flushcourselogs();
-        }
+        &Apache::lonnet::flushcourselogs();
         $r->print("</p>\n<p>\n".&mt('Processed [_1] user(s).',$counts{'user'}).
                   "</p>\n");
         if ($counts{'role'} > 0) {
@@ -2579,6 +2725,39 @@
                       &mt('Authentication changed for [_1] existing users.',
                           $counts{'auth'})."</p>\n");
         }
+        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') {
+                        $r->print(&Apache::loncommon::instrule_disallow_msg(
+                                 'username',$domdesc,$count,'upload'));
+                    }
+                    $r->print(&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') {
+                        $r->print(&Apache::loncommon::instrule_disallow_msg(
+                                 'id',$domdesc,$count,'upload'));
+                    }
+                    $r->print(&Apache::loncommon::user_rule_formats($dom,
+                              $domdesc,$curr_rules{$dom}{'id'},'id'));
+                }
+            }
+        }
         $r->print('<form name="uploadresult" action="/adm/createuser">');
         $r->print(&Apache::lonhtmlcommon::echo_form_input(['phase','prevphase','currstate']));
         $r->print('</form>');
Index: loncom/interface/loncreateuser.pm
diff -u loncom/interface/loncreateuser.pm:1.195 loncom/interface/loncreateuser.pm:1.196
--- loncom/interface/loncreateuser.pm:1.195	Thu Nov 15 14:06:28 2007
+++ loncom/interface/loncreateuser.pm	Thu Nov 15 16:24:51 2007
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Create a user
 #
-# $Id: loncreateuser.pm,v 1.195 2007/11/15 19:06:28 raeburn Exp $
+# $Id: loncreateuser.pm,v 1.196 2007/11/15 21:24:51 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -440,7 +440,7 @@
 }
 
 sub print_user_modification_page {
-    my ($r,$ccuname,$ccdomain,$srch,$response) = @_;
+    my ($r,$ccuname,$ccdomain,$srch,$response,$context) = @_;
     if (($ccuname eq '') || ($ccdomain eq '')) {
         my $usermsg = &mt('No username and/or domain provided.'); 
 	&print_username_entry_form($r,$usermsg);
@@ -448,30 +448,32 @@
     }
     my %abv_auth = &auth_abbrev();
     my ($curr_authtype,%rulematch,%inst_results,$curr_kerb_ver,$newuser,
-        %alerts,%curr_rules);
+        %alerts,%curr_rules,%got_rules);
     my $uhome=&Apache::lonnet::homeserver($ccuname,$ccdomain);
     if ($uhome eq 'no_host') {
         $newuser = 1;
         my $checkhash;
         my $checks = { 'username' => 1 };
-        $checkhash->{$ccuname.':'.$ccdomain} = { 'status' => 'new' };
+        $checkhash->{$ccuname.':'.$ccdomain} = { 'newuser' => $newuser };
         &Apache::loncommon::user_rule_check($checkhash,$checks,
-                   \%alerts,\%rulematch,\%inst_results,\%curr_rules);
-        if (ref($alerts{$ccuname.':'.$ccdomain}) eq 'HASH') {
-            if ($alerts{$ccuname.':'.$ccdomain}{'username'}) {
-                my $domdesc = 
+            \%alerts,\%rulematch,\%inst_results,\%curr_rules,\%got_rules);
+        if (ref($alerts{'username'}) eq 'HASH') {
+            if (ref($alerts{'username'}{$ccdomain}) eq 'HASH') {
+                my $domdesc =
                     &Apache::lonnet::domain($ccdomain,'description');
-                my $userchkmsg;
-                if (ref($curr_rules{$ccdomain}) eq 'HASH') {  
-                    $userchkmsg = 
-                        &Apache::loncommon::instrule_disallow_msg('username',
+                if ($alerts{'username'}{$ccdomain}{$ccuname}) {
+                    my $userchkmsg;
+                    if (ref($curr_rules{$ccdomain}) eq 'HASH') {  
+                        $userchkmsg = 
+                            &Apache::loncommon::instrule_disallow_msg('username',
                                                                  $domdesc,1).
                         &Apache::loncommon::user_rule_formats($ccdomain,
                             $domdesc,$curr_rules{$ccdomain}{'username'},
                             'username');
-                }
-                &print_username_entry_form($r,$userchkmsg);
-                return;
+                    }
+                    &print_username_entry_form($r,$userchkmsg);
+                    return;
+                } 
             }
         }
     } else {
@@ -790,6 +792,9 @@
         } else {
             $r->print($home_server_pick);
         }
+        if ($context eq 'domain') {
+            $r->print(&Apache::lonuserutils::forceid_change());
+        }
         $r->print('</div>'."\n".'<div class="LC_left_float"><h3>'.
                   $lt{'lg'}.'</h3>');
         my ($fixedauth,$varauth,$authmsg); 
@@ -1585,26 +1590,30 @@
         my %checkhash;
         my %checks = ('id' => 1);
         %{$checkhash{$env{'form.ccuname'}.':'.$env{'form.ccdomain'}}} = (
-            'status' => 'new', 
-            'id' => $env{'form.cid'}
+            'newuser' => 1, 
+            'id' => $env{'form.cid'},
         );
-        &Apache::loncommon::user_rule_check(\%checkhash,\%checks,\%alerts,
-                                      \%rulematch,\%inst_results,\%curr_rules);
-        if (ref($alerts{$env{'form.ccuname'}.':'.$env{'form.ccdomain'}}) eq 'HASH') {
-            if ($alerts{$env{'form.ccuname'}.':'.$env{'form.ccdomain'}}{'id'}) {
-                my $domdesc =
-                    &Apache::lonnet::domain($env{'form.ccdomain'},'description');
-                my $userchkmsg;
-                if (ref($curr_rules{$env{'form.ccdomain'}}) eq 'HASH') {
-                    $userchkmsg  = 
-                        &Apache::loncommon::instrule_disallow_msg('id',
-                                                                  $domdesc,1).
-                        &Apache::loncommon::user_rule_formats($env{'form.ccdomain'},
-                            $domdesc,$curr_rules{$env{'form.ccdomain'}}{'id'},'id');
-                } 
-                $r->print($error.&mt('Invalid ID format').$end.
-                          $userchkmsg.$rtnlink);
-                return;
+        if ($env{'form.cid'} ne '') {
+            &Apache::loncommon::user_rule_check(\%checkhash,\%checks,\%alerts,
+                                          \%rulematch,\%inst_results,\%curr_rules);
+            if (ref($alerts{'id'}) eq 'HASH') {
+                if (ref($alerts{'id'}{$env{'form.ccdomain'}}) eq 'HASH') {
+                    my $domdesc =
+                        &Apache::lonnet::domain($env{'form.ccdomain'},'description');
+                    if ($alerts{'id'}{$env{'form.ccdomain'}}{$env{'form.cid'}}) {
+                        my $userchkmsg;
+                        if (ref($curr_rules{$env{'form.ccdomain'}}) eq 'HASH') {
+                            $userchkmsg  = 
+                                &Apache::loncommon::instrule_disallow_msg('id',
+                                                                    $domdesc,1).
+                                &Apache::loncommon::user_rule_formats($env{'form.ccdomain'},
+                                    $domdesc,$curr_rules{$env{'form.ccdomain'}}{'id'},'id');
+                        }
+                        $r->print($error.&mt('Invalid ID format').$end.
+                                  $userchkmsg.$rtnlink);
+                        return;
+                    }
+                }
             }
         }
 	# Call modifyuser
@@ -1644,17 +1653,40 @@
         # Check for need to change
         my %userenv = &Apache::lonnet::get
             ('environment',['firstname','middlename','lastname','generation',
-             'permanentemail','portfolioquota','inststatus'],
+             'id','permanentemail','portfolioquota','inststatus'],
               $env{'form.ccdomain'},$env{'form.ccuname'});
         my ($tmp) = keys(%userenv);
         if ($tmp =~ /^(con_lost|error)/i) { 
             %userenv = ();
         }
         # Check to see if we need to change user information
-        foreach my $item ('firstname','middlename','lastname','generation','permanentemail') {
+        foreach my $item ('firstname','middlename','lastname','generation','permanentemail','id') {
             # Strip leading and trailing whitespace
             $env{'form.c'.$item} =~ s/(\s+$|^\s+)//g; 
         }
+        # Check to see if we can change the ID/student number
+        my $forceid = $env{'form.forceid'};
+        my $recurseid = $env{'form.recurseid'};
+        my $newuser = 0;
+        my $disallowed_id = 0;
+        my (%alerts,%rulematch,%idinst_results,%curr_rules,%got_rules);
+        if (!$forceid) {
+            $env{'form.cid'} = $userenv{'id'};
+        } elsif ($env{'form.cid'} ne $userenv{'id'}) {
+            my $checkhash;
+            my $checks = { 'id' => 1 };
+            $checkhash->{$env{'form.ccuname'}.':'.$env{'form.ccdomain'}} = 
+                   { 'newuser' => $newuser,
+                     'id'  => $env{'form.cid'}, 
+                   };
+            &Apache::loncommon::user_rule_check($checkhash,$checks,
+                \%alerts,\%rulematch,\%idinst_results,\%curr_rules,\%got_rules);
+            if (ref($alerts{'id'}) eq 'HASH') {
+                if (ref($alerts{'id'}{$env{'form.ccdomain'}}) eq 'HASH') {
+                   $disallowed_id = 1;
+                }
+            }
+        }
         my ($quotachanged,$namechanged,$oldportfolioquota,$newportfolioquota,
             $inststatus,$isdefault,$defquotatext);
         my ($defquota,$settingstatus) = 
@@ -1710,6 +1742,7 @@
              $env{'form.cmiddlename'} ne $userenv{'middlename'} ||
              $env{'form.clastname'}   ne $userenv{'lastname'}   ||
              $env{'form.cgeneration'} ne $userenv{'generation'} ||
+             $env{'form.cid'} ne $userenv{'id'}                 ||
              $env{'form.cpermanentemail'} ne $userenv{'permanentemail'} )) {
             $namechanged = 1;
         }
@@ -1719,6 +1752,7 @@
             $changeHash{'middlename'} = $env{'form.cmiddlename'};
             $changeHash{'lastname'}   = $env{'form.clastname'};
             $changeHash{'generation'} = $env{'form.cgeneration'};
+            $changeHash{'id'}         = $env{'form.cid'};
             $changeHash{'permanentemail'} = $env{'form.cpermanentemail'};
             my $putresult = &Apache::lonnet::put
                 ('environment',\%changeHash,
@@ -1731,6 +1765,7 @@
                              'mddl' => "middle",
                              'lst'  => "last",
 			     'gen'  => "generation",
+                             'id'   => "ID/Student number",
                              'mail' => "permanent e-mail",
                              'disk' => "disk space allocated to portfolio files",
                              'prvs' => "Previous",
@@ -1744,6 +1779,7 @@
     <th>$lt{'mddl'}</th>
     <th>$lt{'lst'}</th>
     <th>$lt{'gen'}</th>
+    <th>$lt{'id'}</th>
     <th>$lt{'mail'}</th>
     <th>$lt{'disk'}</th></tr>
 <tr><td>$lt{'prvs'}</td>
@@ -1751,6 +1787,7 @@
     <td>$userenv{'middlename'} </td>
     <td>$userenv{'lastname'}   </td>
     <td>$userenv{'generation'} </td>
+    <td>$userenv{'id'}</td>
     <td>$userenv{'permanentemail'} </td>
     <td>$oldportfolioquota Mb</td>
 </tr>
@@ -1759,10 +1796,24 @@
     <td>$env{'form.cmiddlename'} </td>
     <td>$env{'form.clastname'}   </td>
     <td>$env{'form.cgeneration'} </td>
+    <td>$env{'form.cid'} </td>
     <td>$env{'form.cpermanentemail'} </td>
     <td>$newportfolioquota Mb $defquotatext </td></tr>
 </table>
 END
+                if (($forceid) && ($recurseid) && (!$disallowed_id) &&
+                    (&Apache::lonnet::allowed('mau',$env{'form.ccdomain'}))) {
+                    my %userupdate = (
+                                  lastname   => $env{'form.clasaname'},
+                                  middlename => $env{'form.cmiddlename'},
+                                  firstname  => $env{'form.cfirstname'},
+                                  generation => $env{'fora.cgeneration'},
+                                  id         => $env{'form.cid'},
+                             );
+                    my $idresult = &propagate_id_change($env{'form.ccname'},
+                                    $env{'form.ccdomain'},\%userupdate);
+                    $r->print('<br />'.$idresult.'<br />');
+                }
                 if (($env{'form.ccdomain'} eq $env{'user.domain'}) && 
                     ($env{'form.ccuname'} eq $env{'user.name'})) {
                     my %newenvhash;
@@ -1786,12 +1837,19 @@
             # They did not want to change the users name but we can
             # still tell them what the name is
 	    my %lt=&Apache::lonlocal::texthash(
+                           'id'   => "ID/Student number",
                            'mail' => "Permanent e-mail",
                            'disk' => "Disk space allocated to user's portfolio files",
 					       );
             $r->print(<<"END");
-<h4>$userenv{'firstname'} $userenv{'middlename'} $userenv{'lastname'} $userenv{'generation'}&nbsp;&nbsp;($lt{'mail'}: $userenv{'permanentemail'})</h4>
+<h4>$userenv{'firstname'} $userenv{'middlename'} $userenv{'lastname'} $userenv{'generation'}
 END
+            if ($userenv{'permanentemail'} eq '') {
+                $r->print('</h4>');
+            } else {
+                $r->print('&nbsp;&nbsp;('.$lt{'mail'}.': '.
+                          $userenv{'permanentemail'}.')</h4>');
+            }
             if ($putresult eq 'ok') {
                 if ($oldportfolioquota != $newportfolioquota) {
                     $r->print('<h4>'.$lt{'disk'}.': '.$newportfolioquota.' Mb '. 
@@ -1824,7 +1882,7 @@
 						 $env{'form.ccdomain'},$now);
 		    $r->print($result);
 		}
-	    } 
+	    }
 	    if ($key=~m{^form\.rev\:([^_]+)_cr\.cr/($match_domain)/($match_username)/(\w+)$}s) {
 # Revoke custom role
 		$r->print(&mt('Revoking custom role:').
@@ -2511,7 +2569,7 @@
                         $response = '';
                     }
                     &print_user_modification_page($r,$ccuname,$ccdomain,
-                                                  $srch,$response);
+                                                  $srch,$response,$context);
                 } elsif ($currstate eq 'query') {
                     &print_user_query_page($r,'createuser');
                 } else {
@@ -2521,7 +2579,8 @@
             } elsif ($env{'form.phase'} eq 'userpicked') {
                 my $ccuname = &LONCAPA::clean_username($env{'form.seluname'});
                 my $ccdomain = &LONCAPA::clean_domain($env{'form.seludom'});
-                &print_user_modification_page($r,$ccuname,$ccdomain,$srch);
+                &print_user_modification_page($r,$ccuname,$ccdomain,$srch,'',
+                                              $context);
             }
         } elsif ($env{'form.phase'} eq 'update_user_data') {
             &update_user_data($r);
Index: loncom/enrollment/Autoupdate.pl
diff -u loncom/enrollment/Autoupdate.pl:1.10 loncom/enrollment/Autoupdate.pl:1.11
--- loncom/enrollment/Autoupdate.pl:1.10	Tue Jun  5 19:23:01 2007
+++ loncom/enrollment/Autoupdate.pl	Thu Nov 15 16:24:56 2007
@@ -1,7 +1,7 @@
 #!/usr/bin/perl
 #
 # Automated Userinfo update script
-# $Id: Autoupdate.pl,v 1.10 2007/06/05 23:23:01 raeburn Exp $
+# $Id: Autoupdate.pl,v 1.11 2007/11/15 21:24:56 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -31,6 +31,7 @@
     use Apache::lonnet;
     use Apache::loncommon;
     use Apache::lonlocal;
+    use Apache::lonuserutils();
     use LONCAPA::Configuration;
     use LONCAPA;
 
@@ -135,7 +136,8 @@
                                         my ($cnum,$cdom,$role) = split(/:/,$item);
                                         my ($start,$end) = split(/:/,$roleshash{$item});
                                         if (&Apache::lonnet::is_course($cdom,$cnum)) {
-                                            my $result = &update_classlist($cdom,$cnum,$dom,$uname,\%userupdate);
+                                            my $result = 
+                                                &Apache::lonuserutils::update_classlist($cdom,$cnum,$dom,$uname,\%userupdate);
                                             if ($result eq 'ok') {
                                                 print $fh "Classlist change: $uname:$dom - class -> $cnum:$cdom\n";
                                             } else {
@@ -195,42 +197,6 @@
     }
 }
 
-sub update_classlist {
-    my ($cdom,$cnum,$udom,$uname,$user) = @_;
-    my ($uid,$fullname,$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;
-    for (my $i=0; $i<@classinfo; $i++) {
-        if ($i == $ididx) {
-            if (defined($user->{'id'})) {
-                $classlistentry .= $user->{'id'}.':';
-            } else {
-                $classlistentry .= $classinfo[$i].':';
-            }
-        } elsif ($i == $nameidx) {
-            $classlistentry .= $fullname.':';
-        } 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;
-    }
-}
-
 sub affiliations_check {
     my ($userhash,$insthashref) = @_;
     my (@inststatuses,$insttypechg);;

--raeburn1195161897--