[LON-CAPA-cvs] cvs: loncom /auth lonroles.pm

raeburn raeburn@source.lon-capa.org
Thu, 24 Feb 2011 23:29:10 -0000


This is a MIME encoded message

--raeburn1298590150
Content-Type: text/plain

raeburn		Thu Feb 24 23:29:10 2011 EDT

  Modified files:              
    /loncom/auth	lonroles.pm 
  Log:
  - Bug 5932. Roles Screen usability improvements
    - Work in progress.
    - Check for new roles button to check for new roles or groups or privilege changes for existing groups since last log-in.
      - Handles special cases of: 
        (a) expiration/deletion of current role
        (b) section switching for student role
    - New routines: &update_session_roles(), &curr_role_status(),
        &gather_roleprivs(), &is_active_course().
    - New item in %env - user.update.time records when last new role check occurred. 
  
  
--raeburn1298590150
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20110224232910.txt"

Index: loncom/auth/lonroles.pm
diff -u loncom/auth/lonroles.pm:1.259 loncom/auth/lonroles.pm:1.260
--- loncom/auth/lonroles.pm:1.259	Thu Sep  2 17:06:38 2010
+++ loncom/auth/lonroles.pm	Thu Feb 24 23:29:10 2011
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # User Roles Screen
 #
-# $Id: lonroles.pm,v 1.259 2010/09/02 17:06:38 raeburn Exp $
+# $Id: lonroles.pm,v 1.260 2011/02/24 23:29:10 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -203,12 +203,33 @@
     my $now=time;
     my $then=$env{'user.login.time'};
     my $refresh=$env{'user.refresh.time'};
+    my $update=$env{'user.update.time'};
     if (!$refresh) {
         $refresh = $then;
     }
+    if (!$update) {
+        $update = $then;
+    }
+
+# -------------------------------------------------------- Check for new roles
+    my $updateresult;
+    if ($env{'form.doupdate'}) {
+        my $show_course=&Apache::loncommon::show_course();
+        my $checkingtxt;
+        if ($show_course) {
+            $checkingtxt = &mt('Checking for new courses ...');
+        } else {
+            $checkingtxt = &mt('Checking for new roles ...');
+        }
+        $updateresult = '<div class="LC_info">'.$checkingtxt.'</div>';
+        $updateresult .= &update_session_roles();
+        &Apache::lonnet::appenv({'user.update.time'  => $now});
+        $update = $now;
+    }
+
     my $envkey;
     my %dcroles = ();
-    my $numdc = &check_fordc(\%dcroles,$then);
+    my $numdc = &check_fordc(\%dcroles,$update,$then);
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
     my $loncaparev = $Apache::lonnet::perlvar{'lonVersion'};
 
@@ -228,13 +249,13 @@
                 if (defined($env{'user.role.'.$env{'form.switchrole'}})) {
                     my ($start,$end) = split(/\./,$env{'user.role.'.$env{'form.switchrole'}});
                     if (!$end || $end > $now) {
-                        if (!$start || $start < $refresh) {
+                        if (!$start || $start < $update) {
                             $switch_is_active = 1;
                         }
                     }
                 }
                 unless ($switch_is_active) {
-                    &adhoc_course_role($refresh,$then);
+                    &adhoc_course_role($refresh,$update,$then);
                 }
             }
 	    my %temp=('logout_'.$env{'request.course.id'} => time);
@@ -256,7 +277,7 @@
 		    ($envkey =~ m-^form\.(cc|co)\./($match_domain)/($match_courseid)$-)) {
                     if ($dcroles{$domain}) {
                         &Apache::lonnet::check_adhoc_privs($domain,$coursenum,
-                                                           $then,$refresh,$now,$ccrole);
+                                                           $update,$refresh,$now,$ccrole);
                     }
                     last;
                 }
