[LON-CAPA-cvs] cvs: loncom /interface loncoursegroups.pm

raeburn lon-capa-cvs@mail.lon-capa.org
Tue, 21 Feb 2006 18:56:03 -0000


This is a MIME encoded message

--raeburn1140548163
Content-Type: text/plain

raeburn		Tue Feb 21 13:56:03 2006 EDT

  Modified files:              
    /loncom/interface	loncoursegroups.pm 
  Log:
  Can now change the status of group members (delete, expire, activate, re-enable), change the functionality available to members (if group is configured to allow different members to use different functionality), and/or change member privileges for each of the functions (if group is configured to allow different members to receive different privileges).  If granularity in functionality, and/or in privileges is required, but was not set to be so during initial group creation, this can be changed by modifying the default group settings first.
  
  
--raeburn1140548163
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20060221135603.txt"

Index: loncom/interface/loncoursegroups.pm
diff -u loncom/interface/loncoursegroups.pm:1.5 loncom/interface/loncoursegroups.pm:1.6
--- loncom/interface/loncoursegroups.pm:1.5	Fri Feb 17 20:27:07 2006
+++ loncom/interface/loncoursegroups.pm	Tue Feb 21 13:56:00 2006
@@ -88,8 +88,8 @@
                                   \%functions,\%idx,$view_permission,
                                   $manage_permission,$rowColor1,$rowColor2);
         } else {
-            $r->print('You do not have group administration '.
-                      'privileges in this course');
+            $r->print(&mt('You do not have group administration '.
+                          'privileges in this course'));
         }
     } else {
         &print_main_menu($r,$cdom,$cnum,$function,$tabcol,\%functions,\%idx,
@@ -129,10 +129,22 @@
       delete => '<a href="/adm/coursegroups?action=delete&refpage='.
                 $env{'form.refpage'}.'&groupname=',
     );
-    my %actiontext = &Apache::lonlocal::texthash( 
+    my %lt = &Apache::lonlocal::texthash( 
                           modify => 'Modify',
-                          view => 'View',
+                          view   => 'View',
                           delete => 'Delete',
+                          act    => 'Action',
+                          gname  => 'Group Name',
+                          desc   => 'Description',
+                          crea   => 'Creator',
+                          crtd   => 'Created',
+                          last   => 'Last Modified',
+                          func   => 'Functionality',
+                          quot   => 'Quota (Mb)',
+                          memb   => 'Members',
+                          file   => 'Files',
+                          dibd   => 'Discussion Boards',
+                          dius   => 'Disk Use',
                      );  
     $r->print('<br /><br />');
     if ($view_permission) {
@@ -145,22 +157,22 @@
             $r->print(<<"END");
       <table border="0" cellpadding="4" cellspacing="1">
        <tr bgcolor="$tabcol" align="center">
-        <td><b>Action</b></td>
-        <td><b><a href="javascript:changeSort('groupname')">Group Name</a></b></td>
-        <td><b><a href="javascript:changeSort('description')">Description</a></b></td>
-        <td><b><a href="javascript:changeSort('creator')">Creator</a></b>
+        <td><b>$lt{'act'}</b></td>
+        <td><b><a href="javascript:changeSort('groupname')">$lt{'gname'}</a></b></td>
+        <td><b><a href="javascript:changeSort('description')">$lt{'desc'}</a></b></td>
+        <td><b><a href="javascript:changeSort('creator')">$lt{'crea'}</a></b>
         </td>
-        <td><b><a href="javascript:changeSort('creation')">Created</a></b>
+        <td><b><a href="javascript:changeSort('creation')">$lt{'crtd'}</a></b>
         </td>
-        <td><b><a href="javascript:changeSort('modified')">Last Modified</a></b>
+        <td><b><a href="javascript:changeSort('modified')">$lt{'last'}</a></b>
         </td>
-        <td><b>Functionality</b>
+        <td><b>$lt{'func'}</b>
         </td>
-        <td><b><a href="javascript:changeSort('quota')">Quota (Mb)</a></b></td>
-        <td><b><a href="javascript:changeSort('totalmembers)">Members</a></b></td>
-        <td><b><a href="javascript:changeSort('totalfiles')">Files</a></b></td>
-        <td><b><a href="javascript:changeSort('boards')">Discussion boards</a></b></td>
-        <td><b><a href="javascript:changeSort('diskuse')">Disk use</a></b></td>
+        <td><b><a href="javascript:changeSort('quota')">$lt{'quot'}</a></b></td>
+        <td><b><a href="javascript:changeSort('totalmembers)">$lt{'memb'}</a></b></td>
+        <td><b><a href="javascript:changeSort('totalfiles')">$lt{'file'}</a></b></td>
+        <td><b><a href="javascript:changeSort('boards')">$lt{'dibd'}</a></b></td>
+        <td><b><a href="javascript:changeSort('diskuse')">$lt{'dius'}</a></b></td>
        </tr>
 END
             my %Sortby = ();
@@ -218,12 +230,12 @@
                     my $diskuse = $grp_info{$group}{'diskuse'};
                     my $functionality;
                     foreach my $tool (sort(keys(%{$functions}))) {
-                        if (defined($grp_info{$group}{functions}{$tool})) {
+                        if ($grp_info{$group}{functions}{$tool} eq 'on') {
                             $functionality .= ' '.$tool;
                         }
                     }
                     if (!$functionality) {
-                        $functionality = 'None available';
+                        $functionality = &mt('None available');
                     }
                     my $link = $actionlinks{$action};
                     if ($action eq 'modify' || $action eq 'delete') {
@@ -231,7 +243,7 @@
                     } else {
                         $link .= $group.'/grppg?register=1';
                     }
-                    $link .= '">'.$actiontext{$action}.'</a>';  
+                    $link .= '">'.$lt{$action}.'</a>';  
                     $r->print('<tr bgcolor="'.$rowColor.'"><td><small>'.$link.'</small></td><td><small>'.$group.'</small></td><td><small>'.$description.'</small></td><td><small>'.$creator.'</small></td><td><small>'. &Apache::lonnavmaps::timeToHumanString($creation).'</small></td><td><small>'. &Apache::lonnavmaps::timeToHumanString($modified).'</small></td><td><small>'.$functionality.'</small></td><td><small>'.$quota.'</small></td><td><small>'.$totalmembers.'</small></td><td><small>'.$totalfiles.'</small></td><td><small>'.$boards.'</small></td><td><small>'.$diskuse.'</small></td></tr>');
                     $rowNum ++;
                 }
@@ -256,7 +268,8 @@
                 }
             }
         } else {
-            $r->print('You are not currently a member of any active groups in this course');
+            $r->print(&mt('You are not currently a member of any '.
+                          'active groups in this course'));
         }
     }
     return;
