Diff for /loncom/interface/lonuserutils.pm between versions 1.201 and 1.221

version 1.201, 2019/07/23 13:58:53 version 1.221, 2024/01/05 04:01:40
Line 50  use strict; Line 50  use strict;
 use Apache::lonnet;  use Apache::lonnet;
 use Apache::loncommon();  use Apache::loncommon();
 use Apache::lonhtmlcommon;  use Apache::lonhtmlcommon;
   use Apache::loncoursequeueadmin;
 use Apache::lonlocal;  use Apache::lonlocal;
 use Apache::longroup;  use Apache::longroup;
 use HTML::Entities;  use HTML::Entities;
Line 103  sub modifystudent { Line 104  sub modifystudent {
 sub modifyuserrole {  sub modifyuserrole {
     my ($context,$setting,$changeauth,$cid,$udom,$uname,$uid,$umode,$upass,      my ($context,$setting,$changeauth,$cid,$udom,$uname,$uid,$umode,$upass,
         $first,$middle,$last,$gene,$sec,$forceid,$desiredhome,$email,$role,          $first,$middle,$last,$gene,$sec,$forceid,$desiredhome,$email,$role,
         $end,$start,$checkid,$inststatus) = @_;          $end,$start,$checkid,$inststatus,$emptyok) = @_;
     my ($scope,$userresult,$authresult,$roleresult,$idresult);      my ($scope,$userresult,$authresult,$roleresult,$idresult);
     if ($setting eq 'course' || $context eq 'course') {      if ($setting eq 'course' || $context eq 'course') {
         $scope = '/'.$cid;          $scope = '/'.$cid;
Line 114  sub modifyuserrole { Line 115  sub modifyuserrole {
     } elsif ($context eq 'domain') {      } elsif ($context eq 'domain') {
         $scope = '/'.$env{'request.role.domain'}.'/';          $scope = '/'.$env{'request.role.domain'}.'/';
     } elsif ($context eq 'author') {      } elsif ($context eq 'author') {
         $scope =  '/'.$env{'user.domain'}.'/'.$env{'user.name'};          if ($env{'request.role'} =~ m{^ca\.(/$match_domain/$match_username)$}) {
               $scope = $1;
           } else {
               $scope =  '/'.$env{'user.domain'}.'/'.$env{'user.name'};
           }
     }      }
     if ($context eq 'domain') {      if ($context eq 'domain') {
         my $uhome = &Apache::lonnet::homeserver($uname,$udom);          my $uhome = &Apache::lonnet::homeserver($uname,$udom);
Line 134  sub modifyuserrole { Line 139  sub modifyuserrole {
                                   generation => $gene,                                    generation => $gene,
                                   id         => $uid,                                    id         => $uid,
                                  );                                   );
   
                   # When "Update ID in user's course(s)" and "Force change of existing ID"
                   # checkboxes both checked, prevent replacement of name information
                   # in classlist.db file(s) for the user's course(s) with blank(s),
                   # in the case where the uploaded csv file was without column(s) for
                   # the particular field. Fields are: First Name, Middle Names/Initials,
                   # Last Name (or the composite: Last Name, First Names), and Generation.
   
                   my %emptyallowed;
                   if ((ref($emptyok) eq 'HASH') && (keys(%{$emptyok}) > 0)) {
                       %emptyallowed = %{$emptyok};
                   }
                   foreach my $field (keys(%userupdate)) {
                       if ($userupdate{$field} eq '') {
                           unless ($emptyallowed{$field}) {
                               delete($userupdate{$field});
                           }
                       }
                   }
                 $idresult = &propagate_id_change($uname,$udom,\%userupdate);                  $idresult = &propagate_id_change($uname,$udom,\%userupdate);
             }              }
         }          }
Line 153  sub modifyuserrole { Line 177  sub modifyuserrole {
     return ($userresult,$authresult,$roleresult,$idresult);      return ($userresult,$authresult,$roleresult,$idresult);
 }  }
   
   sub role_approval {
       my ($dom,$context,$process_by,$notifydc) = @_;
       if (ref($process_by) eq 'HASH') {
           my %domconfig = &Apache::lonnet::get_dom('configuration',['privacy'],$dom);
           if (ref($domconfig{'privacy'}) eq 'HASH') {
               if (ref($notifydc) eq 'ARRAY') {
                   if ($domconfig{'privacy'}{'notify'} ne '') {
                       @{$notifydc} = split(/,/,$domconfig{'privacy'}{'notify'});
                   }
               }
               if (ref($domconfig{'privacy'}{'approval'}) eq 'HASH') {
                   my %approvalconf = %{$domconfig{'privacy'}{'approval'}};
                   foreach my $key ('instdom','extdom') {
                       if (ref($approvalconf{$key}) eq 'HASH') {
                           if (keys(%{$approvalconf{$key}})) {
                               $process_by->{$key} = $approvalconf{$key}{$context};
                           }
                       }
                   }
               }
           }
       }
       return;
   }
   
   sub get_instdoms {
       my ($udom,$instdoms) = @_;
       return unless (ref($instdoms) eq 'ARRAY');
       my @intdoms;
       my %iphost = &Apache::lonnet::get_iphost();
       my $primary_id = &Apache::lonnet::domain($udom,'primary');
       my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);
       if (ref($iphost{$primary_ip}) eq 'ARRAY') {
           foreach my $id (@{$iphost{$primary_ip}}) {
               my $intdom = &Apache::lonnet::internet_dom($id);
               unless(grep(/^\Q$intdom\E$/,@intdoms)) {
                   push(@intdoms,$intdom);
               }
           }
       }
       foreach my $ip (keys(%iphost)) {
           if (ref($iphost{$ip}) eq 'ARRAY') {
               foreach my $id (@{$iphost{$ip}}) {
                   my $location = &Apache::lonnet::internet_dom($id);
                   if ($location) {
                       if (grep(/^\Q$location\E$/,@intdoms)) {
                           my $dom = &Apache::lonnet::host_domain($id);
                           unless (grep(/^\Q$dom\E/,@{$instdoms})) {
                               push(@{$instdoms},$dom);
                           }
                       }
                   }
               }
           }
       }
       return;
   }
   
   sub restricted_dom {
       my ($context,$key,$udom,$uname,$role,$start,$end,$cdom,$cnum,$csec,$credits,
           $process_by,$instdoms,$got_role_approvals,$got_instdoms,$reject,$pending,
           $notifydc,$status,$unauthorized,$currqueued) = @_;
       return if ($udom eq $cdom);
       return unless ((ref($process_by) eq 'HASH') && (ref($instdoms) eq 'HASH') &&
                      (ref($got_role_approvals) eq 'HASH') && (ref($got_instdoms) eq 'HASH') &&
                      (ref($reject) eq 'HASH') && (ref($pending) eq 'HASH') &&
                      (ref($notifydc) eq 'HASH') && (ref($status) eq 'HASH') &&
                      (ref($unauthorized) eq 'HASH') && (ref($currqueued) eq 'HASH'));
       my (%approval,@notify,$gotdata,$skip);
       if (ref($got_role_approvals->{$context}) eq 'HASH') {
           if ($got_role_approvals->{$context}{$udom}) {
               $gotdata = 1;
               if (ref($process_by->{$context}{$udom}) eq 'HASH') {
                   %approval = %{$process_by->{$context}{$udom}};
               }
           }
       }
       unless ($gotdata) {
           &role_approval($udom,$context,\%approval,\@notify);
           $process_by->{$context} = {
                                       $udom => \%approval,
                                     };
           $got_role_approvals->{$context} = {
                                               $udom => 1,
                                             };
           $notifydc->{$udom} = \@notify;
       }
       if (ref($process_by->{$context}) eq 'HASH') {
           if (ref($process_by->{$context}{$udom}) eq 'HASH') {
               my @inst;
               if ($got_instdoms->{$udom}) {
                   if (ref($instdoms->{$udom}) eq 'ARRAY') {
                       @inst = @{$instdoms->{$udom}};
                   }
               } else {
                   &get_instdoms(\@inst);
                   $instdoms->{$udom} = \@inst;
                   $got_instdoms->{$udom} = 1;
               }
               if (grep(/^\Q$cdom\E$/,@inst)) {
                   if (exists($approval{'instdom'})) {
                       my $rule = $approval{'instdom'};
                       if (($rule eq 'none') || ($rule eq 'user') || ($rule eq 'domain')) {
                           my ($id,$currstatus,$curradj) = &get_othdomreq_status($key,$uname,$udom,$role,$cdom,$cnum,$csec);
                           if (($currstatus ne '') && ($curradj eq $rule)) {
                               $status->{$key}->{$uname.':'.$udom} = $currstatus;
                           }
                           if ($rule eq 'none') {
                                $reject->{$key}->{$uname.':'.$udom} = {
                                                                        cdom  => $cdom,
                                                                        cnum  => $cnum,
                                                                        csec  => $csec,
                                                                        udom  => $udom,
                                                                        uname => $uname,
                                                                        role  => $role,
                                                                      };
                               $skip = 1;
                           } elsif (($rule eq 'user') || ($rule eq 'domain')) {
                               if ($curradj eq $rule) {
                                   unless ($currstatus eq 'approved') {
                                       if ($currstatus eq 'rejected') {
                                           $unauthorized->{$key}->{$uname.':'.$udom} = {
                                                                                         cdom  => $cdom,
                                                                                         cnum  => $cnum,
                                                                                         csec  => $csec,
                                                                                         udom  => $udom,
                                                                                         uname => $uname,
                                                                                         role  => $role,
                                                                                       };
                                       } elsif ($currstatus eq 'pending') {
                                           $currqueued->{$key}->{$uname.':'.$udom} = {
                                                                                       cdom  => $cdom,
                                                                                       cnum  => $cnum,
                                                                                       csec  => $csec,
                                                                                       udom  => $udom,
                                                                                       uname => $uname,
                                                                                       role  => $role,
                                                                                       adj   => $rule,
                                                                          };
                                       }
                                       $skip = 1;
                                   }
                               } else {
                                   $pending->{$key}->{$uname.':'.$udom} = {
                                                                            cdom  => $cdom,
                                                                            cnum  => $cnum,
                                                                            csec  => $csec,
                                                                            udom  => $udom,
                                                                            uname => $uname,
                                                                            role  => $role,
                                                                            start => $start,
                                                                            end   => $end,
                                                                            adj   => $rule,
                                                                          };
                                   if (($role eq 'st') && ($credits ne '')) {
                                       $pending->{$key}->{$uname.':'.$udom}->{'credits'} = $credits;
                                   }
                                   $skip = 1;
                               }
                           }
                       }
                   }
               } elsif (exists($approval{'extdom'})) {
                   my $rule = $approval{'extdom'};
                   if (($rule eq 'none') || ($rule eq 'user') || ($rule eq 'domain')) {
                       my ($id,$currstatus,$curradj) = &get_othdomreq_status($key,$uname,$udom,$role,$cdom,$cnum,$csec);
                       if (($currstatus ne '') && ($curradj eq $rule)) {
                           $status->{$key}->{$uname.':'.$udom} = $currstatus;
                       }
                       if ($rule eq 'none') {
                           $reject->{$key}->{$uname.':'.$udom} = {
                                                                   cdom  => $cdom,
                                                                   cnum  => $cnum,
                                                                   csec  => $csec,
                                                                   udom  => $udom,
                                                                   uname => $uname,
                                                                   role  => $role,
                                                                 };
                           $skip = 1;
                       } elsif (($rule eq 'user') || ($rule eq 'domain')) {
                           if ($curradj eq $rule) {
                               unless ($currstatus eq 'approved') {
                                   if ($currstatus eq 'rejected') {
                                       $unauthorized->{$key}->{$uname.':'.$udom} = {
                                                                                     cdom  => $cdom,
                                                                                     cnum  => $cnum,
                                                                                     csec  => $csec,
                                                                                     udom  => $udom,
                                                                                     uname => $uname,
                                                                                     role  => $role,
                                                                                   };
                                   } elsif ($currstatus eq 'pending') {
                                       $currqueued->{$key}->{$uname.':'.$udom} = {
                                                                                   cdom  => $cdom,
                                                                                   cnum  => $cnum,
                                                                                   csec  => $csec,
                                                                                   udom  => $udom,
                                                                                   uname => $uname,
                                                                                   role  => $role,
                                                                                   adj   => $rule,
                                                                          };
                                   }
                                   $skip = 1;
                               }
                           } else {
                               $pending->{$key}->{$uname.':'.$udom} = {
                                                                        cdom  => $cdom,
                                                                        cnum  => $cnum,
                                                                        csec  => $csec,
                                                                        udom  => $udom,
                                                                        uname => $uname,
                                                                        role  => $role,
                                                                        start => $start,
                                                                        end   => $end,
                                                                        adj   => $rule,
                                                                      };
                               if (($role eq 'st') && ($credits ne '')) {
                                   $pending->{$key}->{$uname.':'.$udom}->{'credits'} = $credits;
                               }
                               $skip = 1;
                           }
                       }
                   }
               }
           }
       }
       return $skip;
   }
   
   sub get_othdomreq_status {
       my ($key,$uname,$udom,$role,$cdom,$cnum,$csec) = @_;
       my $id = $uname.':'.$udom.':'.$role; 
       my ($dbnum,$currstatus,$curradj);
       if (($role eq 'ca') || ($role eq 'aa')) {
           $dbnum = $cnum;
       } elsif ($key eq $cdom.'_'.$role) {
           $dbnum = &Apache::lonnet::get_domainconfiguser($cdom);
       } else {
           $id .= ':'.$csec;
           $dbnum = $cnum;
       }
       my $statusid = 'status&'.$id;
       my %curr = &Apache::lonnet::get('nohist_othdomqueued',[$id,$statusid],$cdom,$dbnum);
       if (ref($curr{$id}) eq 'HASH') {
           $curradj = $curr{$id}{'adj'};
       }
       $currstatus = $curr{$statusid};
       return ($id,$currstatus,$curradj);
   }
   
   sub print_roles_rejected {
       my ($context,$reject,$unauthorized) = @_;
       return unless ((ref($reject) eq 'HASH') || (ref($unauthorized) eq 'HASH'));
       my $output;
       if (keys(%{$reject}) > 0) {
           $output = '<p class="LC_warning">'.
                     &mt("The following roles could not be assigned because the user is from another domain, and that domain's policies disallow it").'<ul>';
           foreach my $key (sort(keys(%{$reject}))) {
               if (ref($reject->{$key}) eq 'HASH') {
                   foreach my $user (sort(keys(%{$reject->{$key}}))) {
                       if (ref($reject->{$key}->{$user}) eq 'HASH') {
                           my ($crstype,$role,$cdom,$cnum,$csec,$title,$plainrole);
                           $role = $reject->{$key}->{$user}{'role'};
                           $cdom = $reject->{$key}->{$user}{'cdom'};
                           $cnum = $reject->{$key}->{$user}{'cnum'};
                           $csec = $reject->{$key}->{$user}{'csec'};
                           if (($context eq 'domain') && ($cnum ne '')) {
                               if (($role eq 'ca') || ($role eq 'aa')) {
                                   $title = &Apache::loncommon::plainname($cnum,$cdom);
                               } else {
                                   if (&Apache::lonnet::is_course($cdom,$cnum)) {
                                       my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                                       $crstype = $coursedata{'type'};
                                       $title = $coursedata{'description'};
                                   }
                               }
                           } elsif ($context eq 'course') {
                               $crstype = &Apache::loncommon::course_type();
                           }
                           my $plainrole = &Apache::lonnet::plaintext($role,$crstype);
                           $output .= '<li>'.&mt('User: [_1]',$reject->{$key}->{$user}{'uname'}).' | '.
                                             &mt('Domain: [_1]',$reject->{$key}->{$user}{'udom'}).' | '.
                                             &mt('Role: [_1]',$plainrole);
                           if ($crstype) {
                               if ($csec ne'') {
                                   $output .= ' | '.&mt('Section: [_1]',$csec);
                               }
                           } elsif (($context eq 'domain') && (($role eq 'ca') || ($role eq 'aa'))) {
                               $output .= ' | '.&mt('Authoring Space belonging to: [_1]',$title);
                                                   
                           }
                           if (($context eq 'domain') && ($crstype)) {
                               $output .= ' | '.&mt("$crstype: [_1]",$title);
                           }
                           $output .= '</li>';
                       }
                   }
               }
           }
           $output .= '</ul></p>';
       }
       if (keys(%{$unauthorized}) > 0) {
           $output = '<p class="LC_warning">'.
                     &mt("The following roles could not be assigned because the user is from another domain, and that domain's policies require approval by the user themselves or by a domain coordinator in that domain, and approval has been withheld.").'<ul>';
           foreach my $key (sort(keys(%{$unauthorized}))) {
               if (ref($unauthorized->{$key}) eq 'HASH') {
                   foreach my $user (sort(keys(%{$unauthorized->{$key}}))) {
                       if (ref($unauthorized->{$key}->{$user}) eq 'HASH') {
                           my ($crstype,$role,$cdom,$cnum,$csec,$title,$plainrole);
                           $role = $unauthorized->{$key}->{$user}{'role'};
                           $cdom = $unauthorized->{$key}->{$user}{'cdom'};
                           $cnum = $unauthorized->{$key}->{$user}{'cnum'};
                           $csec = $unauthorized->{$key}->{$user}{'csec'};
                           if (($context eq 'domain') && ($cnum ne '')) {
                               if (($role eq 'ca') || ($role eq 'aa')) {
                                   $title = &mt('Authoring Space belonging to: [_1]',
                                                &Apache::loncommon::plainname($cnum,$cdom));
                               } else {
                                   if (&Apache::lonnet::is_course($cdom,$cnum)) {
                                       my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                                       $crstype = $coursedata{'type'};
                                       $title = &mt("$crstype: [_1]",$coursedata{'description'});
                                   }
                               }
                           } elsif ($context eq 'course') {
                               $crstype = &Apache::loncommon::course_type();
                           }
                           $plainrole = &Apache::lonnet::plaintext($role,$crstype);
                           $output .= '<li>'.&mt('User: [_1]',$unauthorized->{$key}->{$user}{'uname'}).' | '.
                                             &mt('Domain: [_1]',$unauthorized->{$key}->{$user}{'udom'}).' | '.
                                             &mt('Role: [_1]',$plainrole);
                           if ($crstype) {
                               if ($csec ne'') {
                                   $output .= ' | '.&mt('Section: [_1]',$csec);
                               }
                           }
                           if ($title ne '') {
                               $output .= ' | '.$title;
                           }
                           $output .= '</li>';
                       }
                   }
               }
           }
           $output .= '</ul></p>'; 
       }
       return $output;
   }
   
   sub print_roles_queued {
       my ($context,$pending,$notifydc,$currqueued) = @_;
       return unless ((ref($pending) eq 'HASH') && (ref($notifydc) eq 'HASH') &&
                      (ref($currqueued) eq 'HASH'));
       my $output;
       if (keys(%{$pending}) > 0) {
           my $now = time;
           $output = '<p class="LC_warning">'.
                     &mt("The following role assignments have been queued because the user is from another domain, and that domain's policies require approval by the user themselves or by a domain coordinator in that domain").'<ul>';
           my (%todom,%touser,%crsqueue,%caqueue,%domqueue);
           my $requester = $env{'user.name'}.':'.$env{'user.domain'};
           foreach my $key (sort(keys(%{$pending}))) {
               if (ref($pending->{$key}) eq 'HASH') {
                   foreach my $user (sort(keys(%{$pending->{$key}}))) {
                       if (ref($pending->{$key}->{$user}) eq 'HASH') {
                           my $role = $pending->{$key}->{$user}{'role'};
                           my $uname = $pending->{$key}->{$user}{'uname'};
                           my $udom = $pending->{$key}->{$user}{'udom'};
                           my $csec = $pending->{$key}->{$user}{'csec'};
                           my $cdom = $pending->{$key}->{$user}{'cdom'};
                           my $cnum = $pending->{$key}->{$user}{'cnum'};
                           my $adj = $pending->{$key}->{$user}{'adj'};
                           my $start = $pending->{$key}->{$user}{'start'};
                           my $end = $pending->{$key}->{$user}{'end'};
                           my $credits = $pending->{$key}->{$user}{'credits'};
                           my $now = time;
                           my ($crstype,$title,$plainrole,$extent,$id,$status);
                           if ($context eq 'course') {
                               $crstype = &Apache::loncommon::course_type();
                               $title = $env{'course.'.$env{'request.course.id'}.'.description'};
                           } elsif ($context eq 'domain') {
                               if (&Apache::lonnet::is_course($cdom,$cnum)) {
                                   my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                                   $crstype = $coursedata{'type'};
                                   $title = $coursedata{'description'};
                               } elsif (($role eq 'ca') || ($role eq 'aa')) {
                                   $title = &Apache::loncommon::plainname($cnum,$cdom);
                               }
                           }
                           $plainrole = &Apache::lonnet::plaintext($role,$crstype);
                           $extent = "/$cdom/$cnum";
                           $id = $uname.':'.$udom.':'.$role;
                           if (($context eq 'course') || ($crstype)) {
                               $id .= ':'.$csec;
                           }
                           $output .= '<li>'.&mt('User: [_1]',$uname).' | '.
                                             &mt('Domain: [_1]',$udom).' | '.
                                             &mt('Role: [_1]',$plainrole);
                           if ($crstype) {
                               if ($csec ne'') {
                                   $output .= ' | '.&mt('Section: [_1]',$csec);
                               }
                           } elsif (($context eq 'domain') && (($role eq 'ca') || ($role eq 'aa'))) {
                               $output .= ' | '.&mt('Authoring Space belonging to: [_1]',$title);
                           }
                           if (($context eq 'domain') && ($crstype)) {
                               $output .= ' | '.&mt("$crstype: [_1]",$title);
                           }
                           if (($crstype) && ($csec ne '')) {
                               $extent .= "/$csec";
                           }
                           if ($adj eq 'user') {
                               $output .= '<br />'.&mt('Message sent to user for approval');
                               $touser{$uname.':'.$udom}{'pending:'.$extent.':'.$role} = {
                                                                                           timestamp => $now,
                                                                                           requester => $requester,
                                                                                           start     => $start,
                                                                                           end       => $end,
                                                                                           credits   => $credits,
                                                                                           context   => $context,
                                                                                         };
                           } elsif ($adj eq 'domain') {
                               $output .= '<br />'.&mt("Message sent to user's domain coordinator for approval");
                               $todom{$udom}{'pending:'.$uname.':'.$extent.':'.$role} = {
                                                                                          timestamp => $now,
                                                                                          requester => $requester,
                                                                                          start     => $start,
                                                                                          end       => $end,
                                                                                          credits   => $credits,
                                                                                          context   => $context,
                                                                                        };
                           }
                           $output .= '</li>';
                           if (($context eq 'course') || ($crstype)) {
                               $crsqueue{$cdom.'_'.$cnum}{$id} = {
                                                                   timestamp => $now,
                                                                   requester => $requester,
                                                                   adj       => $adj,
                                                                 };
                               $crsqueue{$cdom.'_'.$cnum}{'status&'.$id} = 'pending';
                           } elsif (($context eq 'author') ||
                                    (($context eq 'domain') && (($role eq 'ca') || ($role eq 'aa')))) {
                               $caqueue{$cnum.':'.$cdom}{$id} = {
                                                                  timestamp => $now,
                                                                  requester => $requester,
                                                                  adj       => $adj,
                                                                };
                               $caqueue{$cnum.':'.$cdom}{'status&'.$id} = 'pending';
                           } elsif ($context eq 'domain') {
                               $domqueue{$id} = {
                                                  timestamp => $now,
                                                  requester => $requester,
                                                  adj       => $adj,
                                                };
                               $domqueue{'status&'.$id} = 'pending';
                           }
                       }
                   }
               }
           }
           $output .= '</ul></p>';
           if (keys(%touser)) {
               foreach my $key (keys(%touser)) {
                   my ($uname,$udom) = split(/:/,$key);
                   if (&Apache::lonnet::put('nohist_queuedrolereqs',$touser{$key},$udom,$uname) eq 'ok') {
                       my $owndomdesc = &Apache::lonnet::domain($udom);
                       &Apache::loncoursequeueadmin::send_selfserve_notification($uname.':'.$udom,
                           '','',$owndomdesc,$now,'othdomroleuser',$requester);
                   }
               }
           }
           if (keys(%todom)) {
               foreach my $dom (keys(%todom)) {
                   if (ref($todom{$dom}) eq 'HASH') {
                       my $confname = &Apache::lonnet::get_domainconfiguser($dom);
                       if (&Apache::lonnet::put('nohist_queuedrolereqs',$todom{$dom},$dom,$confname) eq 'ok') {
                           if (ref($notifydc->{$dom}) eq 'ARRAY') {
                               if (@{$notifydc->{$dom}} > 0) {
                                   my $notifylist = join(',',@{$notifydc->{$dom}});
                                   &Apache::loncoursequeueadmin::send_selfserve_notification($notifylist,
                                       '','','',$now,'othdomroledc',$requester);
                               }
                           }
                       }
                   }
               }
           }
           if (keys(%crsqueue)) {
               foreach my $key (keys(%crsqueue)) {
                   my ($cdom,$cnum) = split(/_/,$key);
                   if (ref($crsqueue{$key}) eq 'HASH') {
                       &Apache::lonnet::put('nohist_othdomqueued',$crsqueue{$key},$cdom,$cnum);
                   }
               }
           }
           if (keys(%caqueue)) {
               foreach my $key (keys(%caqueue)) {
                   my ($auname,$audom) = split(/:/,$key);
                   if (ref($caqueue{$key}) eq 'HASH') {
                       &Apache::lonnet::put('nohist_othdomqueued',$caqueue{$key},$audom,$auname);
                   }
               }
           }
           if (keys(%domqueue)) {
               my $confname = &Apache::lonnet::get_domainconfiguser($env{'request.role.domain'});
               &Apache::lonnet::put('nohist_othdomqueued',\%domqueue,$env{'request.role.domain'},$confname);
           }
       }
       if (keys(%{$currqueued}) > 0) {
           $output = '<p class="LC_warning">'.
                     &mt("The following role assignments were already queued because the user is from another domain, and that domain's policies require approval by the user themselves or by a domain coordinator in that domain").'<ul>';
           my $requester = $env{'user.name'}.':'.$env{'user.domain'};
           foreach my $key (sort(keys(%{$currqueued}))) {
               if (ref($currqueued->{$key}) eq 'HASH') {
                   foreach my $user (sort(keys(%{$currqueued->{$key}}))) {
                       if (ref($currqueued->{$key}->{$user}) eq 'HASH') {
                           my $role = $currqueued->{$key}->{$user}{'role'};
                           my $csec = $currqueued->{$key}->{$user}{'csec'};
                           my $cdom = $currqueued->{$key}->{$user}{'cdom'};
                           my $cnum = $currqueued->{$key}->{$user}{'cnum'};
                           my ($crstype,$title,$plainrole);
                           if ($context eq 'course') {
                               $crstype = &Apache::loncommon::course_type();
                           } elsif (($context eq 'domain') && ($cnum ne '')) {
                               if (($role eq 'ca') || ($role eq 'aa')) {
                                   $title = &mt('Authoring Space belonging to: [_1]',
                                                &Apache::loncommon::plainname($cnum,$cdom));
                               } elsif (&Apache::lonnet::is_course($cdom,$cnum)) {
                                   my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                                   $crstype = $coursedata{'type'};
                                   $title = &mt("$crstype: [_1]",$coursedata{'description'});
                               }
                           }
                           $plainrole = &Apache::lonnet::plaintext($role,$crstype);
                           $output .= '<li>'.&mt('User: [_1]',$currqueued->{$key}->{$user}{'uname'}).' | '.
                                             &mt('Domain: [_1]',$currqueued->{$key}->{$user}{'udom'}).' | '.
                                             &mt('Role: [_1]',$plainrole);
                           if ($title ne '') {
                               $output .= ' | '.$title;
                           }
                           if ($crstype) {
                               if ($csec ne '') {
                                   $output .= ' | '.&mt('Section: [_1]',$csec);
                               }
                           }
                           $output .= '</li>';
                       }
                   }
               }
           }
           $output .= '</ul></p>';
       }
       return $output;
   }
   
 sub propagate_id_change {  sub propagate_id_change {
     my ($uname,$udom,$user) = @_;      my ($uname,$udom,$user) = @_;
     my (@types,@roles);      my (@types,@roles);
Line 510  END Line 1088  END
 ";  ";
     } elsif ($mode eq 'modifycourse') {      } elsif ($mode eq 'modifycourse') {
         $auth_checks .= "          $auth_checks .= "
     if (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '') {      if ((current.argfield !== null) && (current.argfield !== undefined) && (current.argfield !== '') && (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '')) {
 ";  ";
     }      }
     if ( ($mode eq 'createcourse') || ($mode eq 'modifycourse') ) {      if ( ($mode eq 'createcourse') || ($mode eq 'modifycourse') ) {
Line 532  END Line 1110  END
 END  END
     } else {      } else {
         my ($numrules,$intargjs) =          my ($numrules,$intargjs) =
             &passwd_validation_js('vf.elements[current.argfield].value',$domain);              &Apache::loncommon::passwd_validation_js('vf.elements[current.argfield].value',$domain);
         $auth_checks .= (<<END);          $auth_checks .= (<<END);
     foundatype=1;      foundatype=1;
     if (current.argfield == null || current.argfield == '') {      if (current.argfield == null || current.argfield == '') {
Line 543  END Line 1121  END
             case 'krb':              case 'krb':
                 alertmsg = '$alert{'krb'}';                  alertmsg = '$alert{'krb'}';
                 break;                  break;
             case 'loc':  
             case 'int':              case 'int':
                 alertmsg = '$alert{'ipass'}';                  alertmsg = '$alert{'ipass'}';
                 break;                  break;
             case 'fsys':              case 'fsys':
                 alertmsg = '$alert{'ipass'}';                  alertmsg = '$alert{'ipass'}';
                 break;                  break;
               case 'loc':
                   alertmsg = '';
                   break;
             case 'lti':              case 'lti':
             default:              default:
                 alertmsg = '';                  alertmsg = '';
Line 651  END Line 1231  END
     return $result;      return $result;
 }  }
   
 sub passwd_validation_js {  
     my ($currpasswdval,$domain) = @_;  
     my %passwdconf = &Apache::lonnet::get_passwdconf($domain);  
     my ($min,$max,@chars,$numrules,$intargjs,%alert);  
     $numrules = 0;  
     if (ref($passwdconf{'chars'}) eq 'ARRAY') {  
         if ($passwdconf{'min'} =~ /^\d+$/) {  
             $min = $passwdconf{'min'};  
             $numrules ++;  
         }  
         if ($passwdconf{'max'} =~ /^\d+$/) {  
             $max = $passwdconf{'max'};  
             $numrules ++;  
         }  
         @chars = @{$passwdconf{'chars'}};  
         if (@chars) {  
             $numrules ++;  
         }  
     } else {  
         $min = 7;  
         $numrules ++;  
     }  
     if (($min ne '') || ($max ne '') || (@chars > 0)) {  
         my $alertmsg = &mt('Initial password did not satisfy requirement(s):').'\n\n';  
         if ($min) {  
             $alert{'min'} = &mt('minimum [quant,_1,character]',$min).'\n';  
         }  
         if ($max) {  
             $alert{'max'} = &mt('maximum [quant,_1,character]',$max).'\n';  
         }  
         my (@charalerts,@charrules);  
         if (@chars) {  
             if (grep(/^uc$/,@chars)) {  
                 push(@charalerts,&mt('contain at least one upper case letter'));  
                 push(@charrules,'uc');  
             }  
             if (grep(/^lc$/,@chars)) {  
                 push(@charalerts,&mt('contain at least one lower case letter'));  
                 push(@charrules,'lc');  
             }  
             if (grep(/^num$/,@chars)) {  
                 push(@charalerts,&mt('contain at least one number'));  
                 push(@charrules,'num');  
             }  
             if (grep(/^spec$/,@chars)) {  
                 push(@charalerts,&mt('contain at least one non-alphanumeric'));  
                 push(@charrules,'spec');  
             }  
         }  
         $intargjs = qq|            var rulesmsg = '';\n|.  
                     qq|            var currpwval = $currpasswdval;\n|;  
             if ($min) {  
                 $intargjs .= qq|  
             if (currpwval.length < $min) {  
                 rulesmsg += ' - $alert{min}';  
             }  
 |;  
             }  
             if ($max) {  
                 $intargjs .= qq|  
             if (currpwval.length > $max) {  
                 rulesmsg += ' - $alert{max}';  
             }  
 |;  
             }  
             if (@chars > 0) {  
                 my $charrulestr = '"'.join('","',@charrules).'"';  
                 my $charalertstr = '"'.join('","',@charalerts).'"';  
                 $intargjs .= qq|            var brokerules = new Array();\n|.  
                              qq|            var charrules = new Array($charrulestr);\n|.  
                              qq|            var charalerts = new Array($charalertstr);\n|;  
                 my %rules;  
                 map { $rules{$_} = 1; } @chars;  
                 if ($rules{'uc'}) {  
                     $intargjs .= qq|  
             var ucRegExp = /[A-Z]/;  
             if (!ucRegExp.test(currpwval)) {  
                 brokerules.push('uc');  
             }  
 |;  
                 }  
                 if ($rules{'lc'}) {  
                     $intargjs .= qq|  
             var lcRegExp = /[a-z]/;  
             if (!lcRegExp.test(currpwval)) {  
                 brokerules.push('lc');  
             }  
 |;  
                 }  
                 if ($rules{'num'}) {  
                      $intargjs .= qq|  
             var numRegExp = /[0-9]/;  
             if (!numRegExp.test(currpwval)) {  
                 brokerules.push('num');  
             }  
 |;  
                 }  
                 if ($rules{'spec'}) {  
                      $intargjs .= q|  
             var specRegExp = /[!"#$%&'()*+,\-.\/:;<=>?@[\\^\]_`{\|}~]/;  
             if (!specRegExp.test(currpwval)) {  
                 brokerules.push('spec');  
             }  
 |;  
                 }  
                 $intargjs .= qq|  
             if (brokerules.length > 0) {  
                 for (var i=0; i<brokerules.length; i++) {  
                     for (var j=0; j<charrules.length; j++) {  
                         if (brokerules[i] == charrules[j]) {  
                             rulesmsg += ' - '+charalerts[j]+'\\n';  
                             break;  
                         }  
                     }  
                 }  
             }  
 |;  
             }  
             $intargjs .= qq|  
             if (rulesmsg != '') {  
                 rulesmsg = '$alertmsg'+rulesmsg;  
                 alert(rulesmsg);  
                 return false;  
             }  
 |;  
     }  
     return ($numrules,$intargjs);  
 }  
   
 ###############################################################  ###############################################################
 ###############################################################  ###############################################################
 sub upload_manager_javascript_forward_associate {  sub upload_manager_javascript_forward_associate {
Line 1620  sub construction_space_roles { Line 2071  sub construction_space_roles {
         foreach my $role (@allroles) {          foreach my $role (@allroles) {
             if (&Apache::lonnet::allowed('c'.$role,$env{'user.domain'}.'/'.$env{'user.name'})) {               if (&Apache::lonnet::allowed('c'.$role,$env{'user.domain'}.'/'.$env{'user.name'})) { 
                 push(@roles,$role);                   push(@roles,$role); 
               } elsif ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$}) {
                   my ($audom,$auname) = ($1,$2);
                   if (($role eq 'ca') || ($role eq 'aa')) {
                       if ((&Apache::lonnet::allowed('v'.$role,,$audom.'/'.$auname)) &&
                           ($env{"environment.internal.manager./$audom/$auname"})) {
                           push(@roles,$role);
                       }
                   }
             }              }
         }          }
         return @roles;          return @roles;
Line 1707  sub my_custom_roles { Line 2166  sub my_custom_roles {
     my %rolehash=&Apache::lonnet::dump('roles',$udom,$uname);      my %rolehash=&Apache::lonnet::dump('roles',$udom,$uname);
     foreach my $key (keys(%rolehash)) {      foreach my $key (keys(%rolehash)) {
         if ($key=~/^rolesdef\_(\w+)$/) {          if ($key=~/^rolesdef\_(\w+)$/) {
               my $role = $1;
             if ($crstype eq 'Community') {              if ($crstype eq 'Community') {
                 next if ($rolehash{$key} =~ /bre\&S/);                   next if ($rolehash{$key} =~ /bre\&S/); 
             }              }
             $returnhash{$1}=$1;              $returnhash{$role}=$role;
         }          }
     }      }
     return %returnhash;      return %returnhash;
Line 1723  sub print_userlist { Line 2183  sub print_userlist {
     if (! exists($env{'form.sortby'})) {      if (! exists($env{'form.sortby'})) {
         $env{'form.sortby'} = 'username';          $env{'form.sortby'} = 'username';
     }      }
       my ($showstart,$showend);
       if (($env{'form.Status'} eq '') && ($env{'form.phase'} eq '') &&
           ($env{'form.showrole'} eq '') && ($context eq 'course') &&
           ($env{'request.course.id'} ne '') &&
           ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'} ne '')) {
           my $now = time;
           my $startaccess = $env{'course.'.$env{'request.course.id'}.'.default_enrollment_start_date'};
           my $endaccess = $env{'course.'.$env{'request.course.id'}.'.default_enrollment_end_date'};
           if (($startaccess) && ($startaccess > $now)) {
               $env{'form.Status'} = 'Future';
               $showstart = 1;
           }
           if (($endaccess ne '') && ($endaccess != 0) && ($endaccess < $now)) {
               $env{'form.Status'} = 'Expired';
               undef($showstart);
               $showend = 1;
           }
       }
     if ($env{'form.Status'} !~ /^(Any|Expired|Active|Future)$/) {      if ($env{'form.Status'} !~ /^(Any|Expired|Active|Future)$/) {
         $env{'form.Status'} = 'Active';          $env{'form.Status'} = 'Active';
     }      }
Line 1790  sub print_userlist { Line 2268  sub print_userlist {
         $r->print(&section_group_filter($cnum,$cdom));          $r->print(&section_group_filter($cnum,$cdom));
     }      }
     $r->print('</div><div class="LC_left_float">'.      $r->print('</div><div class="LC_left_float">'.
               &column_checkboxes($context,$mode,$formname,$showcredits).                &column_checkboxes($context,$mode,$formname,$showcredits,$showstart,$showend).
               '</div>');                '</div>');
     if ($env{'form.phase'} eq '') {      if ($env{'form.phase'} eq '') {
         $r->print('<br clear="all" />'.          $r->print('<br clear="all" />'.
Line 1876  sub print_userlist { Line 2354  sub print_userlist {
     } else {      } else {
         my (%cstr_roles,%dom_roles);          my (%cstr_roles,%dom_roles);
         if ($context eq 'author') {          if ($context eq 'author') {
             # List co-authors and assistant co-authors  
             my @possroles = &roles_by_context($context);              my @possroles = &roles_by_context($context);
             %cstr_roles = &Apache::lonnet::get_my_roles(undef,undef,undef,              my @allowedroles;
                                               \@statuses,\@possroles);              # List co-authors and assistant co-authors
             &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo,              my ($auname,$audom);
                              \%cstr_roles,$permission);              if ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$}) {
                   ($audom,$auname) = ($1,$2);
                   foreach my $role (@possroles) {
                       if ((&Apache::lonnet::allowed('v'.$role,"$audom/$auname")) ||
                           (&Apache::lonnet::allowed('c'.$role,"$audom/$auname"))) {
                           push(@allowedroles,$role);
                       }
                   }
               } elsif ($env{'request.role'} =~ m{^au\./($match_domain)/}) {
                   if ($1 eq $env{'user.domain'}) {
                       $auname = $env{'user.name'};
                       $audom = $env{'user.domain'};
                   }
                   @allowedroles = @possroles;
               }
               if (($auname ne '') && ($audom ne '')) {
                   %cstr_roles = &Apache::lonnet::get_my_roles($auname,$audom,undef,
                                                               \@statuses,\@allowedroles);
                   &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo,
                                    \%cstr_roles,$permission);
               }
         } elsif ($context eq 'domain') {          } elsif ($context eq 'domain') {
             if ($env{'form.roletype'} eq 'domain') {              if ($env{'form.roletype'} eq 'domain') {
                 if (grep(/^authorusage$/,@cols)) {                  if (grep(/^authorusage$/,@cols)) {
Line 2172  sub get_cols_array { Line 2669  sub get_cols_array {
             push(@cols,'photo');              push(@cols,'photo');
         }          }
         if ($context eq 'domain') {          if ($context eq 'domain') {
             push (@cols,('authorusage','authorquota','extent'));              push(@cols,('authorusage','authorquota','extent'));
           }
           if ($context eq 'author') {
               push(@cols,'manager');
         }          }
     }      }
     return @cols;      return @cols;
 }  }
   
 sub column_checkboxes {  sub column_checkboxes {
     my ($context,$mode,$formname,$showcredits) = @_;      my ($context,$mode,$formname,$showcredits,$showstart,$showend) = @_;
     my @cols = &get_cols_array($context,$mode,$showcredits);      my @cols = &get_cols_array($context,$mode,$showcredits);
     my @showncols = &Apache::loncommon::get_env_multiple('form.showcol');      my @showncols = &Apache::loncommon::get_env_multiple('form.showcol');
     my (%disabledchk,%unchecked);      my (%disabledchk,%unchecked);
Line 2192  sub column_checkboxes { Line 2692  sub column_checkboxes {
             if ($showcredits) {              if ($showcredits) {
                 $unchecked{'credits'} = 1;                  $unchecked{'credits'} = 1;
             }              }
         } elsif ($context eq 'domain') {               my %curr_groups = &Apache::longroup::coursegroups();
               unless (keys(%curr_groups)) {
                   $unchecked{'groups'} = 1;
               }
           } elsif ($context eq 'domain') {
             $unchecked{'extent'} = 1;               $unchecked{'extent'} = 1; 
         }          }
         $unchecked{'start'} = 1;          if ($showstart) {
         $unchecked{'end'} = 1;              $unchecked{'lastlogin'} = 1;
           } else {
               $unchecked{'start'} = 1;
           }
           unless ($showend) {
               $unchecked{'end'} = 1;
           }
     } else {      } else {
         if ($env{'form.Status'} ne 'Any') {          if ($env{'form.Status'} ne 'Any') {
             $disabledchk{'status'} = 1;              $disabledchk{'status'} = 1;
Line 2213  sub column_checkboxes { Line 2723  sub column_checkboxes {
             } elsif ($env{'form.roletype'} eq 'domain') {              } elsif ($env{'form.roletype'} eq 'domain') {
                 $disabledchk{'extent'} = 1;                   $disabledchk{'extent'} = 1; 
             }              }
           } elsif ($context eq 'author') {
               if (($env{'form.Status'} eq 'Expired') ||
                   ($env{'form.showrole'} eq 'aa')) {
                   $disabledchk{'manager'} = 1;
               }
         }          }
     }      }
     my $numposs = scalar(@cols);      my $numposs = scalar(@cols);
Line 2304  sub get_column_names { Line 2819  sub get_column_names {
         'ca'         => "check all",          'ca'         => "check all",
         'ua'         => "uncheck all",          'ua'         => "uncheck all",
         'clicker'    => "clicker-ID",          'clicker'    => "clicker-ID",
           'manager'    => "co-author manager",
     );      );
     if ($context eq 'domain' && $env{'form.roletype'} eq 'course') {      if ($context eq 'domain' && $env{'form.roletype'} eq 'course') {
         $lt{'extent'} = &mt('course(s): description, section(s), status');          $lt{'extent'} = &mt('course(s): description, section(s), status');
Line 2588  sub make_keylist_array { Line 3104  sub make_keylist_array {
     $index->{'instsec'} = &Apache::loncoursedata::CL_INSTSEC();      $index->{'instsec'} = &Apache::loncoursedata::CL_INSTSEC();
     $index->{'authorquota'} = &Apache::loncoursedata::CL_AUTHORQUOTA();      $index->{'authorquota'} = &Apache::loncoursedata::CL_AUTHORQUOTA();
     $index->{'authorusage'} = &Apache::loncoursedata::CL_AUTHORUSAGE();      $index->{'authorusage'} = &Apache::loncoursedata::CL_AUTHORUSAGE();
       $index->{'manager'} = &Apache::loncoursedata::CL_CAMANAGER();
     foreach my $key (keys(%{$index})) {      foreach my $key (keys(%{$index})) {
         $keylist->[$index->{$key}] = $key;          $keylist->[$index->{$key}] = $key;
     }      }
Line 2662  sub show_users_list { Line 3179  sub show_users_list {
             (($env{'form.showrole'} eq 'Any') || ($env{'form.showrole'} eq 'au'))) {              (($env{'form.showrole'} eq 'Any') || ($env{'form.showrole'} eq 'au'))) {
             push(@sortable,('authorusage','authorquota'));              push(@sortable,('authorusage','authorquota'));
         }          }
           if ($context eq 'author') {
               push(@sortable,'manager');
           }
     }      }
     if ($mode eq 'pickauthor') {      if ($mode eq 'pickauthor') {
         @sortable = ('username','fullname','email','status');          @sortable = ('username','fullname','email','status');
Line 2979  END Line 3499  END
     foreach my $idx (@$keylist) {      foreach my $idx (@$keylist) {
         $index{$idx} = $i++;          $index{$idx} = $i++;
     }      }
       my $now = time;
     my $usercount = 0;      my $usercount = 0;
     my ($secfilter,$grpfilter);      my ($secfilter,$grpfilter);
     if ($context eq 'course') {      if ($context eq 'course') {
Line 2996  END Line 3517  END
                                                 Future  => 'Future',                                                  Future  => 'Future',
                                                 Expired => 'Expired',                                                  Expired => 'Expired',
                                                );                                                 );
     # If this is for a single course get last course "log-in".      my (%crslogins,%camanagers);
     my %crslogins;  
     if ($context eq 'course') {      if ($context eq 'course') {
           # If this is for a single course get last course "log-in".
         %crslogins=&Apache::lonnet::dump('nohist_crslastlogin',$cdom,$cnum);          %crslogins=&Apache::lonnet::dump('nohist_crslastlogin',$cdom,$cnum);
       } elsif ($context eq 'author') {
           map { $camanagers{$_.':ca'} = 1; } split(/,/,$env{'environment.authormanagers'});
     }      }
     # Get groups, role, permanent e-mail so we can sort on them if      # Get groups, role, permanent e-mail so we can sort on them if
     # necessary.      # necessary.
Line 3099  END Line 3622  END
                 }                  }
             }              }
         }          }
           if ($context eq 'author') {
               if (($camanagers{$user}) &&
                   ((!defined($userlist->{$user}->[$index{'end'}])) ||
                    ($userlist->{$user}->[$index{'end'}] == 0) ||
                    ($userlist->{$user}->[$index{'end'}] > $now))) {
                   $userlist->{$user}->[$index{'manager'}] = &mt('Yes');
               } else {
                   $userlist->{$user}->[$index{'manager'}] = &mt('No');
               }
           }
         my %emails   = &Apache::loncommon::getemails($uname,$udom);          my %emails   = &Apache::loncommon::getemails($uname,$udom);
         if ($emails{'permanentemail'} =~ /\S/) {          if ($emails{'permanentemail'} =~ /\S/) {
             $userlist->{$user}->[$index{'email'}] = $emails{'permanentemail'};              $userlist->{$user}->[$index{'email'}] = $emails{'permanentemail'};
Line 3667  END Line 4200  END
         setSections(formname,'$crstype');          setSections(formname,'$crstype');
         if (seccheck == 'ok') {          if (seccheck == 'ok') {
             opener.document.$callingform.newsecs.value = formname.sections.value;              opener.document.$callingform.newsecs.value = formname.sections.value;
           } else {
               return;
         }          }
 END  END
     } else {      } else {
Line 4292  sub upfile_drop_add { Line 4827  sub upfile_drop_add {
         $fieldstype{$field.'_choice'} = 'scalar';          $fieldstype{$field.'_choice'} = 'scalar';
     }      }
     &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype);      &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype);
     my ($cid,$crstype,$setting,$crsdom);      my ($cid,$crstype,$setting,$crsdom,$crsnum,$oldcrsuserdoms,%emptyok);
     if ($context eq 'domain') {      if ($context eq 'domain') {
         $setting = $env{'form.roleaction'};          $setting = $env{'form.roleaction'};
           if (exists($fields{'names'})) {
               map { $emptyok{$_} = 1; } ('lastname','firstname','middlename');
           } else {
               if (exists($fields{'lname'})) {
                   $emptyok{'lastname'} = 1;
               }
               if (exists($fields{'fname'})) {
                   $emptyok{'firstname'} = 1;
               }
               if (exists($fields{'mname'})) {
                   $emptyok{'middlename'} = 1;
               }
           }
           if (exists($fields{'gen'})) {
               $emptyok{'generation'} = 1;
           }
     }      }
     if ($env{'request.course.id'} ne '') {      if ($env{'request.course.id'} ne '') {
         $cid = $env{'request.course.id'};          $cid = $env{'request.course.id'};
         $crstype = &Apache::loncommon::course_type();          $crstype = &Apache::loncommon::course_type();
         $crsdom = $env{'course.'.$env{'request.course.id'}.'.domain'};          $crsdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
           $crsnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     } elsif ($setting eq 'course') {      } elsif ($setting eq 'course') {
         if (&Apache::lonnet::is_course($env{'form.dcdomain'},$env{'form.dccourse'})) {          if (&Apache::lonnet::is_course($env{'form.dcdomain'},$env{'form.dccourse'})) {
             $cid = $env{'form.dcdomain'}.'_'.$env{'form.dccourse'};              $cid = $env{'form.dcdomain'}.'_'.$env{'form.dccourse'};
             $crstype = &Apache::loncommon::course_type($cid);              $crstype = &Apache::loncommon::course_type($cid);
             $crsdom = $env{'form.dcdomain'};              $crsdom = $env{'form.dcdomain'};
               $crsnum = $env{'form.dccourse'};
               if (exists($env{'course.'.$cid.'.internal.userdomains'})) {
                   $oldcrsuserdoms = 1;
               }
               my %coursedesc = &Apache::lonnet::coursedescription($cid,{ one_time => 1 });
               $env{'course.'.$cid.'.internal.userdomains'} = $coursedesc{'internal.userdomains'};
         }          }
     }      }
     my ($startdate,$enddate) = &get_dates_from_form();      my ($startdate,$enddate) = &get_dates_from_form();
Line 4387  sub upfile_drop_add { Line 4945  sub upfile_drop_add {
         if ((defined($env{'form.intarg'})) && ($env{'form.intarg'})) {          if ((defined($env{'form.intarg'})) && ($env{'form.intarg'})) {
             $genpwd=$env{'form.intarg'};              $genpwd=$env{'form.intarg'};
             @genpwdfail =              @genpwdfail =
                 &Apache::loncommon::check_passwd_rules($domain,$genpwd);                   &Apache::loncommon::check_passwd_rules($domain,$genpwd);
         }          }
     } elsif ($env{'form.login'} eq 'loc') {      } elsif ($env{'form.login'} eq 'loc') {
         $amode='localauth';          $amode='localauth';
Line 4489  sub upfile_drop_add { Line 5047  sub upfile_drop_add {
             $r->print('<h3>'.&mt('Adding/Modifying Users')."</h3>\n<p>\n");              $r->print('<h3>'.&mt('Adding/Modifying Users')."</h3>\n<p>\n");
         }          }
         $r->rflush;          $r->rflush;
           my (%got_role_approvals,%got_instdoms,%process_by,%instdoms,
               %pending,%reject,%notifydc,%status,%unauthorized,%currqueued);
   
         my %counts = (          my %counts = (
                        user => 0,                         user => 0,
Line 5005  sub upfile_drop_add { Line 5565  sub upfile_drop_add {
                     my (%userres,%authres,%roleres,%idres);                      my (%userres,%authres,%roleres,%idres);
                     my $singlesec = '';                      my $singlesec = '';
                     if ($role eq 'st') {                      if ($role eq 'st') {
                           if (($context eq 'domain') && ($changeauth eq 'Yes') && (!$newuser)) {
                               if ((&Apache::lonnet::allowed('mau',$userdomain)) &&
                                   (&Apache::lonnet::homeserver($username,$userdomain) ne 'no_host')) {
                                   if ((($amode =~ /^krb4|krb5|internal$/) && $password ne '') ||
                                        ($amode eq 'localauth')) {
                                       $authresult =
                                           &Apache::lonnet::modifyuserauth($userdomain,$username,$amode,$password);
                                   }
                               }
                           }
                         my $sec;                          my $sec;
                         if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') {                          if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') {
                             if (@secs > 0) {                              if (@secs > 0) {
                                 $sec = $secs[0];                                  $sec = $secs[0];
                             }                              }
                         }                          }
                           if ($userdomain ne $env{'request.role.domain'}) {
                               my $item = "/$crsdom/$crsnum" ;
                               if ($sec ne '') {
                                   $item .= "/$sec";
                               }
                               $item .= '_st';
                               next if (&restricted_dom($context,$item,$userdomain,$username,$role,$startdate,
                                                        $enddate,$crsdom,$crsnum,$sec,$credits,\%process_by,
                                                        \%instdoms,\%got_role_approvals,\%got_instdoms,\%reject,
                                                        \%pending,\%notifydc,\%status,\%unauthorized,\%currqueued));
                           }
                         &modifystudent($userdomain,$username,$cid,$sec,                          &modifystudent($userdomain,$username,$cid,$sec,
                                        $desiredhost,$context);                                         $desiredhost,$context);
                         $roleresult =                          $roleresult =
Line 5022  sub upfile_drop_add { Line 5603  sub upfile_drop_add {
                                  '',$context,$inststatus,$credits);                                   '',$context,$inststatus,$credits);
                         $userresult = $roleresult;                          $userresult = $roleresult;
                     } else {                      } else {
                         if ($role ne '') {                           my $possrole;
                           if ($role ne '') {
                             if ($context eq 'course' || $setting eq 'course') {                              if ($context eq 'course' || $setting eq 'course') {
                                 if ($customroles{$role}) {                                  if ($customroles{$role}) {
                                     $role = 'cr_'.$env{'user.domain'}.'_'.                                      $role = 'cr_'.$env{'user.domain'}.'_'.
                                             $env{'user.name'}.'_'.$role;                                              $env{'user.name'}.'_'.$role;
                                 }                                  }
                                 if (($role ne 'cc') && ($role ne 'co')) {                                   $possrole = $role;
                                   if ($possrole =~ /^cr_/) {
                                       $possrole =~ s{_}{/}g;
                                   }
                                   if (($role ne 'cc') && ($role ne 'co')) {
                                    if (@secs > 1) {                                     if (@secs > 1) {
                                         $multiple = 1;                                          $multiple = 1;
                                           my $prefix = "/$crsdom/$crsnum";
                                         foreach my $sec (@secs) {                                          foreach my $sec (@secs) {
                                               if ($userdomain ne $env{'request.role.domain'}) {
                                                   my $item = $prefix;
                                                   if ($sec ne '') {
                                                       $item .= "/$sec";
                                                   }
                                                   $item .= '_'.$possrole;
                                                   next if (&restricted_dom($context,$item,$userdomain,$username,$possrole,
                                                                            $startdate,$enddate,$crsdom,$crsnum,$sec,
                                                                            $credits,\%process_by,\%instdoms,\%got_role_approvals,
                                                                            \%got_instdoms,\%reject,\%pending,\%notifydc,
                                                                            \%status,\%unauthorized,\%currqueued));
                                               }
                                             ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) =                                              ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) =
                                             &modifyuserrole($context,$setting,                                              &modifyuserrole($context,$setting,
                                                 $changeauth,$cid,$userdomain,$username,                                                  $changeauth,$cid,$userdomain,$username,
Line 5045  sub upfile_drop_add { Line 5644  sub upfile_drop_add {
                                         $singlesec = $secs[0];                                          $singlesec = $secs[0];
                                     }                                      }
                                 }                                  }
                               } else {
                                   $possrole = $role;
                             }                              }
                             if (!$multiple) {                          }
                                 ($userresult,$authresult,$roleresult,$idresult) =                           if (!$multiple) {
                                     &modifyuserrole($context,$setting,                              if (($userdomain ne $env{'request.role.domain'}) && ($role ne '')) {
                                                     $changeauth,$cid,$userdomain,$username,                                   my $item = "/$crsdom/$crsnum";
                                                     $id,$amode,$password,$fname,                                  if ($singlesec ne '') {
                                                     $mname,$lname,$gen,$singlesec,                                      $item .= "/$singlesec";
                                                     $env{'form.forceid'},$desiredhost,                                  }
                                                     $email,$role,$enddate,$startdate,                                  $item .= '_'.$possrole;
                                                     $checkid,$inststatus);                                  next if (&restricted_dom($context,$item,$userdomain,$username,$possrole,$startdate,$enddate,
                             }                                                           $crsdom,$crsnum,$singlesec,$credits,\%process_by,\%instdoms,
                                                            \%got_role_approvals,\%got_instdoms,\%reject,\%pending,\%notifydc,
                                                            \%status,\%unauthorized,\%currqueued));
                               }
                               ($userresult,$authresult,$roleresult,$idresult) = 
                                   &modifyuserrole($context,$setting,
                                                   $changeauth,$cid,$userdomain,$username, 
                                                   $id,$amode,$password,$fname,
                                                   $mname,$lname,$gen,$singlesec,
                                                   $env{'form.forceid'},$desiredhost,
                                                   $email,$role,$enddate,$startdate,
                                                   $checkid,$inststatus,\%emptyok);
                         }                          }
                     }                      }
                     if ($multiple) {                      if ($multiple) {
Line 5077  sub upfile_drop_add { Line 5689  sub upfile_drop_add {
             } # end of loop              } # end of loop
             $r->print('</ul>');              $r->print('</ul>');
             &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);              &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
               if (($context eq 'domain') && ($setting eq 'course')) {
                   unless ($oldcrsuserdoms) {
                       if (exists($env{'course.'.$cid.'.internal.userdomains'})) {
                           delete($env{'course.'.$cid.'.internal.userdomains'});
                       }
                   }
               }
         }          }
         # Flush the course logs so reverse user roles immediately updated          # Flush the course logs so reverse user roles immediately updated
         $r->register_cleanup(\&Apache::lonnet::flushcourselogs);          $r->register_cleanup(\&Apache::lonnet::flushcourselogs);
Line 5097  sub upfile_drop_add { Line 5716  sub upfile_drop_add {
         }          }
         $r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules));          $r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules));
         $r->print(&passwdrule_alerts($domain,\%showpasswdrules));          $r->print(&passwdrule_alerts($domain,\%showpasswdrules));
           if ((keys(%reject)) || (keys(%unauthorized))) {
               $r->print(&print_roles_rejected($context,\%reject,\%unauthorized));
           }
           if ((keys(%pending)) || (keys(%currqueued))) {
               $r->print(&print_roles_queued($context,\%pending,\%notifydc,\%currqueued));
           }
         #####################################          #####################################
         # Display list of students to drop  #          # Display list of students to drop  #
         #####################################          #####################################
Line 5175  sub passwdrule_alerts { Line 5800  sub passwdrule_alerts {
             my %passwdconf = &Apache::lonnet::get_passwdconf($domain);              my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
             $warning = '<b>'.&mt('Password requirement(s) unmet for one or more users:').'</b><ul>';              $warning = '<b>'.&mt('Password requirement(s) unmet for one or more users:').'</b><ul>';
             if ($showrules{'min'}) {              if ($showrules{'min'}) {
                 $warning .= '<li>'.&mt('minimum [quant,_1,character]',$passwdconf{'min'}).'</li>';                  my $min = $passwdconf{'min'};
                   if ($min eq '') {
                       $min = $Apache::lonnet::passwdmin;
                   }
                   $warning .= '<li>'.&mt('minimum [quant,_1,character]',$min).'</li>';
             }              }
             if ($showrules{'max'}) {              if ($showrules{'max'}) {
                 $warning .= '<li>'.&mt('maximum [quant,_1,character]',$passwdconf{'max'}).'</li>';                  $warning .= '<li>'.&mt('maximum [quant,_1,character]',$passwdconf{'max'}).'</li>';
Line 5286  sub update_user_list { Line 5915  sub update_user_list {
     if ($context eq 'course') {      if ($context eq 'course') {
         $crstype = &Apache::loncommon::course_type();          $crstype = &Apache::loncommon::course_type();
     }      }
     my @changelist;      my (@changelist,%got_role_approvals,%got_instdoms,%process_by,%instdoms,
           %pending,%reject,%notifydc,%status,%unauthorized,%currqueued);
     if ($choice eq 'drop') {      if ($choice eq 'drop') {
         @changelist = &Apache::loncommon::get_env_multiple('form.droplist');          @changelist = &Apache::loncommon::get_env_multiple('form.droplist');
     } else {      } else {
Line 5316  sub update_user_list { Line 5946  sub update_user_list {
     foreach my $item (@changelist) {      foreach my $item (@changelist) {
         my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype,          my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype,
             @sections,$scopestem,$singlesec,$showsecs,$warn_singlesec,              @sections,$scopestem,$singlesec,$showsecs,$warn_singlesec,
             $nothingtodo,$keepnosection,$credits,$instsec);              $nothingtodo,$keepnosection,$credits,$instsec,$cdom,$cnum);
         if ($choice eq 'drop') {          if ($choice eq 'drop') {
             ($uname,$udom,$sec) = split(/:/,$item,-1);              ($uname,$udom,$sec) = split(/:/,$item,-1);
             $role = 'st';              $role = 'st';
Line 5333  sub update_user_list { Line 5963  sub update_user_list {
                 split(/\:/,$item,8);                  split(/\:/,$item,8);
             $instsec = &unescape($instsec);              $instsec = &unescape($instsec);
             $cid = $env{'request.course.id'};              $cid = $env{'request.course.id'};
               $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
               $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
             $scopestem = '/'.$cid;              $scopestem = '/'.$cid;
             $scopestem =~s/\_/\//g;              $scopestem =~s/\_/\//g;
             if ($sec eq '') {              if ($sec eq '') {
Line 5343  sub update_user_list { Line 5975  sub update_user_list {
         } elsif ($context eq 'author') {          } elsif ($context eq 'author') {
             ($uname,$udom,$role) = split(/\:/,$item,-1);              ($uname,$udom,$role) = split(/\:/,$item,-1);
             $scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'};              $scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'};
               $cdom = $env{'user.domain'};
               $cnum = $env{'user.name'};
         } elsif ($context eq 'domain') {          } elsif ($context eq 'domain') {
             if ($setting eq 'domain') {              if ($setting eq 'domain') {
                 ($role,$uname,$udom) = split(/\:/,$item,-1);                  ($role,$uname,$udom) = split(/\:/,$item,-1);
                 $scope = '/'.$env{'request.role.domain'}.'/';                  $scope = '/'.$env{'request.role.domain'}.'/';
                   $cdom = $env{'request.role.domain'};
             } elsif ($setting eq 'author') {               } elsif ($setting eq 'author') { 
                 ($uname,$udom,$role,$scope) = split(/\:/,$item);                  ($uname,$udom,$role,$scope) = split(/\:/,$item);
                   (undef,$cdom,$cnum) = split(/\//,$scope);
             } elsif ($setting eq 'course') {              } elsif ($setting eq 'course') {
                 ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits,$instsec) =                   ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits,$instsec) = 
                     split(/\:/,$item,9);                      split(/\:/,$item,9);
                   ($cdom,$cnum) = split('_',$cid);
                 $instsec = &unescape($instsec);                  $instsec = &unescape($instsec);
                 $scope = '/'.$cid;                  $scope = '/'.$cid;
                 $scope =~s/\_/\//g;                  $scope =~s/\_/\//g;
Line 5393  sub update_user_list { Line 6030  sub update_user_list {
                 $start = $startdate;                   $start = $startdate; 
                 $end = $enddate;                  $end = $enddate;
             }              }
               my $id = $scope.'_'.$role;
             if ($choice eq 'reenable') {              if ($choice eq 'reenable') {
                   next if (&restricted_dom($context,$id,$udom,$uname,$role,$now,$end,$cdom,$cnum,
                                            $sec,$credits,\%process_by,\%instdoms,\%got_role_approvals,
                                            \%got_instdoms,\%reject,\%pending,\%notifydc,
                                            \%status,\%unauthorized,\%currqueued));
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);                      $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                 } else {                  } else {
Line 5402  sub update_user_list { Line 6044  sub update_user_list {
                                                     $now,'','',$context);                                                      $now,'','',$context);
                 }                  }
             } elsif ($choice eq 'activate') {              } elsif ($choice eq 'activate') {
                   next if (&restricted_dom($context,$id,$udom,$uname,$role,$now,$end,$cdom,$cnum,
                                            $sec,$credits,\%process_by,\%instdoms,\%got_role_approvals,
                                            \%got_instdoms,\%reject,\%pending,\%notifydc,
                                            \%status,\%unauthorized,\%currqueued));
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);                      $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                 } else {                  } else {
Line 5409  sub update_user_list { Line 6055  sub update_user_list {
                                             $now,'','',$context);                                              $now,'','',$context);
                 }                  }
             } elsif ($choice eq 'chgdates') {              } elsif ($choice eq 'chgdates') {
                   next if (&restricted_dom($context,$id,$udom,$uname,$role,$start,$end,$cdom,$cnum,
                                            $sec,$credits,\%process_by,\%instdoms,\%got_role_approvals,
                                            \%got_instdoms,\%reject,\%pending,\%notifydc,
                                            \%status,\%unauthorized,\%currqueued));
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);                      $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                 } else {                  } else {
Line 5618  sub update_user_list { Line 6268  sub update_user_list {
             $r->print(&make_dates_default($startdate,$enddate,$context,$crstype));              $r->print(&make_dates_default($startdate,$enddate,$context,$crstype));
         }          }
     }      }
       if ((keys(%reject)) || (keys(%unauthorized))) {
           $r->print(&print_roles_rejected($context,\%reject,\%unauthorized));
       }
       if ((keys(%pending)) || (keys(%currqueued))) {
           $r->print(&print_roles_queued($context,\%pending,\%notifydc,\%currqueued));
       }
     my $linktext = &mt('Display User Lists');      my $linktext = &mt('Display User Lists');
     if ($choice eq 'drop') {      if ($choice eq 'drop') {
         $linktext = &mt('Display current class roster');          $linktext = &mt('Display current class roster');
Line 6256  sub get_permission { Line 6912  sub get_permission {
                     $permission{'selfenrolladmin'} = 1;                      $permission{'selfenrolladmin'} = 1;
                 }                  }
             }              }
               unless ($permission{'selfenrolladmin'}) {
                   $permission{'selfenrollview'} = 1;
               }
         }          }
         if ($env{'request.course.id'}) {          if ($env{'request.course.id'}) {
             my $user;              my $user;
Line 6275  sub get_permission { Line 6934  sub get_permission {
             }              }
         }          }
     } elsif ($context eq 'author') {      } elsif ($context eq 'author') {
         $permission{'cusr'} = &authorpriv($env{'user.name'},$env{'request.role.domain'});          my $audom = $env{'request.role.domain'};
         $permission{'view'} = $permission{'cusr'};          my $auname = $env{'user.name'};
           if ((&Apache::lonnet::allowed('cca',"$audom/$auname")) ||
               (&Apache::lonnet::allowed('caa',"$audom/$auname"))) {
               $permission{'author'} = 1;
               $permission{'cusr'} = 1;
               $permission{'view'} = 1;
           }
       } elsif ($context eq 'coauthor') {
           my ($audom,$auname) = ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$});
           if ((&Apache::lonnet::allowed('vca',"$audom/$auname")) ||
               (&Apache::lonnet::allowed('vaa',"$audom/$auname"))) {
               if ($env{"environment.internal.manager./$audom/$auname"}) {
                   $permission{'cusr'} = 1;
                   $permission{'view'} = 1;
               }
           }
     } else {      } else {
         my @allroles = &roles_by_context($context);          my @allroles = &roles_by_context($context);
         foreach my $role (@allroles) {          foreach my $role (@allroles) {
Line 6304  sub get_permission { Line 6978  sub get_permission {
         }          }
     }      }
     my $allowed = 0;      my $allowed = 0;
     foreach my $perm (values(%permission)) {      foreach my $key (keys(%permission)) {
         if ($perm) { $allowed=1; last; }          next if (($key eq 'owner') || ($key eq 'co-owner') || ($key eq 'author'));
           if ($permission{$key}) { $allowed=1; last; }
     }      }
     return (\%permission,$allowed);      return (\%permission,$allowed);
 }  }
Line 6318  sub authorpriv { Line 6993  sub authorpriv {
          || (&Apache::lonnet::allowed('caa',$audom.'/'.$auname))) { return ''; }    return 1;           || (&Apache::lonnet::allowed('caa',$audom.'/'.$auname))) { return ''; }    return 1;
 }  }
   
   sub coauthorpriv {
       my ($auname,$audom)=@_;
       my $uname = $env{'user.name'};
       my $udom = $env{'user.domain'};
       if (((&Apache::lonnet::allowed('vca',"$udom/$uname")) ||
            (&Apache::lonnet::allowed('vaa',"$udom/$uname"))) &&
            ($env{"environment.internal.manager./$audom/$auname"})) {
           return 1;
       }
       return '';
   }
   
 sub roles_on_upload {  sub roles_on_upload {
     my ($context,$setting,$crstype,%customroles) = @_;      my ($context,$setting,$crstype,%customroles) = @_;
     my (@possible_roles,@permitted_roles);      my (@possible_roles,@permitted_roles);
Line 6514  sub verify_authen { Line 7201  sub verify_authen {
         $finish = "document.$formname.submit();";          $finish = "document.$formname.submit();";
     }      }
     my ($numrules,$intargjs) =      my ($numrules,$intargjs) =
         &passwd_validation_js('argpicked',$domain);          &Apache::loncommon::passwd_validation_js('argpicked',$domain);
     my $outcome = <<"ENDSCRIPT";      my $outcome = <<"ENDSCRIPT";
   
 function auth_check() {  function auth_check() {
Line 6718  sub selfenrollment_administration { Line 7405  sub selfenrollment_administration {
         }          }
     }      }
     if ($settings{'internal.selfenrollmgrdc'} ne '') {      if ($settings{'internal.selfenrollmgrdc'} ne '') {
         my @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'});          @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'});
         my @diffs = &Apache::loncommon::compare_arrays(\@in_domain,$possconfigs);          my @diffs = &Apache::loncommon::compare_arrays(\@in_domain,$possconfigs);
         unless (@diffs) {          unless (@diffs) {
             return (\@in_course,\@in_domain);              return (\@in_course,\@in_domain);

Removed from v.1.201  
changed lines
  Added in v.1.221


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