@@ -296,7 +317,7 @@
                     if ($dcroles{$domain}) {
                         my ($server_status,$home) = &check_author_homeserver($user,$domain);
                         if (($server_status eq 'ok') || ($server_status eq 'switchserver')) {
-                            &Apache::lonnet::check_adhoc_privs($domain,$user,$then,
+                            &Apache::lonnet::check_adhoc_privs($domain,$user,$update,
                                                                $refresh,$now,'ca');
                             if ($server_status eq 'switchserver') {
                                 my $trolecode = 'ca./'.$domain.'/'.$user; 
@@ -318,7 +339,7 @@
         foreach $envkey (keys %env) {
             next if ($envkey!~/^user\.role\./);
             my ($where,$trolecode,$role,$tstatus,$tend,$tstart);
-            &Apache::lonnet::role_status($envkey,$then,$refresh,$now,\$role,\$where,
+            &Apache::lonnet::role_status($envkey,$update,$refresh,$now,\$role,\$where,
                                          \$trolecode,\$tstatus,\$tstart,\$tend);
             if ($env{'form.'.$trolecode}) {
 		if ($tstatus eq 'is') {
@@ -653,8 +674,15 @@
 	thisform.submit();
     } else {
        alert('$standby');
-    }   
+    }
+}
+
+function setToUpdate(thisform) {
+    thisform.doupdate.value='1';
+    thisform.selectrole.value='';
+    thisform.submit();
 }
+
 // ]]>
 </script>
 ENDHEADER
@@ -715,13 +743,13 @@
 	    }
         }
     }
-# -------------------------------------------------------- Choice or no choice?
     if ($nochoose) {
 	$r->print("<h2>".&mt('Sorry ...')."</h2>\n<span class='LC_error'>".
 		  &mt('This action is currently not authorized.').'</span>'.
 		  &Apache::loncommon::end_page());
 	return OK;
     } else {
+        $r->print($updateresult); 
         if (($ENV{'REDIRECT_QUERY_STRING'}) && ($fn)) {
     	    $fn.='?'.$ENV{'REDIRECT_QUERY_STRING'};
         }
@@ -734,18 +762,40 @@
 
     my (%roletext,%sortrole,%roleclass,%futureroles,%timezones);
     my ($countactive,$countfuture,$inrole,$possiblerole) = 
-        &gather_roles($then,$refresh,$now,$reinit,$nochoose,\%roletext,\%sortrole,\%roleclass,
+        &gather_roles($update,$refresh,$now,$reinit,$nochoose,\%roletext,\%sortrole,\%roleclass,
                       \%futureroles,\%timezones,$loncaparev);
-
     $refresh = $now;
     &Apache::lonnet::appenv({'user.refresh.time'  => $refresh});
+    my $updatebutton = &mt('Check for role changes');
+    my $show_course=&Apache::loncommon::show_course();
+    if ($show_course) {
+        $updatebutton = &mt('Check for new courses');
+    }
+    my $do_update;
+    unless (($env{'form.source'} eq 'login') || ($env{'form.doupdate'})) {
+        $do_update = '<input type="hidden" name="doupdate" value="" />'.
+                     '<input type="button" name="update" value="'.
+                     $updatebutton.'" onclick="javascript:setToUpdate(this.form)" />';
+    }
     if ($env{'user.adv'}) {
-        $r->print('<p><label><input type="checkbox" name="showall"');
-        if ($env{'form.showall'}) { $r->print(' checked="checked" '); }
-        $r->print(' />'.&mt('Show all roles').'</label>'
-                 .' <input type="submit" value="'.&mt('Update display').'" />'
-                 .'</p>');
+        my $showall = '<label><input type="checkbox" name="showall"';
+        if ($env{'form.showall'}) { 
+            $showall .= ' checked="checked" ';
+        }
+        $showall .= ' />'.&mt('Show all roles').'</label>'.
+                    '<input type="submit" value="'.&mt('Update display').'" />';
+        if ($do_update) {
+            $r->print('<div class="LC_left_float"><fieldset>'.
+                      '<legend>'. &mt('Display').'</legend>'.
+                      $showall.'</fieldset></div>'.
+                      '<div class="LC_left_float"><fieldset><legend>'.
+                      &mt('Changes?').'</legend>'.
+                      $do_update.'</fieldset></div><br clear="all" />');
+        } else {
+            $r->print($showall);
+        }
     } else {
+        $r->print('<p>'.$do_update.'</p>');
         if ($countactive > 0) {
             $r->print(&Apache::loncoursequeueadmin::queued_selfenrollment());
             my $domdesc = &Apache::lonnet::domain($env{'user.domain'},'description');
@@ -921,7 +971,7 @@
 }
 
 sub gather_roles {
-    my ($then,$refresh,$now,$reinit,$nochoose,$roletext,$sortrole,$roleclass,$futureroles,$timezones,$loncaparev) = @_;
+    my ($update,$refresh,$now,$reinit,$nochoose,$roletext,$sortrole,$roleclass,$futureroles,$timezones,$loncaparev) = @_;
     my ($countactive,$countfuture,$inrole,$possiblerole) = (0,0,0,'');
     my $advanced = $env{'user.adv'};
     my $tryagain = $env{'form.tryagain'};
@@ -933,7 +983,7 @@
         my ($role_text,$role_text_end,$sortkey);
         if ($envkey=~/^user\.role\./) {
             my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus,$tpstart,$tpend);
-            &Apache::lonnet::role_status($envkey,$then,$refresh,$now,\$role,\$where,
+            &Apache::lonnet::role_status($envkey,$update,$refresh,$now,\$role,\$where,
                                          \$trolecode,\$tstatus,\$tstart,\$tend);
             next if (!defined($role) || $role eq '' || $role =~ /^gr/);
             $tremark='';
@@ -1477,7 +1527,7 @@
 }
 
 sub check_fordc {
-    my ($dcroles,$then) = @_;
+    my ($dcroles,$update,$then) = @_;
     my $numdc = 0;
     if ($env{'user.adv'}) {
         foreach my $envkey (sort keys %env) {
@@ -1485,8 +1535,12 @@
                 my $dcdom = $1;
                 my $livedc = 1;
                 my ($tstart,$tend)=split(/\./,$env{$envkey});
-                if ($tstart && $tstart>$then) { $livedc = 0; }
-                if ($tend   && $tend  <$then) { $livedc = 0; }
+                my $limit = $update;
+                if ($env{'request.role'} eq 'dc./'.$dcdom.'/') {
+                    $limit = $then;
+                }
+                if ($tstart && $tstart>$limit) { $livedc = 0; }
+                if ($tend   && $tend  <$limit) { $livedc = 0; }
                 if ($livedc) {
                     $$dcroles{$dcdom} = $envkey;
                     $numdc++;
@@ -1498,19 +1552,19 @@
 }
 
 sub adhoc_course_role {
-    my ($refresh,$then) = @_;
+    my ($refresh,$update,$then) = @_;
     my ($cdom,$cnum,$crstype);
     $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
     $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     $crstype = &Apache::loncommon::course_type();
-    if (&check_forcc($cdom,$cnum,$refresh,$then,$crstype)) {
+    if (&check_forcc($cdom,$cnum,$refresh,$update,$then,$crstype)) {
         my $setprivs;
         if (!defined($env{'user.role.'.$env{'form.switchrole'}})) {
             $setprivs = 1;
         } else {
             my ($start,$end) = split(/\./,$env{'user.role.'.$env{'form.switchrole'}});
             if (($start && ($start>$refresh || $start == -1)) ||
-                ($end && $end<$then)) {
+                ($end && $end<$update)) {
                 $setprivs = 1;
             }
         }
@@ -1553,7 +1607,7 @@
 }
 
 sub check_forcc {
-    my ($cdom,$cnum,$refresh,$then,$crstype) = @_;
+    my ($cdom,$cnum,$refresh,$update,$then,$crstype) = @_;
     my ($is_cc,$ccrole);
     if ($crstype eq 'Community') {
         $ccrole = 'co';
@@ -1566,8 +1620,12 @@
             if (defined($env{$envkey})) {
                 $is_cc = 1;
                 my ($tstart,$tend)=split(/\./,$env{$envkey});
+                my $limit = $update;
+                if ($env{'request.role'} eq $ccrole.'./'.$cdom.'/'.$cnum) {
+                    $limit = $then;
+                }
                 if ($tstart && $tstart>$refresh) { $is_cc = 0; }
-                if ($tend   && $tend  <$then) { $is_cc = 0; }
+                if ($tend   && $tend  <$limit) { $is_cc = 0; }
             }
         }
     }
@@ -1798,6 +1856,633 @@
     return $startpage;
 }
 
+sub update_session_roles {
+    my $then=$env{'user.login.time'};
+    my $refresh=$env{'user.refresh.time'};
+    if (!$refresh) {
+        $refresh = $then;
+    }
+    my $update = $env{'user.update.time'};
+    if (!$update) {
+        $update = $then;
+    }
+    my $now = time;
+    my %roleshash =
+        &Apache::lonnet::get_my_roles('','','userroles',
+                                      ['active','future','previous'],
+                                      undef,undef,1);
+    my ($msg,@newsec,$oldsec,$currrole_expired,@changed_roles,
+        %changed_groups,%dbroles, %deletedroles,%allroles,%allgroups,
+        %userroles,%checkedgroup,%crprivs,$hasgroups,%rolechange,
+        %groupchange,%newrole,%newgroup,%customprivchg,%groups_roles,
+        @rolecodes);
+    my @possroles = ('cr','st','ta','ad','ep','in','co','cc');
+    my %courseroles;
+    foreach my $item (keys(%roleshash)) {
+        my ($uname,$udom,$role,$remainder) = split(/:/,$item,4);
+        my ($tstart,$tend) = split(/:/,$roleshash{$item});
+        my ($section,$group,@group_privs);
+        if ($role =~ m{^gr/(\w*)$}) {
+            $role = 'gr';
+            my $priv = $1;
+            next if ($tstart eq '-1');
+            if (&curr_role_status($tstart,$tend,$refresh,$now) eq 'active') {
+                if ($priv ne '') {
+                    push(@group_privs,$priv);
+                }
+            }
+            if ($remainder =~ /:/) {
+                (my $additional_privs,$group) =
+                    ($remainder =~ /^([\w:]+):([^:]+)$/);
+                if ($additional_privs ne '') {
+                    if (&curr_role_status($tstart,$tend,$refresh,$now) eq 'active') {
+                        push(@group_privs,split(/:/,$additional_privs));
+                        @group_privs = sort(@group_privs);
+                    }
+                }
+            } else {
+                $group = $remainder;
+            }
+        } else {
+            $section = $remainder;
+        }
+        my $where = "/$udom/$uname";
+        if ($section ne '') {
+            $where .= "/$section";
+        } elsif ($group ne '') {
+            $where .= "/$group";
+        }
+        my $rolekey = "$role.$where";
+        my $envkey = "user.role.$rolekey";
+        $dbroles{$envkey} = 1;
+        if (($env{'request.role'} eq $rolekey) && ($role ne 'st')) {
+            if (&curr_role_status($tstart,$tend,$refresh,$now) ne 'active') {
+                $currrole_expired = 1;
+            }
+        }
+        if ($env{$envkey} eq '') {
+            my $status_in_db =
+                &curr_role_status($tstart,$tend,$refresh,$now);
+                &gather_roleprivs(\%allroles,\%allgroups,\%userroles,$where,$role,$tstart,$tend,$status_in_db);
+            if (($role eq 'st') && ($env{'request.role'} =~ m{^\Q$role\E\.\Q/$udom/$uname\E})) {
+                if ($status_in_db eq 'active') {
+                    if ($section eq '') {
+                        push(@newsec,'none');
+                    } else {
+                        push(@newsec,$section);
+                    }
+                }
+            } else {
+                unless (grep(/^\Q$role\E$/,@changed_roles)) {
+                    push(@changed_roles,$role);
+                }
+                if ($status_in_db ne 'previous') {
+                    if ($role eq 'gr') {
+                        $newgroup{$rolekey} = $status_in_db;
+                        if ($status_in_db eq 'active') {
+                            unless (ref($courseroles{$udom}) eq 'HASH') {
+                                %{$courseroles{$udom}} =
+                                    &Apache::lonnet::get_my_roles('','','userroles',
+                                                                  ['active'],\@possroles,
+                                                                  [$udom],1);
+                            }
+                            &Apache::lonnet::get_groups_roles($udom,$uname,
+                                                              $courseroles{$udom},
+                                                              \@rolecodes,\%groups_roles);
+                        }
+                    } else {
+                        $newrole{$rolekey} = $status_in_db;
+                    }
+                }
+            }
+        } else {
+            my ($currstart,$currend) = split(/\./,$env{$envkey});
+            if ($role eq 'gr') {
+                if (&curr_role_status($currstart,$currend,$refresh,$update) ne 'previous') {
+                    $hasgroups = 1;
+                }
+            }
+            if (($currstart ne $tstart) || ($currend ne $tend)) {
+                my $status_in_env =
+                    &curr_role_status($currstart,$currend,$refresh,$update);
+                my $status_in_db =
+                    &curr_role_status($tstart,$tend,$refresh,$now);
+                if ($status_in_env ne $status_in_db) {
+                    if ($status_in_env eq 'active') {
+                        if ($role eq 'st') {
+                            if ($env{'request.role'} eq $rolekey) {
+                                my $switchsection;
+                                unless (ref($courseroles{$udom}) eq 'HASH') {
+                                    %{$courseroles{$udom}} =
+                                        &Apache::lonnet::get_my_roles('','','userroles',
+                                                                      ['active'],
+                                                                      \@possroles,[$udom],1);
+                                }
+                                foreach my $crsrole (keys(%{$courseroles{$udom}})) {
+                                    if ($crsrole =~ /^\Q$uname\E:\Q$udom\E:st/) {
+                                        $switchsection = 1;
+                                        last;
+                                    }
+                                }
+                                if ($switchsection) {
+                                    if ($section eq '') {
+                                        $oldsec = 'none';
+                                    } else {
+                                        $oldsec = $section;
+                                    }
+                                    &gather_roleprivs(\%allroles,\%allgroups,\%userroles,$where,$role,$tstart,$tend,$status_in_db);
+                                } else {
+                                    $currrole_expired = 1;
+                                    next;
+                                }
+                            }
+                        }
+                        unless ($rolekey eq $env{'request.role'}) {
+                            if ($role eq 'gr') {
+                                &Apache::lonnet::delete_env_groupprivs($where,\%courseroles,\@possroles);
+                            } else {
+                                &Apache::lonnet::delenv("user.priv.$rolekey",undef,[$role]);
+                                &Apache::lonnet::delenv("user.priv.cm.$where",undef,['cm']);
+                            }
+                            &gather_roleprivs(\%allroles,\%allgroups,\%userroles,$where,$role,$tstart,$tend,$status_in_db);
+                        }
+                    } elsif ($status_in_db eq 'active') {
+                        if (($role eq 'st') &&
+                            ($env{'request.role'} =~ m{^\Q$role\E\.\Q/$udom/$uname\E})) {
+                            if ($section eq '') {
+                                push(@newsec,'none');
+                            } else {
+                                push(@newsec,$section);
+                            }
+                        } elsif ($role eq 'gr') {
+                            unless (ref($courseroles{$udom}) eq 'HASH') {
+                                %{$courseroles{$udom}} =
+                                    &Apache::lonnet::get_my_roles('','','userroles',
+                                                                  ['active'],
+                                                                  \@possroles,[$udom],1);
+                            }
+                            &Apache::lonnet::get_groups_roles($udom,$uname,
+                                                              $courseroles{$udom},
+                                                              \@rolecodes,\%groups_roles);
+                        }
+                        &gather_roleprivs(\%allroles,\%allgroups,\%userroles,$where,$role,$tstart,$tend,$status_in_db);
+                    }
+                    unless (grep(/^\Q$role\E$/,@changed_roles)) {
+                        push(@changed_roles,$role);
+                    }
+                    if ($role eq 'gr') {
+                        $groupchange{"/$udom/$uname"}{$group} = $status_in_db;
+                    } else {
+                        $rolechange{$rolekey} = $status_in_db;
+                    }
+                }
+            } else {
+                if ($role eq 'gr') {
+                    unless ($checkedgroup{$where}) {
+                        my $status_in_db =
+                            &curr_role_status($tstart,$tend,$refresh,$now);
+                        if ($tstart eq '-1') {
+                            $status_in_db = 'deleted';
+                        }
+                        unless (ref($courseroles{$udom}) eq 'HASH') {
+                            %{$courseroles{$udom}} =
+                                &Apache::lonnet::get_my_roles('','','userroles',
+                                                              ['active'],
+                                                              \@possroles,[$udom],1);
+                        }
+                        if (ref($courseroles{$udom}) eq 'HASH') {
+                            foreach my $item (keys(%{$courseroles{$udom}})) {
+                                next unless ($item =~ /^\Q$uname\E/);
+                                my ($cnum,$cdom,$crsrole,$crssec) = split(/:/,$item);
+                                my $area = '/'.$cdom.'/'.$cnum;
+                                if ($crssec ne '') {
+                                    $area .= '/'.$crssec;
+                                }
+                                my $crsrolekey = $crsrole.'.'.$area;
+                                my $currprivs = $env{'user.priv.'.$crsrole.'.'.$area.'.'.$where};
+                                $currprivs =~ s/^://;
+                                $currprivs =~ s/\&F$//;
+                                my @curr_grp_privs = split(/\&F:/,$currprivs);
+                                @curr_grp_privs = sort(@curr_grp_privs);
+                                my @diffs;
+                                if (@group_privs > 0 || @curr_grp_privs > 0) {
+                                    @diffs = &Apache::loncommon::compare_arrays(\@group_privs,\@curr_grp_privs);
+                                }
+                                if (@diffs == 0) {
+                                    last;
+                                } else {
+                                    unless(grep(/^\Qgr\E$/,@rolecodes)) {
+                                        push(@rolecodes,'gr');
+                                    }
+                                    &gather_roleprivs(\%allroles,\%allgroups,
+                                                      \%userroles,$where,$role,
+                                                      $tstart,$tend,$status_in_db);
+                                    if ($status_in_db eq 'active') {
+                                        &Apache::lonnet::get_groups_roles($udom,$uname,
+                                                                          $courseroles{$udom},
+                                                                          \@rolecodes,\%groups_roles);
+                                    }
+                                    $changed_groups{$udom.'_'.$uname}{$group} = $status_in_db;
+                                    last;
+                                }
+                            }
+                        }
+                        $checkedgroup{$where} = 1;
+                    }
+                } elsif ($role =~ /^cr/) {
+                    my $status_in_db =
+                        &curr_role_status($tstart,$tend,$refresh,$now);
+                    my ($rdummy,$rest) = split(/\//,$role,2);
+                    my ($rdummy,$rdomain,$rauthor,$rrole)=split(/\//,$role);
+                    my %currpriv;
+                    unless (exists($crprivs{$rest})) {
+                        my ($rdomain,$rauthor,$rrole)=split(/\//,$rest);
+                        my $homsvr=&Apache::lonnet::homeserver($rauthor,$rdomain);
+                        if (&Apache::lonnet::hostname($homsvr) ne '') {
+                            my ($rdummy,$roledef)=
+                            &Apache::lonnet::get('roles',["rolesdef_$rrole"],
+                                                 $rdomain,$rauthor);
+                            if (($rdummy ne 'con_lost') && ($roledef ne '')) {
+                                my $i = 0;
+                                my @scopes = ('sys','dom','crs');
+                                my @privs = split(/\_/,$roledef);
+                                foreach my $priv (@privs) {
+                                    my ($blank,@prv) = split(/:/,$priv);
+                                    @prv = map { $_ .= (/\&\w+$/ ? '':'&F') } @prv;
+                                    $priv = ':'.join(':',sort(@prv));
+                                    $crprivs{$rest}{$scopes[$i]} = $priv;
+                                    $i++;
+                                }
+                            }
+                        }
+                    }
+                    $currpriv{sys} = $env{"user.priv.$rolekey./"};
+                    $currpriv{dom} = $env{"user.priv.$rolekey./$udom/"};
+                    $currpriv{crs} = $env{"user.priv.$rolekey.$where"};
+                    if (keys(%crprivs)) {
+                        if (($crprivs{$rest}{sys} ne $currpriv{sys}) ||
+                            ($crprivs{$rest}{dom} ne $currpriv{dom})
+ ||
+                            ($crprivs{$rest}{crs} ne $currpriv{crs})) {
+                            &gather_roleprivs(\%allroles,\%allgroups,\%userroles,$where,$role,$tstart,$tend,$status_in_db);
+                            unless (grep(/^\Q$role\E$/,@changed_roles)) {
+                                push(@changed_roles,$role);
+                            }
+                            my $status_in_env =
+                                &curr_role_status($currstart,$currend,$refresh,$update);
+                            if ($status_in_env eq 'active') {
+                                $customprivchg{$rolekey} = $status_in_env;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    foreach my $envkey (keys(%env)) {
+        next unless ($envkey =~ /^user\.role\./);
+        next if ($dbroles{$envkey});
+        next if ($envkey eq 'user.role.'.$env{'request.role'});
+        my ($currstart,$currend) = split(/\./,$env{$envkey});
+        my $status_in_env =
+            &curr_role_status($currstart,$currend,$refresh,$update);
+        my ($rolekey) = ($envkey =~ /^user\.role\.(.+)$/);
+        my ($role,$rest)=split(/\./,$rolekey,2);
+        if (&Apache::lonnet::delenv($envkey,undef,[$role])) {
+            if ($status_in_env eq 'active') {
+                if ($role eq 'gr') {
+                    &Apache::lonnet::delete_env_groupprivs($rest,\%courseroles,
+                                                           \@possroles);
+                } else {
+                    &Apache::lonnet::delenv("user.priv.$rolekey",undef,[$role]);
+                    &Apache::lonnet::delenv("user.priv.cm.$rest",undef,['cm']);
+                }
+                unless (grep(/^\Q$role\E$/,@changed_roles)) {
+                    push(@changed_roles,$role);
+                }
+                $deletedroles{$rolekey} = 1;
+            }
+        }
+    }
+    if (($oldsec) && (@newsec > 0)) {
+        if (@newsec > 1) {
+            $msg = '<div class="LC_warning">'.&mt('The section has changed for your current role. Log-out and log-in again to select a role for the new section.').'</div>';
+        } else {
+            my $newrole = $env{'request.role'};
+            if ($newsec[0] eq 'none') {
+                $newrole =~ s{(/[^/])$}{};
+            } elsif ($oldsec eq 'none') {
+                $newrole .= '/'.$newsec[0];
+            } else {
+                $newrole =~ s{([^/]+)$}{$newsec[0]};
+            }
+            my $coursedesc = $env{'course.'.$env{'request.course.id'}.'.description'};
+            my ($curr_role) = ($env{'request.role'} =~ m{^(\w+)\./$match_domain/$match_courseid});
+            my %temp=('logout_'.$env{'request.course.id'} => time);
+            &Apache::lonnet::put('email_status',\%temp);
+            &Apache::lonnet::delenv('user.state.'.$env{'request.course.id'});
+            &Apache::lonnet::appenv({"request.course.id"   => '',
+                                     "request.course.fn"   => '',
+                                     "request.course.uri"  => '',
+                                     "request.course.sec"  => '',
+                                     "request.role"        => 'cm',
+                                     "request.role.adv"    => $env{'user.adv'},
+                                     "request.role.domain" => $env{'user.domain'}});
+            my $rolename = &Apache::loncommon::plainname($curr_role);
+            $msg = '<p><form name="reselectrole" action="/adm/roles" method="post" />'.
+                   '<input type="hidden" name="newrole" value="" />'.
+                   '<input type="hidden" name="selectrole" value="1" />'.
+                   '<span class="LC_info">'.
+                   &mt('Your section has changed for your current [_1] role in [_2].',$rolename,$coursedesc).'</span><br />';
+            my $button = '<input type="button" name="sectionchanged" value="'.
+                         &mt('Re-Select').'" onclick="javascript:enterrole(this.form,'."'$newrole','sectionchanged'".')" />';
+            if ($newsec[0] eq 'none') {
+                $msg .= &mt('[_1] to continue with your new section-less role.',$button);
+            } else {
+                $msg .= &mt('[_1] to continue with your new role in section ([_2]).',$button,$newsec[0]);
+            }
+            $msg .= '</form></p>';
+        }
+    } elsif ($currrole_expired) {
+        $msg .= '<div class="LC_warning">';
+        if (&Apache::loncommon::show_course()) {
+            $msg .= &mt('Your role in the current course has expired.');
+        } else {
+            $msg .= &mt('Your current role has expired.');
+        }
+        $msg .= '<br />'.&mt('However you can continue to use this role until you logout, click the "Re-Select" button, or your session has been idle for more than 24 hours.').'</div>';
+    }
+    if (!@changed_roles || !(keys(%changed_groups))) {
+        $msg .= '<ul>';
+        if (!@changed_roles) {
+            $msg .= '<li>';
+            if (&Apache::loncommon::show_course()) {
+                $msg .= &mt('No new courses or communities');
+            } else {
+                $msg .= &mt('No role changes');
+            }
+            $msg .= '</li>';
+        }
+        if ($hasgroups && !(keys(%changed_groups)) && !(grep(/gr/,@changed_roles))) {
+            $msg .= '<li>'.&mt('No changes in course/community groups').'</li>';
+        }
+        $msg .= '</ul>';
+        if (!@changed_roles && !(keys(%changed_groups))) {
+            return $msg;
+        }
+    }
+    my $changemsg;
+    if (@changed_roles > 0) {
+        if (keys(%newgroup) > 0) {
+            my $groupmsg;
+            foreach my $item (sort(keys(%newgroup))) {
+                if (&is_active_course($item,$refresh,$update,\%roleshash)) {
+                    $groupmsg .= '<li>'.
+                                 &mt('[_1] with status: [_2].',
+                                 $item,$newgroup{$item}).'</li>';
+                }
+            }
+            if ($groupmsg) {
+                $changemsg .= '<li>'.
+                              &mt('Courses with new groups').'</li>'.
+                              '<ul>'.$groupmsg.'</ul></li>';
+            }
+        }
+        if (keys(%newrole) > 0) {
+            $changemsg .= '<li>'.&mt('New roles').
+                          '<ul>';
+            foreach my $item (sort(keys(%newrole))) {
+                $changemsg .= '<li>'.
+                              &mt('[_1] with status: [_2].',
+                              $item,$newrole{$item}).'</li>';
+            }
+            $changemsg .= '</ul></li>';
+        }
+        if (keys(%customprivchg) > 0) {
+            $changemsg .= '<li>'.
+                          &mt('Custom roles with privilege changes').
+                          '<ul>';
+            foreach my $item (sort(keys(%customprivchg))) {
+                $changemsg .= '<li>'.$item.'</li>';
+            }
+            $changemsg .= '</ul></li>';
+        }
+        if (keys(%rolechange) > 0) {
+            $changemsg .= '<li>'.
+                          &mt('Existing roles with status changes').'</li>'.
+                          '<ul>';
+            foreach my $item (sort(keys(%rolechange))) {
+                $changemsg .= '<li>'.
+                              &mt('[_1] status now: [_2].',$item,
+                              $rolechange{$item}).'</li>';
+            }
+            $changemsg .= '</ul></li>';
+        }
+        if (keys(%deletedroles) > 0) {
+            $changemsg .= '<li>'.
+                          &mt('Existing roles deleted').'</li>'.
+                          '<ul>';
+            foreach my $item (sort(keys(%deletedroles))) {
+                $changemsg .= '<li>'.$item.'</li>';
+            }
+            $changemsg .= '</ul></li>';
+        }
+    }
+    if ((keys(%changed_groups) > 0) || (keys(%groupchange) > 0)) {
+        my $groupchgmsg;
+        foreach my $key (sort(keys(%changed_groups))) {
+            my $crs = 'gr/'.$key;
+            $crs =~ s/_/\//;
+            if (&is_active_course($crs,$refresh,$update,\%roleshash)) {
+                if (ref($changed_groups{$key}) eq 'HASH') {
+                    my @showgroups;
+                    foreach my $group (sort(keys(%{$changed_groups{$key}}))) {
+                        if ($changed_groups{$key}{$group} eq 'active') {
+                            push(@showgroups,$group);
+                        }
+                    }
+                    if (@showgroups > 0) {
+                        $groupchgmsg .= '<li>'.
+                                        &mt('Course: [_1], groups: [_2].',$key,
+                                        join(', ',@showgroups)).
+                                        '</li>';
+                    }
+                }
+            }
+        }
+        if (keys(%groupchange) > 0) {
+            $groupchgmsg .= '<li>'.
+                          &mt('Existing course/community groups with status changes').'</li>'.
+                          '<ul>';
+            foreach my $crs (sort(keys(%groupchange))) {
+                if (ref($groupchange{$crs}) eq 'HASH') {
+                    $groupchgmsg .= '<li>'.&mt('Course/Community: [_1]','<b>'.$crs.'</b><ul>');
+                    foreach my $group (sort(keys(%{$groupchange{$crs}}))) {
+                        $groupchgmsg .= '<li>'.&mt('Group: [_1] status now: [_2].','<b>'.$group.'</b>',$groupchange{$crs}{$group}).'</li>';
+                    }
+                    $groupchgmsg .= '</ul></li>';
+                }
+            }
+            $groupchgmsg .= '</ul></li>';
+        }
+        if ($groupchgmsg) {
+            $changemsg .= '<li>'.
+                          &mt('Courses with changes in groups').'</li>'.
+                          '<ul>'.$groupchgmsg.'</ul></li>';
+        }
+    }
+    if ($changemsg) {
+        $msg .= '<ul>'.$changemsg.'</ul>';
+    }
+    &Apache::lonnet::set_userprivs(\%userroles,\%allroles,\%allgroups,\%groups_roles);
+    my ($curr_is_adv,$curr_role_adv,$curr_author,$curr_role_author);
+    $curr_author = $env{'user.author'};
+    if (($env{'request.role'} =~/^au/) || ($env{'request.role'} =~/^ca/) ||
+        ($env{'request.role'} =~/^aa/)) {
+        $curr_role_author=1;
+    }
+    $curr_is_adv = $env{'user.adv'};
+    $curr_role_adv = $env{'request.role.adv'};
+    if (keys(%userroles) > 0) {
+        foreach my $role (@changed_roles) {
+            unless(grep(/^\Q$role\E$/,@rolecodes)) {
+                push(@rolecodes,$role);
+            }
+        }
+        unless(grep(/^\Qcm\E$/,@rolecodes)) {
+            push(@rolecodes,'cm');
+        }
+        &Apache::lonnet::appenv(\%userroles,\@rolecodes);
+    }
+    my %newenv;
+    if (&Apache::lonnet::is_advanced_user($env{'user.domain'},$env{'user.name'})) {
+        unless ($curr_is_adv) {
+            $newenv{'user.adv'} = 1;
+        }
+    } elsif ($curr_is_adv && !$curr_role_adv) {
+        &Apache::lonnet::delenv('user.adv');
+    }
+    my %authorroleshash =
+        &Apache::lonnet::get_my_roles('','','userroles',['active'],['au','ca','aa']);
+    if (keys(%authorroleshash)) {
+        unless ($curr_author) {
+            $newenv{'user.author'} = 1;
+        }
+    } elsif ($curr_author && !$curr_role_author) {
+        &Apache::lonnet::delenv('user.author');
+    }
+    if ($env{'request.course.id'}) {
+        my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+        my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+        my (@activecrsgroups,$crsgroupschanged);
+        if ($env{'request.course.groups'}) {
+            @activecrsgroups = split(/:/,$env{'request.course.groups'});
+            foreach my $item (keys(%deletedroles)) {
+                if ($item =~ m{^gr\./\Q$cdom\E/\Q$cnum\E/(\w+)$}) {
+                    if (grep(/^\Q$1\E$/,@activecrsgroups)) {
+                        $crsgroupschanged = 1;
+                        last;
+                    }
+                }
+            }
+        }
+        unless ($crsgroupschanged) {
+            foreach my $item (keys(%newgroup)) {
+                if ($item =~ m{^gr\./\Q$cdom\E/\Q$cnum\E/(\w+)$}) {
+                    if ($newgroup{$item} eq 'active') {
+                        $crsgroupschanged = 1;
+                        last;
+                    }
+                }
+            }
+        }
+        if ((ref($changed_groups{$env{'request.course.id'}}) eq 'HASH') ||
+            (ref($groupchange{"/$cdom/$cnum"}) eq 'HASH') ||
+            ($crsgroupschanged)) {
+            my %grouproles =  &Apache::lonnet::get_my_roles('','','userroles',
+                                                            ['active'],['gr'],[$cdom],1);
+            my @activegroups;
+            foreach my $item (keys(%grouproles)) {
+                next unless($item =~ /^\Q$cnum\E:\Q$cdom\E/);
+                my $group;
+                my ($crsn,$crsd,$role,$remainder) = split(/:/,$item,4);
+                if ($remainder =~ /:/) {
+                    (my $other,$group) = ($remainder =~ /^([\w:]+):([^:]+)$/);
+                } else {
+                    $group = $remainder;
+                }
+                if ($group ne '') {
+                    push(@activegroups,$group);
+                }
+            }
+            $newenv{'request.course.groups'} = join(':',@activegroups);
+        }
+    }
+    if (keys(%newenv)) {
+        &Apache::lonnet::appenv(\%newenv);
+    }
+    return $msg;
+}
+
+sub curr_role_status {
+    my ($start,$end,$refresh,$update) = @_;
+    if (($start) && ($start<0)) { return 'deleted' };
+    my $status = 'active';
+    if (($end) && ($end<=$update)) {
+        $status = 'previous';
+    }
+    if (($start) && ($refresh<$start)) {
+        $status = 'future';
+    }
+    return $status;
+}
+
+sub gather_roleprivs {
+    my ($allroles,$allgroups,$userroles,$area,$role,$tstart,$tend,$status) = @_;
+    return unless ((ref($allroles) eq 'HASH') && (ref($allgroups) eq 'HASH') && (ref($userroles) eq 'HASH'));
+    if (($area ne '') && ($role ne '')) {
+        &Apache::lonnet::userrolelog($role,$env{'user.name'},$env{'user.domain'},
+                                     $area,$tstart,$tend);
+        my $spec=$role.'.'.$area;
+        $userroles->{'user.role.'.$spec} = $tstart.'.'.$tend;
+        my ($tdummy,$tdomain,$trest)=split(/\//,$area);
+        if ($status eq 'active') { 
+            if ($role =~ /^cr\//) {
+                &Apache::lonnet::custom_roleprivs($allroles,$role,$tdomain,$trest,$spec,$area);
+            } elsif ($role eq 'gr') {
+                my %rolehash = &Apache::lonnet::get('roles',[$area.'_'.$role],
+                                                    $env{'user.domain'},
+                                                    $env{'user.name'});
+                my ($trole) = split(/_/,$rolehash{$area.'_'.$role},2);
+                (undef,my $group_privs) = split(/\//,$trole);
+                $group_privs = &unescape($group_privs);
+                &Apache::lonnet::group_roleprivs($allgroups,$area,$group_privs,$tend,$tstart);
+            } else {
+                &Apache::lonnet::standard_roleprivs($allroles,$role,$tdomain,$spec,$trest,$area);
+            }
+        }
+    }
+    return;
+}
+
+sub is_active_course {
+    my ($rolekey,$refresh,$update,$roleshashref) = @_;
+    return unless(ref($roleshashref) eq 'HASH');
+    my ($role,$cdom,$cnum) = split(/\//,$rolekey);
+    my $is_active;
+    foreach my $key (keys(%{$roleshashref})) {
+        if ($key =~ /^\Q$cnum\E:\Q$cdom\E:/) {
+            my ($tstart,$tend) = split(/:/,$roleshashref->{$key});
+            my $status = &curr_role_status($tstart,$tend,$refresh,$update);
+            if ($status eq 'active') {
+                $is_active = 1;
+                last;
+            }
+        }
+    }
+    return $is_active;
+}
+
 1;
 __END__
 

--raeburn1298590150--