@@ -276,7 +289,7 @@
     my %usertools = ();
     my %stored = ();
     my %memchg;
-    my @member_changes = ('delete','expire','activate','reenable',
+    my @member_changes = ('deletion','expire','activate','reenable',
                           'changefunc','changepriv');
     my $state = $env{'form.state'};
     my ($groupname,$description,$startdate,$enddate,$granularity,$specificity);
@@ -315,23 +328,6 @@
         }
     }
 
-    if (($action eq 'modify') && (($state eq 'change_privs') || ($state eq 'memresult'))) {
-        foreach my $chg (@member_changes) {
-            if (defined($env{'form.'.$chg})) {
-                @{$memchg{$chg}} = &Apache::loncommon::get_env_multiple('form.'.$chg);
-            }
-        }
-        &check_changes(\@member_changes,\%memchg);
-        foreach my $change (@member_changes) {
-            if (($change eq 'delete') || ($change eq 'expire')) {
-                next;
-            } 
-            foreach my $user (@{$memchg{$change}}) {
-                %{$usertools{$user}} = ();
-            }
-        }
-    }
-
     if ($action eq 'modify') {
         if ($state eq '') {
             $state = 'pick_group';
@@ -471,9 +467,11 @@
         }
     }
 
-    if (($state eq 'pick_members') || ($state eq 'pick_privs')) {
-        &build_members_list($cdom,$cnum,\@types,\@roles,
-                            \@sections,\%users,\%userdata);
+    if (($state eq 'pick_members') || ($state eq 'pick_privs') || ($state eq 'change_privs')) {
+        &build_members_list($cdom,$cnum,\@types,\@roles,\@sections,\%users,
+                            \%userdata);
+    }
+    if ($state eq 'pick_members') {
         if ((keys(%users) > 0) && (@tools > 0)) {
             foreach my $tool (@tools) {
                 if ($granularity eq 'Yes') {
@@ -483,6 +481,62 @@
             $elements{$action}{'pick_members'}{'specificity'} = 'radio';
         }
     }
+    if ($state eq 'change_members') {
+        my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
+                                                               $groupname);
+        my $now = time;
+        my $num_expire = 0;
+        my $num_activate = 0;
+        my $num_reenable = 0;
+        my $num_deletion = 0;
+        my $numusers = 0;
+        foreach my $key (sort(keys(%membership))) {
+            if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) {
+                my $user = $1;
+                my($end,$start,@userprivs) = split(/:/,$membership{$key});
+                unless ($start == -1) {
+                    $numusers ++;
+                    $num_deletion ++;
+                    if (($end > 0) && ($end < $now)) {
+                        $num_reenable ++;
+                        next;
+                    } elsif (($start > $now)) {
+                        $num_activate = 1;
+                        next;
+                    } else {
+                        $num_expire ++;
+                        next;
+                    }
+                    next;
+                }
+                if ($num_reenable && $num_activate && $num_expire) {
+                    last;
+                }
+            }
+        }
+        if ($num_deletion) {
+            $elements{$action}{'change_members'}{'deletion'} = 'checkbox';
+        }
+        if ($num_expire) {
+            $elements{$action}{'change_members'}{'expire'} = 'checkbox';
+        }
+        if ($num_activate) {
+            $elements{$action}{'change_members'}{'activate'} = 'checkbox';
+        }
+        if ($num_reenable) {
+            $elements{$action}{'change_members'}{'reenable'} = 'checkbox';
+        }
+        if ($numusers) {
+            foreach my $tool (@tools) {
+                if ($granularity eq 'Yes') {
+                    $elements{$action}{'change_members'}{'user_'.$tool} = 'checkbox';
+                }
+            }
+            if ($specificity eq 'Yes') {
+                $elements{$action}{'change_members'}{'changepriv'} = 'checkbox';
+            }
+        }
+    }
 
     if (($state eq 'pick_privs') || ($state eq 'change_privs') ||
         (($specificity eq 'No') && 
@@ -495,14 +549,106 @@
                 }
             }
         }
-        if ((($state eq 'pick_privs') || ($state eq 'change_privs'))
-            && ($specificity eq 'Yes')) {
-            foreach my $user (sort(keys(%usertools))) {
-                foreach my $tool (keys(%{$usertools{$user}})) {
-                    foreach my $priv (keys(%{$toolprivs{$tool}})) {
-                        unless (exists($fixedprivs{$tool}{$priv})) {
-                            $elements{$action}{$state}{'userpriv_'.$priv} = 'checkbox';
+    }
+
+    if (($action eq 'modify') && (($state eq 'change_privs') || ($state eq 'memresult'))) {
+        foreach my $chg (@member_changes) {
+            if (defined($env{'form.'.$chg})) {
+                @{$memchg{$chg}} = &Apache::loncommon::get_env_multiple('form.'.$chg);
+            }
+        }
+                                                                              
+        if ($state eq 'change_privs') {
+            my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
+                                                                   $groupname);
+            my $now = time;
+            foreach my $key (sort(keys(%membership))) {
+                if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) {
+                    my $user = $1;
+                    my $changefunc = 0;
+                    my ($end,$start,@userprivs) = split(/:/,$membership{$key});
+                    unless ($start == -1) {
+                        if (($end > 0) && ($end < $now)) {
+                            unless (grep/^$user$/,$memchg{'reenable'}) {
+                                next;
+                            }
+                        }
+                        my @currtools = ();
+                        if (@userprivs > 0) {
+                            foreach my $tool (sort(keys(%fixedprivs))) {
+                                foreach my $priv (keys(%{$fixedprivs{$tool}})) {
+                                    if (grep/^$priv$/,@userprivs) {
+                                        push(@currtools,$tool);
+                                        last;
+                                    }
+                                }
+                            }
                         }
+                        foreach my $tool (@currtools) {
+                            if (keys(%{$usertools{$user}}) > 0) {
+                                if (!$usertools{$user}{$tool}) {
+                                    push(@{$memchg{'changefunc'}},$user);
+                                    $changefunc = 1;
+                                    last;
+                                }
+                            } else {
+                                push(@{$memchg{'changefunc'}},$user);
+                                $changefunc = 1;
+                            }
+                        }
+                        if ($changefunc) {
+                            next;
+                        }
+                        if (keys(%{$usertools{$user}}) > 0) {
+                            foreach my $tool (keys(%{$usertools{$user}})) {
+                                if (!grep/^$tool$/,@currtools) {
+                                    push(@{$memchg{'changefunc'}},$user);
+                                    $changefunc = 1;
+                                    last;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            &check_changes(\@member_changes,\%memchg);
+            my %temptools;
+            foreach my $change (@member_changes) {
+                if (($change eq 'deletion') || ($change eq 'expire')) {
+                    next;
+                }
+                foreach my $user (@{$memchg{$change}}) {
+                    unless (exists($usertools{$user})) {
+                        %{$usertools{$user}} = ();
+                    }
+                    %{$temptools{$user}} = %{$usertools{$user}}; 
+                }
+            }
+            %usertools = %temptools;
+        } elsif ($state eq 'memresult') {
+            foreach my $change (@member_changes) {
+                if ($change eq 'expire' || $change eq 'deletion') {
+                    next;
+                }
+                if (ref($memchg{$change}) eq 'ARRAY') { 
+                    my @users = @{$memchg{$change}};
+                    foreach my $user (@users) {
+                        unless (exists($usertools{$user})) {
+                            %{$usertools{$user}} = ();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    if ((($state eq 'pick_privs') || ($state eq 'change_privs'))
+        && ($specificity eq 'Yes')) {
+        foreach my $user (sort(keys(%usertools))) {
+            foreach my $tool (keys(%{$usertools{$user}})) {
+                foreach my $priv (keys(%{$toolprivs{$tool}})) {
+                    unless (exists($fixedprivs{$tool}{$priv})) {
+                        $elements{$action}{$state}{'userpriv_'.$priv} = 'checkbox';
                     }
                 }
             }
@@ -519,6 +665,11 @@
     formname.state.value = prevstate;
     formname.submit();
 }
+function changeSort(caller) {
+    document.$state.state.value = '$state';
+    document.$state.sortby.value = caller;
+    document.$state.submit();
+} 
                                                                                       
 |;
     $jscript .= &Apache::lonhtmlcommon::set_form_elements(
@@ -767,7 +918,7 @@
                                $startdate,$enddate,$tools,$functions,
                                $toolprivs,$fixedprivs,$userdata,$usertools,
                                $memchg,$idx,$states,$stored,$sectioncount,
-                               $navbuttons,$rowColor1,$rowColor2) = @_;
+                               $navbuttons,$rowColor1,$rowColor2);
         } elsif ($state eq 'chgresult' || $state eq 'memresult' || 
                  $state eq 'addresult') {
             &process_request($r,$cdom,$cnum,$tabcol,$action,$state,$page,
@@ -829,6 +980,7 @@
 
 sub footer {
        return(<<ENDFOOT);
+   <input type="hidden" name="sortby" value="$env{'form.sortby'}" />
   </form>
  </body>
 </html>
@@ -870,12 +1022,14 @@
     foreach my $member (keys %memberhash) {
         $totalmembers ++;
         my ($end,$start) = split(/:/,$memberhash{$member});
-        if (($end!=0) && ($end<$now)) {
-            $previous ++;
-        } elsif (($start!=0) && ($start>$now)) {
-            $future ++;
-        } else {
-            $active ++;
+        unless ($start == -1) {
+            if (($end!=0) && ($end<$now)) {
+                $previous ++;
+            } elsif (($start!=0) && ($start>$now)) {
+                $future ++;
+            } else {
+               $active ++;
+            }
         }
     }
     if ($totalmembers == 0) {
@@ -1030,7 +1184,7 @@
                 'picr' => 'Pick the criteria to use to build a list of '.
                           'course users from which you will select ',
                 'meof' => 'members of the new group.',
-                'adme' => 'additional members of the group.',
+                'admg' => 'additional members of the group.',
                 'ifno' => 'If you do not wish to add members when you first '.
                           'create the group, do not make any selections',  
                 'acty' => 'Access types',
@@ -1056,7 +1210,7 @@
     if ($action eq 'create') {
         $r->print($lt{'meof'}.'<br />'.$lt{'ifno'});
     } else {
-        $r->print($lt{'adme'});
+        $r->print($lt{'admg'});
     }
     $r->print('
      <br />
@@ -1155,7 +1309,7 @@
     my %origmembers;
     $r->print(&Apache::lonhtmlcommon::echo_form_input(
          ['origin','action','state','page','member','specificity','branch',
-          'defpriv','autorole','autoadd','autodrop'],
+          'defpriv','autorole','autoadd','autodrop','sortby'],
          \@regexps));
     my $earlyout = &validate_groupname($groupname,$action,$cdom,$cnum);
     $r->print('
@@ -1189,10 +1343,13 @@
                                                                $groupname);
         foreach my $key (sort(keys(%membership))) {
             if ($key =~ /^\Q$groupname\E:([^:]+):([^:]+)$/) {
-                my $uname = $1;
-                my $udom = $2;
-                my $user = $uname.':'.$udom;
-                $origmembers{$user} = 1; 
+                my ($end,$start,@userprivs) = split(/:/,$membership{$key});
+                unless ($start == -1) {  
+                    my $uname = $1;
+                    my $udom = $2;
+                    my $user = $uname.':'.$udom;
+                    $origmembers{$user} = 1; 
+                }
             }
         }
     }
@@ -1824,8 +1981,9 @@
                                         );
     my @regexps = ('user_','userpriv_');
     $r->print(&Apache::lonhtmlcommon::echo_form_input(
-                         ['origin','action','state','page','expire','delete',
-                          'changefunc','changepriv'],\@regexps));
+                         ['origin','action','state','page','expire','deletion',
+                          'reenable','activate','changepriv','sortby'],
+                          \@regexps));
     my $rowimg = 1;
     my @available = ();
     my @unavailable = ();
@@ -1869,12 +2027,17 @@
     my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
                                                                    $groupname);
     my %lt = &Apache::lonlocal::texthash(
+                                          'actn' => 'Action?',
+                                          'name' => 'Name',
+                                          'usnm' => 'Username',
+                                          'doma' => 'Domain',
+                                          'stda' => 'Start Date',
+                                          'enda' => 'End Date',
                                           'expi' => 'Expire',
                                           'reen' => 'Re-enable',
                                           'acti' => 'Activate',
                                           'dele' => 'Delete',
                                           'curf' => 'Current Functionality',
-                                          'chfn' => 'Change Functions',
                                           'chpr' => 'Change Privileges' 
                                         );
     if (keys(%membership) > 0) {
@@ -1976,11 +2139,8 @@
             if ($num_activate) {
                 &check_uncheck_buttons($r,$formname,'activate',$lt{'acti'});
             }
-            &check_uncheck_buttons($r,$formname,'delete',$lt{'dele'});
+            &check_uncheck_buttons($r,$formname,'deletion',$lt{'dele'});
             if (@{$available} > 0) {
-                if ($granularity eq 'Yes') {
-                    &check_uncheck_buttons($r,$formname,'changefunc',$lt{'chfn'});
-                }
                 if ($specificity eq 'Yes') {
                     &check_uncheck_buttons($r,$formname,'changepriv',$lt{'chpr'});
                 }
@@ -2018,22 +2178,39 @@
             $r->print(<<"END");
    <table border="0" cellpadding="4" cellspacing="1">
     <tr bgcolor="$tabcol" align="center">
-     <td><b>Action?</b></td>
-     <td><b><a href="javascript:changeSort('fullname')">Name</a></b></td>
-     <td><b><a href="javascript:changeSort('username')">Username</a></b>
+     <td><b>$lt{'actn'}</b></td>
+     <td><b><a href="javascript:changeSort('fullname')">$lt{'name'}</a></b></td>
+     <td><b><a href="javascript:changeSort('username')">$lt{'usnm'}</a></b>
      </td>
-     <td><b><a href="javascript:changeSort('domain')">Domain</a></b></td>
+     <td><b><a href="javascript:changeSort('domain')">$lt{'doma'}</a></b></td>
      <td><b><a href="javascript:changeSort('id')">ID</a></b></td>
-     <td><b><a href="javascript:changeSort('start')">Start Date</a></b></td>
-     <td><b><a href="javascript:changeSort('end')">End Date</a></b></td>
+     <td><b><a href="javascript:changeSort('start')">$lt{'stda'}</a></b></td>
+     <td><b><a href="javascript:changeSort('end')">$lt{'enda'}</a></b></td>
 END
+            my $colspan = 0;
             if ($hastools) {
                 $r->print('<td><b>'.$lt{'curf'}.'</b></td>');
+                $colspan ++;  
             }
             if ($addtools) {
                 $r->print('<td><b>Additional Functionality</b></td>');
+                $colspan ++;
             }
             $r->print('</tr>');
+            if ($colspan) {
+                if ($granularity eq 'Yes') {
+                    $r->print('<tr bgcolor="#cccccc">
+ <td colspan="7">&nbsp;</td>
+ <td colspan="'.$colspan.'" align="center"><small><nobr><b>'.&mt('All:').
+  '</b>&nbsp;');
+                    foreach my $tool (@{$available}) {
+                        $r->print('<input type="checkbox" name="togglefunc" '.
+   'onclick="javascript:toggleTools(document.'.$formname.'.user_'.$tool.',this);">'.
+   '<b>'.$tool.'</b>&nbsp;&nbsp;&nbsp;');
+                    }
+                    $r->print('</nobr></small></td></tr>');
+                }
+            }
             my %Sortby = ();
             foreach my $user (sort(keys(%current))) {
                 if ($env{'form.sortby'} eq 'fullname') {
@@ -2079,13 +2256,8 @@
    $lt{'acti'}.'</nobr><br />');
                     }
                     $r->print('<nobr>'.
-   '<input type="checkbox" name="delete" value="'.$user.'" />'.
+   '<input type="checkbox" name="deletion" value="'.$user.'" />'.
    $lt{'dele'}.'</nobr>');
-                    if ($granularity eq 'Yes') {
-                        $r->print('<br /><nobr>'.
-   '<input type="checkbox" name="changefunc" value="'.$user.'" />'.$lt{'chfn'}.
-   '</nobr>');
-                    }
                     if ($specificity eq 'Yes') {
                         $r->print('<br /><nobr>'.
    '<input type="checkbox" name="changepriv" value="'.$user.'" />'.$lt{'chpr'}.
@@ -2098,7 +2270,8 @@
     $udom.'</small></td><td><small>'.$id.'</small></td><td><small>'.$start.
     '</small></td><td><small>'.$end.'</small></td>');
                     if ($hastools) {
-                        $r->print('<td align="left"><small><nobr>');
+                        $r->print('<td align="left"><small><nobr>'.
+                                  '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');
                         foreach my $tool (@{$current{$user}{currtools}}) {
                             if ($granularity eq 'Yes') {
                                 $r->print('<input type="checkbox" 
@@ -2173,23 +2346,62 @@
        $rowColor2) = @_;
     my @regexps = ('userpriv_');
     my $nexttext;
-                                                                                      
+    my %lt = &Apache::lonlocal::texthash(
+               'tode' => 'To be deleted',
+               'toex' => 'To be expired',
+               'nome' => 'No members to be deleted or expired from the group.',
+    );
     $r->print(&Apache::lonhtmlcommon::echo_form_input(
-         ['origin','action','state','page'],\@regexps));
-    $nexttext = $$navbuttons{'adme'};
-                                                                                      
+         ['origin','action','state','page','sortby'],\@regexps));
+    if ($env{'form.branch'} eq 'adds') {
+        $nexttext = $$navbuttons{'adme'};
+    } else {
+        $nexttext = $$navbuttons{'mose'};
+    }
     $r->print('<br /><table width="100%" cellpadding="0" cellspacing="0" border="0">');
+    &topic_bar($r,$tabcol,3,&mt('Members to delete or expire'));
+    my $exp_or_del = 0;
+    if (ref($$memchg{'deletion'}) eq 'ARRAY') {
+        if (@{$$memchg{'deletion'}} > 0) {
+            $r->print('<tr><td>&nbsp;</td><td colspan="3"><b>'.$lt{'tode'}.':</b><br /><ul>');
+            foreach my $user (@{$$memchg{'deletion'}}) {
+                $r->print('<li>'.$$userdata{$user}[$$idx{fullname}].
+                          '&nbsp;('.$user.')</li>');
+            }
+            $r->print('</ul></td><tr><td colspan="4">&nbsp;</td></tr>');
+            $exp_or_del += @{$$memchg{'deletion'}};
+        }
+    }
+    if (ref($$memchg{'expire'}) eq 'ARRAY') {
+        if (@{$$memchg{'expire'}} > 0) {
+            $r->print('<tr><td>&nbsp;</td><td colspan="3"><b>'.$lt{'toex'}.':</b><br /><ul>');
+            foreach my $user (@{$$memchg{'expire'}}) {
+                $r->print('<li>'.$$userdata{$user}[$$idx{fullname}].
+                          '&nbsp;('.$user.')</li>');
+            }
+            $r->print('</ul></td><tr><td colspan="4">&nbsp;</td></tr>');
+            $exp_or_del += @{$$memchg{'expire'}};
+        }
+    }
+    if (!$exp_or_del) {
+        $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'nome'}.
+                  '</td></tr><tr><td colspan="4">&nbsp;</td></tr>');
+    }
     
-    &topic_bar($r,$tabcol,3,&mt('Group member privileges'));
-                                                                                      
-    &member_privileges_form($r,$tabcol,$action,$formname,$tools,$toolprivs,
-                            $fixedprivs,$userdata,$usertools,$idx,$memchg,
-                            $states,$stored,$rowColor1,$rowColor2);
-                                                                                      
+    &topic_bar($r,$tabcol,4,&mt('Group member privileges'));
+
+    my $numchgs = &member_privileges_form($r,$tabcol,$action,$formname,$tools,
+                                          $toolprivs,$fixedprivs,$userdata,
+                                          $usertools,$idx,$memchg,$states,
+                                          $stored,$rowColor1,$rowColor2);
     $r->print('</td></tr><tr><td colspan="4">&nbsp;</td></tr>');
     my $prevtext = $$navbuttons{'gtps'};
-    &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
-                        $$states{$action}[$page+1],$nexttext);
+    if ($numchgs || $exp_or_del) {
+        &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
+                            $$states{$action}[$page+1],$nexttext);
+    } else {
+        &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext);
+    }
     $r->print('</table>');
     return;
 }
@@ -2238,12 +2450,12 @@
     if ($action eq 'create') {
         push(@regexps,'sec_');
         $r->print(&Apache::lonhtmlcommon::echo_form_input(
-         ['origin','action','state','page','autoadd','autodrop'],
+         ['origin','action','state','page','sortby','autoadd','autodrop'],
          \@regexps));
         $nexttext = $$navbuttons{'crgr'};
     } else {
         $r->print(&Apache::lonhtmlcommon::echo_form_input(
-         ['origin','action','state','page'],\@regexps));
+         ['origin','action','state','page','sortby'],\@regexps));
         $nexttext = $$navbuttons{'adme'};
     }
 
@@ -2273,21 +2485,28 @@
 
 sub build_boxes {
     my ($r,$tools,$usertools,$fixedprivs,$toolprivs,$showtools,
-        $showboxes,$prefix,$specificity) = @_;
+        $showboxes,$prefix,$specificity,$excluded) = @_;
     my $totalboxes = 0;
     if (@{$tools} > 0) {
         if ($specificity eq 'Yes') {
             foreach my $tool (@{$tools}) {
                 @{$$showboxes{$tool}} = ();
                 foreach my $user (sort(keys(%{$usertools}))) {
-                    unless (grep/^$tool$/,@{$showtools}) {
-                        push(@{$showtools},$tool);
+                    if (ref($excluded) eq 'ARRAY') {
+                        if (grep/^$user$/,@{$excluded}) {
+                            next;
+                        }
                     }
-                    foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
-                        unless (exists($$fixedprivs{$tool}{$priv})) {
-                            unless(grep(/^$priv$/,@{$$showboxes{$tool}})) {
-                                push(@{$$showboxes{$tool}},$priv);
-                                $totalboxes ++;
+                    if ($$usertools{$user}{$tool}) {
+                        unless (grep/^$tool$/,@{$showtools}) {
+                            push(@{$showtools},$tool);
+                        }
+                        foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
+                            unless (exists($$fixedprivs{$tool}{$priv})) {
+                                unless(grep(/^$priv$/,@{$$showboxes{$tool}})) {
+                                    push(@{$$showboxes{$tool}},$priv);
+                                    $totalboxes ++;
+                                }
                             }
                         }
                     }
@@ -2338,6 +2557,10 @@
                       'there are no specific user privileges to set.',
             'asng' => 'As no group tools will be made available to users, '.
                       'there are no specific user privileges to set.',
+            'nogm' => 'No group member privileges to display or set, '.
+                      'as you have not indicated that you will be activating,'.
+                      ' re-enabling, changing privileges, or adding/removing '.
+                      'functionality for any current members ',
             'full' => 'Fullname',
             'user' => 'Username',
             'doma' => 'Domain',
@@ -2355,43 +2578,72 @@
     }
     my @showtools;
     my %showboxes = ();
-    my $totalboxes = 0;
     my $numtools = 1 + @{$tools};
 
-    $totalboxes = &build_boxes($r,$tools,$usertools,$fixedprivs,$toolprivs,
-                               \@showtools,\%showboxes,'userpriv_',
-                               $specificity);
+    my @excluded = ();
+    my $numchgs = 0;
+    if ($formname eq 'change_privs') {
+        my @currmembers = ();
+        if (ref($$memchg{'deletion'}) eq 'ARRAY') {
+            push(@excluded,@{$$memchg{'deletion'}});
+        }
+        if (ref($$memchg{'expire'}) eq 'ARRAY') {
+            push(@excluded,@{$$memchg{'expire'}});
+        }
+        if (@excluded > 0) {
+            foreach my $user (sort(keys(%{$usertools}))) {
+                if (grep/^$user$/,@excluded) {
+                    next;
+                }
+                push(@currmembers,$user);
+            }
+        } else {
+            @currmembers = sort(keys(%{$usertools}));
+        }
+        $numchgs = @currmembers;
+        if (!$numchgs) {
+            $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'nogm'}); 
+            return $numchgs;
+        }
+    }
+ 
+    my $totalboxes = &build_boxes($r,$tools,$usertools,$fixedprivs,
+                                   $toolprivs,\@showtools,\%showboxes,
+                                   'userpriv_',$specificity,\@excluded);
     if (@{$tools} > 0) {
         if ($specificity eq 'Yes') {
             if ($totalboxes > 0) {
                 my $numcells = 2;
                 my $colspan = $numcells + 1;
                 my %total;
-                $r->print('
+                if (keys(%{$usertools}) > 1) {
+                    $r->print('
  <tr>
   <td>&nbsp;</td>
   <td colspan="3">
    <table border="0" cellspacing="2" cellpadding="2" border="0">
     <tr>
 ');
-                foreach my $tool (@{$tools}) {
-                    if (@{$showboxes{$tool}} > 0) {
-                        $r->print('<td valign="top">');
-                        $r->print('<table class="thinborder"><tr bgcolor="'.$tabcol.
-                      '"><th colspan="'.$colspan.'">'.$tool.'</th></tr><tr>');
-                        my $privcount = 0;
-                        foreach my $priv (@{$showboxes{$tool}}) {
-                            $privcount ++;
-                            if (($privcount == @{$showboxes{$tool}}) && ($privcount > 1)) {
-                                if ($privcount%$numcells) {
-                                    $r->print('<td colspan="'.$colspan.'">');
+                    foreach my $tool (@{$tools}) {
+                        if (@{$showboxes{$tool}} > 0) {
+                            $r->print('<td valign="top">');
+                            $r->print('<table class="thinborder"><tr bgcolor="'.
+                                      $tabcol.'"><th colspan="'.$colspan.'">'.
+                                      $tool.'</th></tr><tr>');
+                            my $privcount = 0;
+                            foreach my $priv (@{$showboxes{$tool}}) {
+                                $privcount ++;
+                                if (($privcount == @{$showboxes{$tool}}) && 
+                                    ($privcount > 1)) {
+                                    if ($privcount%$numcells) {
+                                        $r->print('<td colspan="'.$colspan.'">');
+                                    } else {
+                                        $r->print('<td>');
+                                    }
                                 } else {
                                     $r->print('<td>');
                                 }
-                            } else {
-                                $r->print('<td>');
-                            }
-                            $r->print(qq|
+                                $r->print(qq|
        <fieldset><legend><b>$$toolprivs{$tool}{$priv}</b></legend>
        <nobr>
        <input type="button" value="check all"
@@ -2400,22 +2652,24 @@
        <input type="button" value="uncheck all"
         onclick="javascript:uncheckAll(document.$formname.userpriv_$priv)" />
       </nobr></fieldset><br />|);
-                            $r->print('</td>');
-                            if ($privcount < @{$showboxes{$tool}}) {
-                                if (@{$showboxes{$tool}} > 2) {
-                                    if ($privcount%$numcells == 0) {
-                                        $r->print('</tr><tr>');
+                                $r->print('</td>');
+                                if ($privcount < @{$showboxes{$tool}}) {
+                                    if (@{$showboxes{$tool}} > 2) {
+                                        if ($privcount%$numcells == 0) {
+                                            $r->print('</tr><tr>');
+                                        }
+                                    } else {
+                                        $r->print('<tr></tr>');
                                     }
-                                } else {
-                                    $r->print('<tr></tr>');
                                 }
                             }
+                            $r->print('</tr></table></td><td>&nbsp;</td>');
                         }
-                        $r->print('</tr></table></td><td>&nbsp;</td>');
                     }
+                    $r->print('</tr></table></td></tr>');
+                    $r->print('<tr><td colspan="4">&nbsp;</td></tr>');
                 }
-                $r->print('</tr></table></td></tr>');
-                $r->print('<tr><td colspan="4">&nbsp;</td></tr><tr><td>&nbsp;</td><td colspan="3">');
+                $r->print('<tr><td>&nbsp;</td><td colspan="3">');
                 $r->print(&Apache::lonhtmlcommon::start_pick_box());
                 $r->print(<<"END");
    <tr bgcolor="$tabcol">
@@ -2427,7 +2681,8 @@
 END
                 &member_privs_entries($r,$tabcol,$rowColor1,$rowColor2,
                                       $usertools,$toolprivs,$fixedprivs,
-                                      $userdata,$idx,\@showtools,\@defprivs);
+                                      $userdata,$idx,\@showtools,\@defprivs,
+                                      \@excluded);
                 $r->print('</td>');
                 $r->print(&Apache::lonhtmlcommon::end_pick_box());
                 $r->print('</td></tr>
@@ -2456,7 +2711,7 @@
     } else {
         $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'asng'});
     }
-    return;
+    return $numchgs;
 }
 
 sub process_request {
@@ -2466,7 +2721,7 @@
         $sectioncount,$stored,$rowColor1,$rowColor2) = @_;
 
     $r->print(&Apache::lonhtmlcommon::echo_form_input(
-                                        ['origin','action','state','page']));
+                                 ['origin','action','state','page','sortby']));
 
     my $earlyout = &validate_groupname($groupname,$action,$cdom,$cnum);
     if ($earlyout) {
@@ -2516,9 +2771,9 @@
     }
     if (($action eq 'create' && $outcome eq 'ok') || (($action eq 'modify') && 
        (($state eq 'memresult') || ($state eq 'addresult')))) {
-        &process_membership($r,$cdom,$cnum,$groupname,$tools,$enddate,
-                            $startdate,$userdata,$idx,$toolprivs,$usertools,
-                            $specificity,\@defprivs);
+        &process_membership($r,$cdom,$cnum,$action,$state,$groupname,$tools,
+                            $enddate,$startdate,$userdata,$idx,$toolprivs,
+                            $usertools,$specificity,\@defprivs,$memchg);
     }
     return;
 }
@@ -2621,11 +2876,13 @@
 }
 
 sub process_membership {
-    my ($r,$cdom,$cnum,$groupname,$tools,$enddate,$startdate,$userdata,$idx,
-        $toolprivs,$usertools,$specificity,$defprivs) = @_;
+    my ($r,$cdom,$cnum,$action,$state,$groupname,$tools,$enddate,$startdate,
+        $userdata,$idx,$toolprivs,$usertools,$specificity,$defprivs,$memchg)=@_;
     my %usersettings = ();
-    my @added= ();
-    my @failed = ();
+    my %added= ();
+    my %failed = ();
+    my $num_ok = 0;
+    my $num_fail = 0;
     my %group_privs = ();
     my %tooltype = ();
 
@@ -2655,40 +2912,126 @@
         $group_privs{$user} =~ s/:$//;
     }
 
+    my $now = time;
+    my @activate = ();
+    my @expire = ();
+    my @deletion = ();
+    my @reenable = ();
+    if ($state eq 'memresult') {
+        if (ref($$memchg{'activate'}) eq 'ARRAY') {
+            @activate = @{$$memchg{'activate'}};
+        }
+        if (ref($$memchg{'expire'}) eq 'ARRAY') {
+            @expire = @{$$memchg{'expire'}};
+        }
+        if (ref($$memchg{'deletion'}) eq 'ARRAY') {
+            @deletion = @{$$memchg{'deletion'}};
+        }
+        if (ref($$memchg{'reenable'}) eq 'ARRAY') {
+            @reenable = @{$$memchg{'reenable'}};
+        }
+        if (@expire + @deletion > 0) {
+            my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
+                                                                   $groupname);
+            foreach my $user (@expire) {
+                my ($currend,$currstart,@userprivs) = 
+                                  split(/:/,$membership{$groupname.':'.$user});
+                $group_privs{$user} = join(':',@userprivs); 
+                if ($currstart > $now) {
+                    $currstart = $now;
+                }
+                $usersettings{$groupname.':'.$user} = $now.':'.$currstart.':'.
+                                                      $group_privs{$user};
+                if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname,
+                                                       $user,$now,$currstart,
+                                                       $group_privs{$user}) eq 'ok') {
+                    push(@{$added{'expired'}},$user);
+                    $num_ok ++;
+                } else {
+                    push(@{$failed{'expired'}},$user);
+                    $num_fail ++;
+                }
+            }
+            foreach my $user (@deletion) {
+                $usersettings{$groupname.':'.$user} = $now.':-1:';
+                if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname,
+                                                       $user,$now,'-1','')
+                                                         eq 'ok') {
+                    push(@{$added{'deleted'}},$user);
+                    $num_ok ++;
+                } else {
+                    push(@{$failed{'deleted'}},$user);
+                    $num_fail ++;
+                }
+            }
+        }
+    }   
+
     foreach my $user (sort(keys(%{$usertools}))) {
-        $usersettings{$groupname.':'.$user} = $enddate.':'.$startdate.':'.
+        my $type;
+        my $start = $startdate;
+        my $end = $enddate;
+        if ($state eq 'memresult') {
+            $type = 'modified';
+            if (@activate > 0) {
+                if (grep/^$user$/,@activate) {
+                    $start = $now;
+                    $type = 'activated';
+                }
+            }
+            if (@reenable > 0) {
+                if (grep/^$user$/,@reenable) {
+                    $type = 'reenabled';
+                }
+            }
+        } else {
+            $type = 'added';
+        }
+        $usersettings{$groupname.':'.$user} = $end.':'.$start.':'.
                                               $group_privs{$user};
         if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname,
-                                                $user,$enddate,$startdate,
+                                                $user,$end,$start,
                                                 $group_privs{$user}) eq 'ok') {
-            push(@added,$user);
+            push(@{$added{$type}},$user);
+            $num_ok ++;
         } else {
-            push(@failed,$user);
+            push(@{$failed{$type}},$user);
+            $num_fail ++;
         }
     }
     my $roster_result = &Apache::lonnet::modify_coursegroup_membership($cdom,
                                                        $cnum,\%usersettings);
-    if (@added > 0) {
-        $r->print('Users were added with following privileges:<br />');
-        foreach my $user (@added) {
-            my @privs = split(/:/,$group_privs{$user});
-            my $privlist= '';
-            my $curr_tool = '';
-            foreach my $priv (@privs) {
-                unless ($curr_tool eq $tooltype{$priv}) {
-                    $curr_tool = $tooltype{$priv};
-                    $privlist .= '<b>'.$curr_tool.'</b>: ';
-                }
-                $privlist .= $$toolprivs{$curr_tool}{$priv}.', ';
-            }
-            $privlist =~ s/, $//;
-            $r->print($$userdata{$user}[$$idx{fullname}].'&nbsp;-&nbsp;'.$user.': '.$privlist.'<br />');
-        }
-    }
-    if (@failed > 0) {
-        $r->print('Addition of the following users was unsuccessful:<br />');
-        foreach my $user (@failed) {
-            $r->print($$userdata{$user}[$$idx{fullname}].' - '.$user.'<br />');
+    if ($num_ok) {
+        foreach my $type (sort(keys(%added))) { 
+            $r->print(&mt('The following users were successfully [_1]',$type));
+            if ($type eq 'activated' || $type eq 'added' || $type eq 'reenabled') {
+                $r->print(&mt(' with the following privileges'));
+            }
+            $r->print(':<br />');
+            foreach my $user (@{$added{$type}}) {
+                my $privlist;
+                if ($type eq 'activated' || $type eq 'added') {
+                    my @privs = split(/:/,$group_privs{$user});
+                    my $curr_tool = '';
+                    foreach my $priv (@privs) {
+                        unless ($curr_tool eq $tooltype{$priv}) {
+                            $curr_tool = $tooltype{$priv};
+                            $privlist .= '<b>'.$curr_tool.'</b>: ';
+                        }
+                        $privlist .= $$toolprivs{$curr_tool}{$priv}.', ';
+                    }
+                    $privlist =~ s/, $//;
+                }
+                $r->print($$userdata{$user}[$$idx{fullname}].'&nbsp;-&nbsp;'.$user.': '.$privlist.'<br />');
+            }
+        }
+    }
+    if ($num_fail) {
+        foreach my $type (sort(keys(%failed))) {
+            $r->print(&mt('The following users could not be [_1], because an error occurred:<br />',$type));
+            foreach my $user (@{$failed{$type}}) {
+                $r->print($$userdata{$user}[$$idx{fullname}].' - '.$user.'<br />');
+            }
         }
     }
     if ($roster_result eq 'ok') {
@@ -2870,8 +3213,8 @@
             state => 'change_settings',
             branch => 'settings',
             },
-          { text => 'Modify access, tools and/or privileges for previous,future'.
-                    'or current members',
+          { text => 'Modify access, tools and/or privileges for previous, '.
+                    'future, or current members',
             help => 'Course_Modify_Group_Membership',
             state => 'change_members',
             branch => 'members',
@@ -2899,10 +3242,17 @@
 
 sub member_privs_entries {
     my ($r,$tabcol,$rowColor1,$rowColor2,$usertools,$toolprivs,
-        $fixedprivs,$userdata,$idx,$showtools,$defprivs) = @_;
+        $fixedprivs,$userdata,$idx,$showtools,$defprivs,$excluded) = @_;
     my $rowColor;
     my $rowNum = 0;
     foreach my $user (sort(keys(%{$usertools}))) {
+        if (defined($excluded)) {
+            if (ref($excluded) eq 'ARRAY') {
+                if (grep/^$user$/,@{$excluded}) {
+                    next;
+                }
+            }
+        }
         my ($uname,$udom) = split(/:/,$user);
         if ($rowNum %2 == 1) {
             $rowColor = $rowColor1;
@@ -3118,10 +3468,10 @@
     @{$exclusions{'changepriv'}} = ('expire','changefunc');
 
     foreach my $change (@{$member_changes}) {
-        if ($change eq 'delete') {
+        if ($change eq 'deletion') {
             next;
         }
-        my @checks = ('delete');
+        my @checks = ('deletion');
         if (exists($exclusions{$change})) {
             push(@checks,@{$exclusions{$change}});
         }
@@ -3129,10 +3479,14 @@
         foreach my $item (@{$$memchg{$change}}) {
             my $match = 0;
             foreach my $check (@checks) {
-                if (@{$$memchg{$check}} > 0) {
-                    if (grep/^$item$/,@{$$memchg{$check}}) {
-                        $match = 1;
-                        last;
+                if (defined($$memchg{$check})) { 
+                    if (ref(@{$$memchg{$check}}) eq 'ARRAY') {
+                        if (@{$$memchg{$check}} > 0) {
+                            if (grep/^$item$/,@{$$memchg{$check}}) {
+                                $match = 1;
+                                last;
+                            }
+                        }
                     }
                 }
             }

--raeburn1140548163--