Annotation of loncom/interface/loncoursegroups.pm, revision 1.5

1.1       raeburn     1: #
                      2: # Copyright Michigan State University Board of Trustees
                      3: #
                      4: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      5: #
                      6: # LON-CAPA is free software; you can redistribute it and/or modify
                      7: # it under the terms of the GNU General Public License as published by
                      8: # the Free Software Foundation; either version 2 of the License, or
                      9: # (at your option) any later version.
                     10: #
                     11: # LON-CAPA is distributed in the hope that it will be useful,
                     12: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: # GNU General Public License for more details.
                     15: #
                     16: # You should have received a copy of the GNU General Public License
                     17: # along with LON-CAPA; if not, write to the Free Software
                     18: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     19: #
                     20: # /home/httpd/html/adm/gpl.txt
                     21: #
                     22: # http://www.lon-capa.org/
                     23: #
                     24: 
                     25: package Apache::loncoursegroups;
                     26: 
                     27: use strict;
                     28: use Apache::lonnet;
                     29: use Apache::loncommon;
                     30: use Apache::lonhtmlcommon;
                     31: use Apache::lonlocal;
1.3       raeburn    32: use Apache::lonnavmaps;
1.1       raeburn    33: use Apache::Constants qw(:common :http);
                     34: 
                     35: sub handler {
                     36:     my ($r) = @_;
1.3       raeburn    37: 
1.1       raeburn    38:     &Apache::loncommon::content_type($r,'text/html');
                     39:     $r->send_http_header;
                     40:                                                                                 
                     41:     if ($r->header_only) {
                     42:         return OK;
                     43:     }
                     44: 
                     45:     #  Needs to be in a course
                     46:     if (! ($env{'request.course.fn'})) {
                     47:         # Not in a course
                     48:         $env{'user.error.msg'}=
1.3       raeburn    49:      "/adm/coursegroups:mdg:0:0:Cannot edit or view course groups";
1.1       raeburn    50:         return HTTP_NOT_ACCEPTABLE;
                     51:     }
                     52: 
1.3       raeburn    53:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.5     ! raeburn    54:                         ['action','refpage','state','groupname','branch']);
1.3       raeburn    55:     my $function = &Apache::loncommon::get_users_function();
                     56:     my $tabcol = &Apache::loncommon::designparm($function.'.tabbg');
                     57:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                     58:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                     59: 
1.1       raeburn    60:     my $view_permission =
1.3       raeburn    61:           &Apache::lonnet::allowed('vcg',$env{'request.course.id'});
1.1       raeburn    62:     my $manage_permission =
1.3       raeburn    63:           &Apache::lonnet::allowed('mdg',$env{'request.course.id'});
                     64:     &Apache::lonhtmlcommon::clear_breadcrumbs();
                     65: 
                     66:     my %functions = (
                     67:                       email => 'E-mail',
                     68:                       discussion => 'Discussion boards',
                     69:                       chat => 'Chat',
                     70:                       files => 'File repository',
                     71:                       roster => 'Membership roster',
                     72:                       homepage => 'Group home page',
                     73:                     );
                     74: 
                     75:     my %idx = ();
                     76:     $idx{id} = &Apache::loncoursedata::CL_ID();
                     77:     $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
                     78:     $idx{udom} = &Apache::loncoursedata::CL_SDOM();
                     79:     $idx{uname} = &Apache::loncoursedata::CL_SNAME();
                     80: 
1.5     ! raeburn    81:     my $rowColor1 = "#dddddd";
        !            82:     my $rowColor2 = "#eeeeee";
        !            83: 
1.3       raeburn    84:     my $action = $env{'form.action'};
                     85:     if ($action eq 'create' || $action eq 'modify' || $action eq 'view') { 
                     86:         if ($view_permission || $manage_permission) {
                     87:             &group_administration($r,$action,$cdom,$cnum,$function,$tabcol,
1.5     ! raeburn    88:                                   \%functions,\%idx,$view_permission,
        !            89:                                   $manage_permission,$rowColor1,$rowColor2);
1.3       raeburn    90:         } else {
                     91:             $r->print('You do not have group administration '.
                     92:                       'privileges in this course');
                     93:         }
                     94:     } else {
                     95:         &print_main_menu($r,$cdom,$cnum,$function,$tabcol,\%functions,\%idx,
1.5     ! raeburn    96:                          $view_permission,$manage_permission,$action,
        !            97:                          $rowColor1,$rowColor2);
1.3       raeburn    98:     }
                     99:     return OK;
                    100: }
                    101: 
                    102: sub print_main_menu {
                    103:     my ($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,$view_permission,
1.5     ! raeburn   104:         $manage_permission,$action,$rowColor1,$rowColor2) = @_;
1.3       raeburn   105:     $r->print(&header('Course Groups',&mt('LON-CAPA Course Groups'),
1.5     ! raeburn   106:               undef,undef,undef,undef,$function));
1.3       raeburn   107:     &Apache::lonhtmlcommon::add_breadcrumb
                    108:         ({href=>"/adm/coursegroups",
                    109:           text=>"Course Groups",});
                    110:     $r->print(&Apache::lonhtmlcommon::breadcrumbs
1.5     ! raeburn   111:               (undef,'Course Groups'));
1.3       raeburn   112:     &display_groups($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,
1.5     ! raeburn   113:                     $view_permission,$manage_permission,$action,$rowColor1,
        !           114:                     $rowColor2);
1.3       raeburn   115:     $r->print(&footer());
                    116:     return;
                    117: }
                    118: 
                    119: sub display_groups {
                    120:     my ($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,$view_permission,
1.5     ! raeburn   121:         $manage_permission,$action,$rowColor1,$rowColor2) = @_;
1.3       raeburn   122:     my %curr_groups = ();
                    123:     my %grp_info = ();
                    124: 
1.5     ! raeburn   125:     my %actionlinks = (
        !           126:       modify => '<a href="/adm/coursegroups?action=modify&state=pick_task&refpage='.
        !           127:                 $env{'form.refpage'}.'&groupname=',
        !           128:       view => '<a href="/adm/'.$cdom.'/'.$cnum.'/',
        !           129:       delete => '<a href="/adm/coursegroups?action=delete&refpage='.
        !           130:                 $env{'form.refpage'}.'&groupname=',
        !           131:     );
        !           132:     my %actiontext = &Apache::lonlocal::texthash( 
        !           133:                           modify => 'Modify',
        !           134:                           view => 'View',
        !           135:                           delete => 'Delete',
        !           136:                      );  
1.3       raeburn   137:     $r->print('<br /><br />');
                    138:     if ($view_permission) {
1.5     ! raeburn   139:         if (!defined($action)) {
        !           140:             $action = 'view';
        !           141:         }
1.4       raeburn   142:         my %curr_groups;
                    143:         if (&Apache::loncommon::coursegroups(\%curr_groups,$cdom,$cnum)) {
1.3       raeburn   144:             $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.4       raeburn   145:             $r->print(<<"END");
1.3       raeburn   146:       <table border="0" cellpadding="4" cellspacing="1">
                    147:        <tr bgcolor="$tabcol" align="center">
                    148:         <td><b>Action</b></td>
                    149:         <td><b><a href="javascript:changeSort('groupname')">Group Name</a></b></td>
                    150:         <td><b><a href="javascript:changeSort('description')">Description</a></b></td>
                    151:         <td><b><a href="javascript:changeSort('creator')">Creator</a></b>
                    152:         </td>
                    153:         <td><b><a href="javascript:changeSort('creation')">Created</a></b>
                    154:         </td>
                    155:         <td><b><a href="javascript:changeSort('modified')">Last Modified</a></b>
                    156:         </td>
                    157:         <td><b>Functionality</b>
                    158:         </td>
                    159:         <td><b><a href="javascript:changeSort('quota')">Quota (Mb)</a></b></td>
                    160:         <td><b><a href="javascript:changeSort('totalmembers)">Members</a></b></td>
                    161:         <td><b><a href="javascript:changeSort('totalfiles')">Files</a></b></td>
                    162:         <td><b><a href="javascript:changeSort('boards')">Discussion boards</a></b></td>
                    163:         <td><b><a href="javascript:changeSort('diskuse')">Disk use</a></b></td>
                    164:        </tr>
                    165: END
1.4       raeburn   166:             my %Sortby = ();
                    167:             foreach my $group (sort(keys(%curr_groups))) {
                    168:                 %{$grp_info{$group}} = 
                    169:                                   &Apache::loncommon::get_group_settings(
1.3       raeburn   170:                                                          $curr_groups{$group});
1.5     ! raeburn   171:                 my $members_result = &group_members($cdom,$cnum,$group,
        !           172:                                                     \%grp_info);
1.4       raeburn   173:                 my $files_result = &group_files($group,\%grp_info); 
                    174:                 if ($env{'form.sortby'} eq 'groupname') {
                    175:                     push(@{$Sortby{$group}},$group);
                    176:                 } elsif ($env{'form.sortby'} eq 'description') {
                    177:                     push(@{$Sortby{$grp_info{$group}{'description'}}},
1.3       raeburn   178:                                                                      $group);
1.4       raeburn   179:                 } elsif ($env{'form.sortby'} eq 'creator') {
                    180:                     push(@{$Sortby{$grp_info{$group}{'creator'}}},$group);
                    181:                 } elsif ($env{'form.sortby'} eq 'creation') {
                    182:                     push(@{$Sortby{$grp_info{$group}{'creation'}}},$group);
                    183:                 } elsif ($env{'form.sortby'} eq 'modified') {
                    184:                     push(@{$Sortby{$grp_info{$group}{'modified'}}},$group);
                    185:                 } elsif ($env{'form.sortby'} eq 'quota') {
                    186:                     push(@{$Sortby{$grp_info{$group}{'quota'}}},$group);
                    187:                 } elsif ($env{'form.sortby'} eq 'totalmembers') {
                    188:                     push(@{$Sortby{$grp_info{$group}{'totalmembers'}}},
1.3       raeburn   189:                                                                        $group);
1.4       raeburn   190:                 } elsif ($env{'form.sortby'} eq 'totalfiles') {
1.5     ! raeburn   191:                     push(@{$Sortby{$grp_info{$group}{'totalfiles'}}},$group);
1.4       raeburn   192:                 } elsif ($env{'form.sortby'} eq 'boards') {
                    193:                     push(@{$Sortby{$grp_info{$group}{'boards'}}},$group);
                    194:                 } elsif ($env{'form.sortby'} eq 'diskuse') {
                    195:                     push(@{$Sortby{$grp_info{$group}{'diskuse'}}},$group);
                    196:                 } else {
                    197:                     push(@{$Sortby{$group}},$group);
                    198:                 }
                    199:             }
                    200:             my $rowNum = 0;
                    201:             my $rowColor;
                    202:             foreach my $key (sort(keys(%Sortby))) {
                    203:                 foreach my $group (@{$Sortby{$key}}) {
                    204:                     if ($rowNum %2 == 1) {
                    205:                         $rowColor = $rowColor1;
1.3       raeburn   206:                     } else {
1.4       raeburn   207:                         $rowColor = $rowColor2;
1.3       raeburn   208:                     }
1.4       raeburn   209:                     my $description = 
1.3       raeburn   210:                    &Apache::lonnet::unescape($grp_info{$group}{'description'});
1.4       raeburn   211:                     my $creator = $grp_info{$group}{'creator'};
                    212:                     my $creation = $grp_info{$group}{'creation'};
                    213:                     my $modified = $grp_info{$group}{'modified'}; 
                    214:                     my $quota = $grp_info{$group}{'quota'};
                    215:                     my $totalmembers = $grp_info{$group}{'totalmembers'};
                    216:                     my $totalfiles = $grp_info{$group}{'totalfiles'};
                    217:                     my $boards = $grp_info{$group}{'boards'};
                    218:                     my $diskuse = $grp_info{$group}{'diskuse'};
                    219:                     my $functionality;
1.5     ! raeburn   220:                     foreach my $tool (sort(keys(%{$functions}))) {
1.4       raeburn   221:                         if (defined($grp_info{$group}{functions}{$tool})) {
                    222:                             $functionality .= ' '.$tool;
1.3       raeburn   223:                         }
                    224:                     }
1.4       raeburn   225:                     if (!$functionality) {
                    226:                         $functionality = 'None available';
                    227:                     }
1.5     ! raeburn   228:                     my $link = $actionlinks{$action};
        !           229:                     if ($action eq 'modify' || $action eq 'delete') {
        !           230:                         $link .= $group;
        !           231:                     } else {
        !           232:                         $link .= $group.'/grppg?register=1';
        !           233:                     }
        !           234:                     $link .= '">'.$actiontext{$action}.'</a>';  
        !           235:                     $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>');
1.4       raeburn   236:                     $rowNum ++;
1.3       raeburn   237:                 }
1.4       raeburn   238:             }
                    239:             $r->print('</table>');
                    240:             $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.3       raeburn   241:         } else {
                    242:             $r->print('No groups exist');
                    243:         }
                    244:     } else {
1.4       raeburn   245:         my @coursegroups = split(/:/,$env{'request.course.groups'});
                    246:         if (@coursegroups > 0) {
                    247:             my %curr_groups;
                    248:             if (&Apache::loncommon::coursegroups(\%curr_groups,$cdom,$cnum)) {
                    249:                 foreach my $group (@coursegroups) {
                    250:                     my %group_info =  &Apache::loncommon::get_group_settings(
1.5     ! raeburn   251:                                         $curr_groups{$group});
1.4       raeburn   252:                     my $description = &Apache::lonnet::unescape(
1.5     ! raeburn   253:                                         $group_info{description});
1.4       raeburn   254:                     my ($uname,$udom) = split(/:/,$group_info{creator});
                    255:                     $r->print('<font size="+1"><a href="/adm/'.$udom.'/'.$uname.'/'.$group.'/grppg?register=1">'.$group,'</a><font><br /><small>'.$description.'</small><br /><br />');
                    256:                 }
                    257:             }
                    258:         } else {
                    259:             $r->print('You are not currently a member of any active groups in this course');
                    260:         }
1.3       raeburn   261:     }
                    262:     return;
                    263: }
                    264: 
                    265: sub group_administration {
                    266:     my ($r,$action,$cdom,$cnum,$function,$tabcol,$functions,$idx,
1.5     ! raeburn   267:         $view_permission,$manage_permission,$rowColor1,$rowColor2) = @_;
1.3       raeburn   268:     my %sectioncount = ();
                    269:     my @tools = ();
                    270:     my @types = ();
                    271:     my @roles = ();
                    272:     my @sections = ();
                    273:     my %users = ();
                    274:     my %userdata = ();
                    275:     my @members = ();
                    276:     my %usertools = ();
1.5     ! raeburn   277:     my %stored = ();
        !           278:     my %memchg;
        !           279:     my @member_changes = ('delete','expire','activate','reenable',
        !           280:                           'changefunc','changepriv');
        !           281:     my $state = $env{'form.state'};
        !           282:     my ($groupname,$description,$startdate,$enddate,$granularity,$specificity);
        !           283: 
        !           284:     if (defined($env{'form.groupname'})) {
        !           285:         $groupname = $env{'form.groupname'};
        !           286:     }
        !           287: 
        !           288:     if (($action eq 'create') && ($state eq '')) {
        !           289:         $state = 'pick_name';
        !           290:     }
        !           291:     if (($action eq 'create') || 
        !           292:         (($action eq 'modify') && ($state eq 'chgresult'))) { 
        !           293:         ($startdate,$enddate) = &get_dates_from_form();
        !           294:         if (defined($env{'form.description'})) {
        !           295:             $description = $env{'form.description'};
        !           296:         }
        !           297:         if (defined($env{'form.tool'})) {
        !           298:             @tools=&Apache::loncommon::get_env_multiple('form.tool');
        !           299:         }
        !           300:         if (defined($env{'form.granularity'})) {
        !           301:             $granularity=$env{'form.granularity'};
        !           302:         }
        !           303:         if (defined($env{'form.specificity'})) {
        !           304:             $specificity=$env{'form.specificity'};
        !           305:         }
        !           306: 
        !           307:     }
        !           308:     if (($action eq 'create') || (($action eq 'modify') 
        !           309:         && (($state eq 'pick_privs') || ($state eq 'addresult')))) {
        !           310:         if (defined($env{'form.member'})) {
        !           311:             @members = &Apache::loncommon::get_env_multiple('form.member');
        !           312:             foreach my $user (@members) {
        !           313:                 %{$usertools{$user}} = ();
        !           314:             }
        !           315:         }
        !           316:     }
1.3       raeburn   317: 
1.5     ! raeburn   318:     if (($action eq 'modify') && (($state eq 'change_privs') || ($state eq 'memresult'))) {
        !           319:         foreach my $chg (@member_changes) {
        !           320:             if (defined($env{'form.'.$chg})) {
        !           321:                 @{$memchg{$chg}} = &Apache::loncommon::get_env_multiple('form.'.$chg);
        !           322:             }
        !           323:         }
        !           324:         &check_changes(\@member_changes,\%memchg);
        !           325:         foreach my $change (@member_changes) {
        !           326:             if (($change eq 'delete') || ($change eq 'expire')) {
        !           327:                 next;
        !           328:             } 
        !           329:             foreach my $user (@{$memchg{$change}}) {
        !           330:                 %{$usertools{$user}} = ();
        !           331:             }
        !           332:         }
        !           333:     }
1.3       raeburn   334: 
1.5     ! raeburn   335:     if ($action eq 'modify') {
1.3       raeburn   336:         if ($state eq '') {
1.5     ! raeburn   337:             $state = 'pick_group';
1.3       raeburn   338:         } else {
1.5     ! raeburn   339:             %stored = &retrieve_settings($cdom,$cnum,$groupname);
        !           340:             if (ref($stored{'types'}) eq 'ARRAY') {
        !           341:                 @types = @{$stored{'types'}};
        !           342:             }
        !           343:             if (ref($stored{'roles'}) eq 'ARRAY') {
        !           344:                 @roles = @{$stored{'roles'}};
        !           345:             }
        !           346:             if (ref($stored{'sectionpick'}) eq 'ARRAY') {
        !           347:                 @sections = @{$stored{'sectionpick'}};
        !           348:             }
        !           349:             unless ($state eq 'chgresult') {
        !           350:                 if (ref($stored{'tool'}) eq 'ARRAY') { 
        !           351:                     @tools = @{$stored{'tool'}};
1.3       raeburn   352:                 }
1.5     ! raeburn   353:                 $startdate = $stored{'startdate'};
        !           354:                 $enddate = $stored{'enddate'};
        !           355:                 $description = $stored{'description'};
        !           356:                 $granularity = $stored{'granularity'};
        !           357:                 $specificity =  $stored{'specificity'};
1.3       raeburn   358:             }
                    359:         }
                    360:     }
                    361: 
                    362:     my %toolprivs = ();
                    363:     %{$toolprivs{'email'}} = (
                    364:                                  sgm => 'Send group mail',
                    365:                                  sgb => 'Broadcast mail',
                    366:                              );
                    367:     %{$toolprivs{'discussion'}} =  (
                    368:                                      cgb => 'Create boards',
                    369:                                      pgd => 'Post',
                    370:                                      pag => 'Anon. posts',
                    371:                                      rgi => 'Get identities', 
                    372:                                      vgb => 'View boards',
                    373:                                    );
                    374:     %{$toolprivs{'chat'}} =  (
                    375:                                 pgc => 'Chat',
                    376:                              );
                    377:     %{$toolprivs{'files'}} =  (
                    378:                                  rgf => 'Retrieve',
                    379:                                  ugf => 'Upload',
                    380:                                  dgf => 'Delete',
                    381:                               );
                    382:     %{$toolprivs{'roster'}} = (
                    383:                                  vgm => 'View',
                    384:                               );
                    385:     %{$toolprivs{'homepage'}} = (
                    386:                                 vgh => 'View page',
                    387:                                 mgh => 'Modify page',
                    388:                               );
                    389:     my %fixedprivs = ();
                    390:     %{$fixedprivs{'email'}} = ('sgm' => 1);
                    391:     %{$fixedprivs{'discussion'}} = ('vgb' => 1);
                    392:     %{$fixedprivs{'chat'}} = ('pgc' => 1);
                    393:     %{$fixedprivs{'files'}} = ('rgf' => 1);
                    394:     %{$fixedprivs{'roster'}} = ('vgm' => 1);
                    395:     %{$fixedprivs{'homepage'}} = ('vgh' => 1);
                    396: 
                    397:     my %elements = ();
                    398:     %{$elements{'create'}} = ();
                    399:     %{$elements{'modify'}} = ();
                    400:     %{$elements{'create'}{'pick_name'}} = (
                    401:         startdate_month => 'selectbox',
                    402:         startdate_hour => 'selectbox',
                    403:         enddate_month => 'selectbox',
                    404:         enddate_hour => 'selectbox',
                    405:         startdate_day => 'text',
                    406:         startdate_year => 'text',
                    407:         startdate_minute => 'text',
                    408:         startdate_second => 'text',
                    409:         enddate_day => 'text',
                    410:         enddate_year => 'text',
                    411:         enddate_minute => 'text',
                    412:         enddate_second => 'text',
                    413:         groupname => 'text',
                    414:         description => 'text',
                    415:         tool => 'checkbox',
                    416:         granularity => 'radio',
                    417:         no_end_date => 'checkbox',
                    418:     );
1.5     ! raeburn   419:     %{$elements{'modify'}{'change_settings'}} = (
        !           420:                                    %{$elements{'create'}{'pick_name'}},
        !           421:                                                 specificity => 'radio',
        !           422:                                                 defpriv => 'checkbox',
        !           423:                                                 autorole => 'checkbox',
        !           424:                                                 autoadd => 'radio',
        !           425:                                                 autodrop => 'radio',
        !           426:                                    );
        !           427:     if (ref($stored{'autorole'}) eq 'ARRAY') {
        !           428:         foreach my $role (@{$stored{'autorole'}}) {
        !           429:             $elements{'modify'}{'change_settings'}{'sec_'.$role} = 'selectbox'; 
        !           430:         }
        !           431:     }
1.3       raeburn   432:     %{$elements{'create'}{'pick_members'}} = (
                    433:         member => 'checkbox',
1.5     ! raeburn   434:         defpriv => 'checkbox',
        !           435:     );
        !           436: 
        !           437:     %{$elements{'modify'}{'add_members'}} = (
        !           438:         types => 'selectbox',
        !           439:         roles => 'selectbox',
1.3       raeburn   440:     );
1.5     ! raeburn   441: 
1.3       raeburn   442:     if (($action eq 'create') && ($state eq 'pick_name')) {
1.5     ! raeburn   443:         $elements{'create'}{'pick_name'}{'types'} = 'selectbox';
        !           444:         $elements{'create'}{'pick_name'}{'roles'} = 'selectbox';
        !           445:     }
        !           446:     if ((($action eq 'create') &&  
        !           447:         (($state eq 'pick_name') || ($state eq 'pick_privs'))) ||
        !           448:        (($action eq 'modify') && (($state eq 'change_settings') ||
        !           449:                                   ($state eq 'add_members')))) {
1.3       raeburn   450:         my $numsections = &Apache::loncommon::get_sections($cdom,$cnum,
1.5     ! raeburn   451:                                                            \%sectioncount);
1.3       raeburn   452:         if ($numsections > 0) {
                    453:             $elements{'create'}{'pick_name'}{'sectionpick'} = 'selectbox';
1.5     ! raeburn   454:             $elements{'modify'}{'change_mapping'}{'sectionpick'} = 'selectbox';
        !           455:             $elements{'modify'}{'add_members'}{'sectionpick'} = 'selectbox';
1.3       raeburn   456:         }
                    457:     }
1.5     ! raeburn   458: 
        !           459:     if ($action eq 'create') {
1.3       raeburn   460:         if (defined($env{'form.types'})) {
                    461:             @types=&Apache::loncommon::get_env_multiple('form.types');
                    462:         }
                    463:         if (defined($env{'form.roles'})) {
                    464:             @roles=&Apache::loncommon::get_env_multiple('form.roles');
                    465:         }
                    466:         if (defined($env{'form.sectionpick'})) {
                    467:             @sections=&Apache::loncommon::get_env_multiple('form.sectionpick');
                    468:             if (grep/^_all$/,@sections) {
                    469:                 @sections = sort {$a cmp $b} keys(%sectioncount);
                    470:             }
                    471:         }
1.5     ! raeburn   472:     }
        !           473: 
        !           474:     if (($state eq 'pick_members') || ($state eq 'pick_privs')) {
1.3       raeburn   475:         &build_members_list($cdom,$cnum,\@types,\@roles,
1.5     ! raeburn   476:                             \@sections,\%users,\%userdata);
1.3       raeburn   477:         if ((keys(%users) > 0) && (@tools > 0)) {
                    478:             foreach my $tool (@tools) {
1.5     ! raeburn   479:                 if ($granularity eq 'Yes') {
        !           480:                     $elements{$action}{'pick_members'}{'user_'.$tool} = 'checkbox';
1.3       raeburn   481:                 }
                    482:             }
1.5     ! raeburn   483:             $elements{$action}{'pick_members'}{'specificity'} = 'radio';
1.3       raeburn   484:         }
                    485:     }
                    486: 
1.5     ! raeburn   487:     if (($state eq 'pick_privs') || ($state eq 'change_privs') ||
        !           488:         (($specificity eq 'No') && 
        !           489:          (($state eq 'result') || ($state eq 'memresult')))) {
1.3       raeburn   490:         foreach my $tool (@tools) {
                    491:             my @values = &Apache::loncommon::get_env_multiple('form.user_'.$tool);
                    492:             foreach my $user (@values) {
                    493:                 unless(exists($usertools{$user}{$tool})) {
                    494:                     $usertools{$user}{$tool} = 1;
                    495:                 }
                    496:             }
                    497:         }
1.5     ! raeburn   498:         if ((($state eq 'pick_privs') || ($state eq 'change_privs'))
        !           499:             && ($specificity eq 'Yes')) {
        !           500:             foreach my $user (sort(keys(%usertools))) {
        !           501:                 foreach my $tool (keys(%{$usertools{$user}})) {
1.3       raeburn   502:                     foreach my $priv (keys(%{$toolprivs{$tool}})) {
                    503:                         unless (exists($fixedprivs{$tool}{$priv})) {
1.5     ! raeburn   504:                             $elements{$action}{$state}{'userpriv_'.$priv} = 'checkbox';
1.3       raeburn   505:                         }
                    506:                     }
                    507:                 }
                    508:             }
                    509:         }
                    510:     }
                    511:  
1.5     ! raeburn   512:     my $jscript = &Apache::loncommon::check_uncheck_jscript();
1.3       raeburn   513:     $jscript .= qq|
                    514: function nextPage(formname,nextstate) {
                    515:     formname.state.value= nextstate;
                    516:     formname.submit();
                    517: }
                    518: function backPage(formname,prevstate) {
                    519:     formname.state.value = prevstate;
                    520:     formname.submit();
                    521: }
                    522:                                                                                       
                    523: |;
                    524:     $jscript .= &Apache::lonhtmlcommon::set_form_elements(
1.5     ! raeburn   525:                            \%{$elements{$action}{$state}},\%stored);
        !           526:     my $page = 0;
        !           527:     my %states = ();
        !           528:     my %branchstates = ();
        !           529:     @{$states{'create'}} = ('pick_name','pick_members','pick_privs','result');
        !           530:     @{$states{'modify'}} = ('pick_group','pick_task');
        !           531:     @{$branchstates{'noprivs'}} = ('result');
        !           532:     @{$branchstates{'settings'}} = ('change_settings','chgresult');
        !           533:     @{$branchstates{'members'}} = ('change_members','change_privs','memresult');
        !           534:     @{$branchstates{'adds'}} = ('add_members','pick_members','pick_privs',
        !           535:                                 'addresult');
        !           536:     
        !           537:     if (defined($env{'form.branch'})) {
        !           538:         push (@{$states{$action}},@{$branchstates{$env{'form.branch'}}});
        !           539:     }
        !           540: 
        !           541:     if (($action eq 'create') || ($action eq 'modify')) {
        !           542:         my $done = 0;
        !           543:         my $i=0;
        !           544:         while ($i<@{$states{$action}} && !$done) {
        !           545:             if ($states{$action}[$i] eq $state) {
        !           546:                 $page = $i;
        !           547:                 $done = 1;
        !           548:             }
        !           549:             $i++;
        !           550:         }
        !           551:     }
1.3       raeburn   552: 
                    553:     my $loaditems =  &onload_action($action,$state);
                    554:     $r->print(&header('Course Groups Manager',&mt('LON-CAPA Groups Manager'),
1.5     ! raeburn   555:                           $jscript,$action,$state,$page,$function,$loaditems));
1.1       raeburn   556: 
1.3       raeburn   557:     if ($env{'form.refpage'} eq 'enrl') {
                    558:         &Apache::lonhtmlcommon::add_breadcrumb
                    559:         ({href=>"/adm/dropadd",
                    560:           text=>"Enrollment Manager",
                    561:           faq=>9,bug=>'Instructor Interface',});
                    562:     } else {
1.1       raeburn   563:         &Apache::lonhtmlcommon::add_breadcrumb
1.3       raeburn   564:        ({href=>"/adm/coursegroups",
                    565:           text=>"Course Groups",
                    566:           faq=>9,bug=>'Instructor Interface',});
                    567:     }
                    568: 
                    569:     my %trail = ();
1.5     ! raeburn   570:     %{$trail{'create'}} = &Apache::lonlocal::texthash (
1.3       raeburn   571:                             pick_name => 'Group Settings',
                    572:                             pick_members => 'Select Members',
                    573:                             pick_privs => 'Choose Privileges',
                    574:                             result => 'Creation Complete',
                    575:                           );
1.5     ! raeburn   576:     %{$trail{'modify'}} = &Apache::lonlocal::texthash(
        !           577:                             pick_group => 'Groups',
        !           578:                             pick_task => 'Choose Task',
        !           579:                             change_settings => 'Group Settings',
        !           580:                             change_members => 'Modify/Delete Members',
        !           581:                             change_privs => 'Change Privileges',
        !           582:                             change_mapping => 'Membership Mapping',
        !           583:                             add_members => 'Add Members',
        !           584:                             pick_members => 'Select Members',
        !           585:                             pick_privs => 'Choose Privileges',
        !           586:                             chgresult => 'Setting Changes Complete',
        !           587:                             memresult => 'Modifications Complete',
        !           588:                             addresult => 'Additions Complete',
        !           589:                           );
        !           590:     my %navbuttons = &Apache::lonlocal::texthash(
        !           591:                              gtns => 'Go to next step',
        !           592:                              gtps => 'Go to previous step',
        !           593:                              crgr => 'Create group',
        !           594:                              mose => 'Modify settings',
        !           595:                              gtpp => 'Go to previous page',
        !           596:                              adme => 'Add members',
        !           597:     );
1.3       raeburn   598:     if ((($action eq 'create') || ($action eq 'modify')) &&
                    599:               ($manage_permission)) {
                    600:         for (my $i=0; $i<@{$states{$action}}; $i++) {
                    601:             if ($state eq $states{$action}[$i]) {
                    602:                 &Apache::lonhtmlcommon::add_breadcrumb(
                    603:                    {text=>"$trail{$action}{$state}"});
                    604:                 $r->print(&Apache::lonhtmlcommon::breadcrumbs
                    605:                      (undef,'Course Groups Manager'));
1.5     ! raeburn   606:                 &display_control($r,$cdom,$cnum,$tabcol,$action,$state,$page,
        !           607:                        \%sectioncount,$groupname,$description,$functions,
        !           608:                        \@tools,\%toolprivs,\%fixedprivs,$startdate,$enddate,
        !           609:                        \%users,\%userdata,$idx,\%memchg,\%usertools,
        !           610:                        $function,$view_permission,$manage_permission,
        !           611:                        \%stored,$granularity,$specificity,\@types,\@roles,
        !           612:                        \@sections,\%states,\%navbuttons,$rowColor1,$rowColor2);
1.3       raeburn   613:                 last;
                    614:             } else {
1.5     ! raeburn   615:                 if (($state  =~ /^\w+result$/) && ($i > 0)) {
1.3       raeburn   616:                     &Apache::lonhtmlcommon::add_breadcrumb(
                    617:     {href=>"javascript:backPage(document.$state,'$states{$action}[0]')",
                    618:       text=>"$trail{$action}{$states{$action}[$i]}"});
                    619:                 } else { 
                    620:                     &Apache::lonhtmlcommon::add_breadcrumb(
                    621:      {href=>"javascript:backPage(document.$state,'$states{$action}[$i]')",
                    622:       text=>"$trail{$action}{$states{$action}[$i]}"});
                    623:                 }
                    624:             }
                    625:         }
                    626:     } elsif (($action eq 'view') && ($view_permission)) {
                    627:                         &Apache::lonhtmlcommon::add_breadcrumb(
                    628:                    {text=>"View groups"});
1.1       raeburn   629:         $r->print(&Apache::lonhtmlcommon::breadcrumbs
1.3       raeburn   630:                      (undef,'Course Groups Manager'));
                    631:         &display_groups($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,
1.5     ! raeburn   632:                         $view_permission,$manage_permission,$action,
        !           633:                         $rowColor1,$rowColor2);
1.3       raeburn   634: 
                    635:     }
                    636:     $r->print(&footer());
                    637:     return;
                    638: }
                    639: 
1.5     ! raeburn   640: sub retrieve_settings {
        !           641:     my ($cdom,$cnum,$groupname) = @_;
        !           642:     my %groupinfo;
        !           643:     my %stored;
        !           644:     my %curr_groups;
        !           645:     my $numgroups = &Apache::loncommon::coursegroups(\%curr_groups,$cdom,
        !           646:                                                              $cnum,$groupname);
        !           647:     if ($numgroups > 0) {
        !           648:         %groupinfo = &Apache::loncommon::get_group_settings(
        !           649:                                                      $curr_groups{$groupname});
        !           650:         $stored{'description'} = &Apache::lonnet::unescape(
        !           651:                                                     $groupinfo{'description'});
        !           652:         $stored{'startdate'} = $groupinfo{'startdate'};
        !           653:         $stored{'enddate'} = $groupinfo{'enddate'};
        !           654:         if ($stored{'enddate'} == 0) {
        !           655:             $stored{'no_end_date'} = 1;
        !           656:         }
        !           657:         $stored{'granularity'} = $groupinfo{'granularity'};
        !           658:         $stored{'specificity'} = $groupinfo{'specificity'};
        !           659:         $stored{'creation'} = $groupinfo{'creation'};
        !           660:         $stored{'creator'} = $groupinfo{'creator'};
        !           661: 
        !           662:         foreach my $tool (sort(keys(%{$groupinfo{'functions'}}))) {
        !           663:             if ($groupinfo{functions}{$tool} eq 'on') {
        !           664:                 push(@{$stored{tool}},$tool);
        !           665:             }
        !           666:         }
        !           667:         foreach my $role (@{$groupinfo{'roles'}}) {
        !           668:             push(@{$stored{roles}},$role);
        !           669:         }
        !           670:         foreach my $type (@{$groupinfo{'types'}}) {
        !           671:             push(@{$stored{types}},$type);
        !           672:         }
        !           673:         foreach my $section (@{$groupinfo{'sectionpick'}}) {
        !           674:             push(@{$stored{sectionpick}},$section);
        !           675:         }
        !           676:         foreach my $defpriv (@{$groupinfo{'defpriv'}}) {
        !           677:             push(@{$stored{defpriv}},$defpriv);
        !           678:         }
        !           679:         $stored{'autoadd'} = $groupinfo{'autoadd'};
        !           680:         $stored{'autodrop'} = $groupinfo{'autodrop'};
        !           681:         if (exists($groupinfo{'autosec'})) {
        !           682:             foreach my $role (sort(keys(%{$groupinfo{'autosec'}}))) {
        !           683:                 foreach my $section (@{$groupinfo{'autosec'}{$role}}) {
        !           684:                     push (@{$stored{'sec_'.$role}},$section);
        !           685:                 }
        !           686:                 if (@{$groupinfo{'autosec'}{$role}} > 0) {
        !           687:                     push(@{$stored{'autorole'}},$role);
        !           688:                 }
        !           689:             }
        !           690:         }
        !           691:     }
        !           692:     return %stored;
        !           693: }
        !           694: 
1.3       raeburn   695: sub display_control {
1.5     ! raeburn   696:     my ($r,$cdom,$cnum,$tabcol,$action,$state,$page,$sectioncount,$groupname,
1.3       raeburn   697:         $description,$functions,$tools,$toolprivs,$fixedprivs,$startdate,
1.5     ! raeburn   698:         $enddate,$users,$userdata,$idx,$memchg,$usertools,$function,
        !           699:         $view_permission,$manage_permission,$stored,$granularity,$specificity,
        !           700:         $types,$roles,$sections,$states,$navbuttons,$rowColor1,$rowColor2)=@_;
1.3       raeburn   701:     if ($action eq 'create') {
                    702:         if ($state eq 'pick_name') {
1.5     ! raeburn   703:             &general_settings_form($r,$cdom,$cnum,$action,$tabcol,$state,$page,
        !           704:                                    $functions,$tools,$toolprivs,$fixedprivs,
        !           705:                                    $sectioncount,$stored,$states,$navbuttons,
        !           706:                                    $rowColor1,$rowColor2);
1.3       raeburn   707:         } elsif ($state eq 'pick_members') {
1.5     ! raeburn   708:             &choose_members_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
        !           709:                                  $groupname,$description,$granularity,
        !           710:                                  $startdate,$enddate,$tools,$fixedprivs,
        !           711:                                  $toolprivs,$functions,$users,$userdata,$idx,
        !           712:                                  $stored,$states,$navbuttons,$rowColor1,
        !           713:                                  $rowColor2);
1.3       raeburn   714:         } elsif ($state eq 'pick_privs') {
1.5     ! raeburn   715:             &choose_privs_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
        !           716:                                $startdate,$enddate,$tools,$functions,
        !           717:                                $toolprivs,$fixedprivs,$userdata,$usertools,
        !           718:                                $idx,$states,$stored,$sectioncount,$navbuttons,
        !           719:                                $rowColor1,$rowColor2);
1.3       raeburn   720:         } elsif ($state eq 'result') {
1.5     ! raeburn   721:             &process_request($r,$cdom,$cnum,$tabcol,$action,$state,$page,
        !           722:                              $groupname,$description,$specificity,$userdata,
        !           723:                              $startdate,$enddate,$tools,$functions,
        !           724:                              $toolprivs,$usertools,$idx,$types,$roles,
        !           725:                              $sections,$states,$navbuttons,$memchg,
        !           726:                              $sectioncount,$stored,$rowColor1,$rowColor2);
        !           727:         }
        !           728:     } elsif ($action eq 'modify') {
        !           729:         my $groupname = $env{'form.groupname'};
        !           730:         if ($state eq 'pick_group') {
        !           731:             &display_groups($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,
        !           732:                             $view_permission,$manage_permission,$action,
        !           733:                             $rowColor1,$rowColor2);
        !           734:         } elsif ($state eq 'pick_task') {
        !           735:             &modify_menu($r,$groupname,$page);
        !           736:         } elsif ($state eq 'change_settings') {
        !           737:             &general_settings_form($r,$cdom,$cnum,$action,$tabcol,$state,$page,
        !           738:                                    $functions,$tools,$toolprivs,$fixedprivs,
        !           739:                                    $sectioncount,$stored,$states,$navbuttons,
        !           740:                                    $rowColor1,$rowColor2);
        !           741:         } elsif ($state eq 'change_members') {
        !           742:             &change_members_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
        !           743:                                  $groupname,$description,$startdate,$enddate,
        !           744:                                  $tools,$fixedprivs,$functions,$users,
        !           745:                                  $userdata,$granularity,$specificity,$idx,
        !           746:                                  $states,$navbuttons,$rowColor1,$rowColor2);
        !           747:         } elsif ($state eq 'add_members') {
        !           748:             &add_members_form($r,$tabcol,$action,$state,$page,$startdate,
        !           749:                               $enddate,$groupname,$description,$granularity,
        !           750:                               $sectioncount,$tools,$functions,$stored,$states,
        !           751:                               $navbuttons,$rowColor1,$rowColor2);
        !           752:         } elsif ($state eq 'pick_members') {
        !           753:             &choose_members_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
        !           754:                                  $groupname,$description,$granularity,
        !           755:                                  $startdate,$enddate,$tools,$fixedprivs,
        !           756:                                  $toolprivs,$functions,$users,$userdata,$idx,
        !           757:                                  $stored,$states,$navbuttons,$rowColor1,
        !           758:                                  $rowColor2);
        !           759:         } elsif ($state eq 'pick_privs') {
        !           760:             &choose_privs_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
        !           761:                                $startdate,$enddate,$tools,$functions,
        !           762:                                $toolprivs,$fixedprivs,$userdata,$usertools,
        !           763:                                $idx,$states,$stored,$sectioncount,$navbuttons,
        !           764:                                $rowColor1,$rowColor2);
        !           765:         } elsif ($state eq 'change_privs') {
        !           766:             &change_privs_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
        !           767:                                $startdate,$enddate,$tools,$functions,
        !           768:                                $toolprivs,$fixedprivs,$userdata,$usertools,
        !           769:                                $memchg,$idx,$states,$stored,$sectioncount,
        !           770:                                $navbuttons,$rowColor1,$rowColor2) = @_;
        !           771:         } elsif ($state eq 'chgresult' || $state eq 'memresult' || 
        !           772:                  $state eq 'addresult') {
        !           773:             &process_request($r,$cdom,$cnum,$tabcol,$action,$state,$page,
        !           774:                              $groupname,$description,$specificity,$userdata,
        !           775:                              $startdate,$enddate,$tools,$functions,
        !           776:                              $toolprivs,$usertools,$idx,$types,$roles,
        !           777:                              $sections,$states,$navbuttons,$memchg,
        !           778:                              $sectioncount,$stored,$rowColor1,$rowColor2);
1.1       raeburn   779:         }
                    780:     }
                    781: }
                    782: 
                    783: sub header {
1.5     ! raeburn   784:     my ($bodytitle,$title,$jscript,$action,$state,$page,$function,$loaditems) = @_;
1.1       raeburn   785:     my $html=&Apache::lonxml::xmlbegin();
1.3       raeburn   786:     my $bodytag=&Apache::loncommon::bodytag($bodytitle,$function,$loaditems);
                    787:     my $output = <<"END";
1.1       raeburn   788: $html
                    789: <head>
                    790: <title>$title</title>
1.3       raeburn   791: <script type="text/javascript">
                    792: $jscript
                    793: </script>
1.1       raeburn   794: </head>
                    795: $bodytag
1.3       raeburn   796: <form method="post" name="$state">
                    797: 
                    798: END
                    799:     if ($action eq 'create' || $action eq 'modify') {
                    800:         $output .= <<"END";
                    801:  <input type="hidden" name="action" value="$action" />
                    802:  <input type="hidden" name="state" value="" />
                    803:  <input type="hidden" name="origin" value="$state" />
1.5     ! raeburn   804:  <input type="hidden" name="page" value="$page" />
1.3       raeburn   805: END
                    806:     }
                    807:     return $output;
1.1       raeburn   808: }
                    809: 
1.3       raeburn   810: sub onload_action {
                    811:     my ($action,$state) = @_;
                    812:     my $loaditems;
                    813:     if ((defined($env{'form.origin'})) && ($action eq 'create') &&
                    814:                 ($state eq 'pick_name' || $state eq 'pick_members' || 
                    815:                  $state eq 'pick_privs')) {
                    816:         unless ($env{'form.origin'} eq '') {
                    817:             $loaditems = 
                    818:              'onload="javascript:setFormElements(document.'.$state.')"';
1.1       raeburn   819:         }
                    820:     }
1.5     ! raeburn   821:     if (($action eq 'modify') &&
        !           822:                 ($state eq 'change_settings' || $state eq 'change_members' ||
        !           823:                  $state eq 'change_privs') || $state eq 'add_members') {
        !           824:             $loaditems =
        !           825:              'onload="javascript:setFormElements(document.'.$state.')"';
        !           826:     }
1.3       raeburn   827:     return $loaditems;
1.1       raeburn   828: }
                    829: 
                    830: sub footer {
                    831:        return(<<ENDFOOT);
                    832:   </form>
                    833:  </body>
                    834: </html>
                    835: ENDFOOT
                    836: }
                    837: 
1.3       raeburn   838: sub build_members_list {
                    839:     my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_;
                    840:     my %access = ();
                    841:     foreach my $role (@{$roles}) {
                    842:         %{$$users{$role}} = ();
                    843:     }
                    844:     foreach my $type (@{$types}) {
                    845:         $access{$type} = $type;
                    846:     }
                    847:     &Apache::loncommon::get_course_users($cdom,$cnum,\%access,$roles,
1.5     ! raeburn   848:                                          $sections,$users,$userdata);
1.3       raeburn   849:     return;
                    850: }
                    851: 
                    852: sub group_files {
                    853:     return;
                    854: }
                    855: 
                    856: sub group_members {
1.4       raeburn   857:     my ($cdom,$cnum,$group,$group_info) = @_;
                    858:     my %memberhash = &Apache::lonnet::get_group_membership($cdom,$cnum,$group);
                    859:     my $now = time;
                    860:     my ($tmp)=keys(%memberhash);
                    861:     if ($tmp=~/^error:/) {
                    862:         $$group_info{'totalmembers'} = 'Unknown - an error occurred';
                    863:         return $tmp;
                    864:     }
                    865:     my $now = time;
                    866:     my $totalmembers = 0;
                    867:     my $active = 0;
                    868:     my $previous = 0;
                    869:     my $future = 0;
                    870:     foreach my $member (keys %memberhash) {
                    871:         $totalmembers ++;
                    872:         my ($end,$start) = split(/:/,$memberhash{$member});
                    873:         if (($end!=0) && ($end<$now)) {
                    874:             $previous ++;
                    875:         } elsif (($start!=0) && ($start>$now)) {
                    876:             $future ++;
                    877:         } else {
                    878:             $active ++;
                    879:         }
                    880:     }
                    881:     if ($totalmembers == 0) {
                    882:         $$group_info{$group}{'totalmembers'} = 'None';
                    883:     } else {
                    884:         $$group_info{$group}{'totalmembers'} = $active.' - active<br />'.$previous.' -previous<br />'.$future.' -future';
                    885:     }
                    886:     return 'ok';
1.3       raeburn   887: }
                    888: 
                    889: 
1.5     ! raeburn   890: sub general_settings_form {
        !           891:     my ($r,$cdom,$cnum,$action,$tabcol,$formname,$page,$functions,$tools,
        !           892:         $toolprivs,$fixedprivs,$sectioncount,$stored,$states,$navbuttons,
        !           893:         $rowColor1,$rowColor2) = @_;
        !           894:     my ($nexttext,$prevtext);
        !           895:     $r->print(' <br />
        !           896:  <table width="100%" cellpadding="0" cellspacing="0" border="0">
        !           897: ');
        !           898:     &groupsettings_options($r,$tabcol,$functions,$action,$formname,$stored,1);
        !           899:     $r->print(' 
        !           900:   <tr>
        !           901:    <td colspan="4">&nbsp;</td>
        !           902:   </tr>');
        !           903:     &access_date_settings($r,$tabcol,$action,$formname,$stored,2);
        !           904:     $r->print('
        !           905:   <tr>
        !           906:    <td colspan="4">&nbsp;</td>
        !           907:   </tr>');
        !           908:     if ($action eq 'create') {
        !           909:         &membership_options($r,$action,$formname,$tabcol,$sectioncount,3);
        !           910:         $nexttext = $$navbuttons{'gtns'};
        !           911:     } else {
        !           912:         my @available = ();
        !           913:         my @unavailable = ();
        !           914:         &check_tools($functions,$tools,\@available,\@unavailable);
        !           915:         @{$tools} = sort(keys(%{$functions}));
        !           916:         &privilege_specificity($r,$tabcol,$rowColor1,$rowColor2,$action,
        !           917:                                3,$tools,$stored,$toolprivs,$fixedprivs,
        !           918:                                \@available,$formname);
        !           919:         $r->print('
        !           920:   <tr>
        !           921:    <td colspan="4">&nbsp;</td>
        !           922:   </tr>');
        !           923:         &mapping_options($r,$action,$formname,$page,$tabcol,$sectioncount,
        !           924:                          $states,$stored,$navbuttons,4,5,$rowColor1,
        !           925:                          $rowColor2);
        !           926:         $nexttext = $$navbuttons{'mose'};
        !           927:     }
        !           928:     $prevtext = $$navbuttons{'gtpp'};
        !           929:     &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
        !           930:                         $$states{$action}[$page+1],$nexttext);
        !           931:     $r->print('
        !           932:  </table>');
        !           933:     return;
        !           934: }
        !           935: 
        !           936: sub groupsettings_options {
        !           937:     my ($r,$tabcol,$functions,$action,$formname,$stored,$image) = @_;
1.1       raeburn   938:     my %lt = &Apache::lonlocal::texthash(
                    939:         'gdat' => 'Group open and close dates',
                    940:         'sten' => 'Set a start date/time and end date/time for the group',
                    941:         'gfun' => 'Group functionality',
1.5     ! raeburn   942:         'gnde' => 'Group name, description and available functionality',
        !           943:         'desc' => 'Description',
        !           944:         'func' => 'Functionality',
        !           945:         'gnam' => 'Group Name',
        !           946:         'doyo' => 'Do you want to assign different functionality '.
        !           947:                   'to different group members?',
1.1       raeburn   948:     );
1.5     ! raeburn   949:     &topic_bar($r,$tabcol,$image,$lt{'gnde'});
        !           950:     $r->print('
1.3       raeburn   951:    <tr>
                    952:     <td>&nbsp;</td>
                    953:     <td colspan="3">
                    954:      <table border="0" cellpadding="2" cellspacing="2">
                    955:       <tr>
1.5     ! raeburn   956:        <td><b>'.$lt{'gnam'}.':</b></td>
        !           957:        <td colspan="5">
        !           958: ');
        !           959:     if ($action eq 'create') {
        !           960:         $r->print('<input type="text" name="groupname" size="25" />');
        !           961:     } else {
        !           962:         $r->print('<input type="hidden" name="groupname" value="'.
        !           963:                          $env{'form.groupname'}.'" />'.$env{'form.groupname'});
        !           964:     }
        !           965:     $r->print(<<"END");
1.3       raeburn   966:        </td>
                    967:       <tr>
                    968:       <tr>
1.5     ! raeburn   969:        <td><b>$lt{'desc'}:</b></td>
        !           970:        <td colspan="5"><input type="text" name="description" size="40"
        !           971:                                                     value="" />
1.3       raeburn   972:        </td>
                    973:       <tr>
                    974:       <tr>
1.5     ! raeburn   975:        <td><b>$lt{'func'}:</b></td>
1.3       raeburn   976: END
                    977:     my $numitems = keys(%{$functions});
                    978:     my $halfnum = int($numitems/2);
                    979:     my $remnum = $numitems%2;
                    980:     if ($remnum) {
                    981:         $halfnum ++;
                    982:     }
1.5     ! raeburn   983:     my @allfunctions = sort(keys (%{$functions}));
1.3       raeburn   984:     for (my $i=0; $i<$halfnum; $i++) {
                    985:         $r->print('<td><input type="checkbox" name="tool" value="'.
                    986:                   $allfunctions[$i].'" />&nbsp;'.
                    987:                    $$functions{$allfunctions[$i]}.'</td>
                    988:                    <td>&nbsp;</td><td>&nbsp;</td>');
                    989:     }
                    990:     $r->print('<td><input type="button" value="check all" '.
                    991:               'onclick="javascript:checkAll(document.'.$formname.'.tool)" />'.
                    992:               '</td></tr><tr><td>&nbsp;</td>');
                    993:     for (my $j=$halfnum; $j<@allfunctions; $j++) {
                    994:         $r->print('<td><input type="checkbox" name="tool" value="'.
                    995:                   $allfunctions[$j].'" />&nbsp;'.
                    996:                   $$functions{$allfunctions[$j]}.'</td>
                    997:                   <td>&nbsp;</td><td>&nbsp;</td>');
                    998:     }
                    999:     if ($remnum) {
                   1000:         $r->print('<td>&nbsp;</td>');
                   1001:     }
1.5     ! raeburn  1002:     $r->print('
1.3       raeburn  1003:        <td>
1.5     ! raeburn  1004:         <input type="button" value="uncheck all"
        !          1005:           onclick="javascript:uncheckAll(document.'.$formname.'.tool)" />
1.3       raeburn  1006:        </td>
                   1007:       </tr>
                   1008:       <tr>
                   1009:        <td><b>Granularity:</b></td>
1.5     ! raeburn  1010:        <td colspan="9">'.$lt{'doyo'}.'&nbsp;<input type="radio" name="granularity" value="Yes" />'.&mt('Yes').'&nbsp;<input type="radio" name="granularity" value="No" checked="checked" />'.&mt('No'));
        !          1011:     if ($action eq 'modify') {
        !          1012:         $r->print('&nbsp;&nbsp;('.&mt('Currently set to "[_1]"',
        !          1013:                                       $$stored{'granularity'}).')');
        !          1014:     }
        !          1015:     $r->print('
        !          1016:        </td>
        !          1017:       </tr>
1.3       raeburn  1018:      </table>
                   1019:     </td>
                   1020:    </tr>
1.5     ! raeburn  1021: ');
        !          1022:     return;
        !          1023: }
        !          1024: 
        !          1025: sub membership_options {
        !          1026:     my ($r,$action,$state,$tabcol,$sectioncount,$image) = @_;
        !          1027:     my %lt = &Apache::lonlocal::texthash(
        !          1028:                 'pipa' => 'Pick parameters to generate membership list',
        !          1029:                 'gmem' => 'Group membership options',
        !          1030:                 'picr' => 'Pick the criteria to use to build a list of '.
        !          1031:                           'course users from which you will select ',
        !          1032:                 'meof' => 'members of the new group.',
        !          1033:                 'adme' => 'additional members of the group.',
        !          1034:                 'ifno' => 'If you do not wish to add members when you first '.
        !          1035:                           'create the group, do not make any selections',  
        !          1036:                 'acty' => 'Access types',
        !          1037:                 'coro' => 'Course roles',
        !          1038:                 'cose' => 'Course sections',
        !          1039:              );
        !          1040:     my %status_types = (
        !          1041:                    active => &mt('Currently has access'),
        !          1042:                    previous => &mt('Previously had access'),
        !          1043:                    future => &mt('Will have future access'),
        !          1044:                    );
        !          1045:                                                                                  
        !          1046:     my @roles = ('st','cc','in','ta','ep','cr');
        !          1047: 
        !          1048:     my @sections = keys(%{$sectioncount});
        !          1049: 
        !          1050:     &topic_bar($r,$tabcol,$image,$lt{'pipa'});
        !          1051:     $r->print('
1.3       raeburn  1052:    <tr>
                   1053:     <td>&nbsp;</td>
                   1054:     <td colspan="3">
1.5     ! raeburn  1055:      <b>'.$lt{'gmem'}.'</b><br/>'.$lt{'picr'});
        !          1056:     if ($action eq 'create') {
        !          1057:         $r->print($lt{'meof'}.'<br />'.$lt{'ifno'});
        !          1058:     } else {
        !          1059:         $r->print($lt{'adme'});
        !          1060:     }
        !          1061:     $r->print('
        !          1062:      <br />
        !          1063:      <br />
1.3       raeburn  1064:      <table border="0">
                   1065:       <tr>
1.5     ! raeburn  1066:        <td><b>'.$lt{'acty'}.'</b></td>
1.3       raeburn  1067:        <td>&nbsp;</td>
1.5     ! raeburn  1068:        <td><b>'.$lt{'coro'}.'</b></td>');
1.3       raeburn  1069:     if (@sections >0) {
1.5     ! raeburn  1070:         $r->print('
1.3       raeburn  1071:        <td>&nbsp;</td>
                   1072:        <td><b>'.$lt{'cose'}.'</b></td>
                   1073:        <td>&nbsp;</td>');
                   1074:     }
                   1075:     $r->print('</tr><tr>');
                   1076:     $r->print(&Apache::lonhtmlcommon::status_select_row(\%status_types));
                   1077:     $r->print('<td>&nbsp;</td>');
                   1078:     $r->print(&Apache::lonhtmlcommon::role_select_row(\@roles));
                   1079:     if (@sections > 0) {
1.5     ! raeburn  1080:         @sections = sort {$a cmp $b} @sections;
        !          1081:         unshift(@sections,'_all'); # Put 'all' at the front of the list
        !          1082:         unshift(@sections,'_nosec'); # Put 'no sections' next
        !          1083:         $r->print('<td>&nbsp;</td>
        !          1084:                    <td colspan="3" align="center" valign="top">'.
        !          1085:         &sections_selection(\@sections,'sectionpick').'</td>');
1.3       raeburn  1086:     }
                   1087:     $r->print('
                   1088:       </tr>
                   1089:      </table>
                   1090:     </td>
1.5     ! raeburn  1091:    </tr>');
        !          1092:     return;
        !          1093: }
        !          1094: 
        !          1095: sub sections_selection {
        !          1096:     my ($sections,$elementname) = @_;
        !          1097:     my $section_sel;
        !          1098:     my $numvisible = 4;
        !          1099:     if (@{$sections} < 4) {
        !          1100:         $numvisible = @{$sections};
        !          1101:     }
        !          1102:     foreach my $sec (@{$sections}) {
        !          1103:         if ($sec eq '_all') {
        !          1104:             $section_sel .= '  <option value="'.$sec.'" />all sections'."\n";
        !          1105:         } elsif ($sec eq '_nosec') {
        !          1106:             $section_sel .= '  <option value="'.$sec.'" />no section'."\n"; 
        !          1107:         } else {
        !          1108:             $section_sel .= '  <option value="'.$sec.'" />'.$sec."\n";
        !          1109:         }
        !          1110:     }
        !          1111:     my $output = '
        !          1112:         <select name="'.$elementname.'" multiple="true" size="'.$numvisible.'">
        !          1113:           '.$section_sel.'
        !          1114:         </select>';
        !          1115:     return $output;
        !          1116: }
        !          1117: 
        !          1118: sub access_date_settings {
        !          1119:     my ($r,$tabcol,$action,$formname,$stored,$image) = @_;
        !          1120:     my %lt = &Apache::lonlocal::texthash(
        !          1121:                 'sten' => 'Default start and end dates for group access',
        !          1122:              );
        !          1123:     my $starttime = time;
        !          1124:     my $endtime = time+(6*30*24*60*60); # 6 months from now, approx
        !          1125:     if ($action eq 'modify') {
        !          1126:         $starttime = $$stored{'startdate'};
        !          1127:         unless ($$stored{'enddate'} == 0) {
        !          1128:             $endtime = $$stored{'enddate'};
        !          1129:         }
        !          1130:     }
        !          1131:     my ($start_table,$end_table) = &date_setting_table
        !          1132:                                     ($starttime,$endtime,$formname);
        !          1133:     &topic_bar($r,$tabcol,$image,$lt{'sten'});
        !          1134:     $r->print('
        !          1135:    <tr>
        !          1136:     <td>&nbsp;</td>
        !          1137:     <td colspan="3">'.$start_table.'</td>
        !          1138:    <tr>
1.3       raeburn  1139:    <tr>
                   1140:     <td colspan="4">&nbsp;</td>
                   1141:    </tr>
                   1142:    <tr>
                   1143:     <td>&nbsp;</td>
1.5     ! raeburn  1144:     <td colspan="3">'.$end_table.'</td>
        !          1145:    <tr>');
1.3       raeburn  1146:     return;
                   1147: }
                   1148: 
1.5     ! raeburn  1149: sub choose_members_form {
        !          1150:     my ($r,$cdom,$cnum,$tabcol,$action,$formname,$page,$groupname,$description,
        !          1151:         $granularity,$startdate,$enddate,$tools,$fixedprivs,$toolprivs,
        !          1152:         $functions,$users,$userdata,$idx,$stored,$states,$navbuttons,
        !          1153:         $rowColor1,$rowColor2) = @_;
        !          1154:     my @regexps = ('user_','userpriv_','sec_');
        !          1155:     my %origmembers;
1.3       raeburn  1156:     $r->print(&Apache::lonhtmlcommon::echo_form_input(
1.5     ! raeburn  1157:          ['origin','action','state','page','member','specificity','branch',
        !          1158:           'defpriv','autorole','autoadd','autodrop'],
        !          1159:          \@regexps));
        !          1160:     my $earlyout = &validate_groupname($groupname,$action,$cdom,$cnum);
        !          1161:     $r->print('
        !          1162: <table width="100%" cellpadding="0" cellspacing="0" border="0">
1.1       raeburn  1163:  <tr>
                   1164:   <td>&nbsp;</td>
1.5     ! raeburn  1165:   <td colspan="3">
        !          1166: ');
        !          1167:     if ($earlyout) {
        !          1168:         $r->print($earlyout.'</td></tr>');
        !          1169:         &display_navbuttons($r,$formname,$$states{$action}[$page-1],
        !          1170:                            $$navbuttons{'gtps'});
        !          1171:         $r->print('</table>');
1.3       raeburn  1172:         return;
1.5     ! raeburn  1173:     } 
        !          1174:     my ($specimg,$memimg);
        !          1175:     my @available = ();
        !          1176:     my @unavailable = ();
        !          1177:     &check_tools($functions,$tools,\@available,\@unavailable);
        !          1178:     if ($action eq 'create') {
        !          1179:         &print_current_settings($r,$action,$tabcol,$rowColor1,$rowColor2,
        !          1180:                                 $functions,$startdate,$enddate,$groupname,
        !          1181:                                 $description,$granularity,\@available,
        !          1182:                                 \@unavailable);
        !          1183:         $specimg = 4;
        !          1184:         $memimg = 5;
        !          1185:     } else {
        !          1186:         $specimg = 2;
        !          1187:         $memimg = 3;
        !          1188:         my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
        !          1189:                                                                $groupname);
        !          1190:         foreach my $key (sort(keys(%membership))) {
        !          1191:             if ($key =~ /^\Q$groupname\E:([^:]+):([^:]+)$/) {
        !          1192:                 my $uname = $1;
        !          1193:                 my $udom = $2;
        !          1194:                 my $user = $uname.':'.$udom;
        !          1195:                 $origmembers{$user} = 1; 
        !          1196:             }
        !          1197:         }
        !          1198:     }
        !          1199:     &privilege_specificity($r,$tabcol,$rowColor1,$rowColor2,$action,
        !          1200:                           $specimg,$tools,$stored,$toolprivs,
        !          1201:                           $fixedprivs,\@available,$formname);
        !          1202:     my $newusers = &pick_new_members($r,$action,$formname,$tabcol,$rowColor1,
        !          1203:                                     $rowColor2,\@available,$idx,$stored,
        !          1204:                                     $memimg,$users,$userdata,$granularity,
        !          1205:                                     \%origmembers);
        !          1206:     if ($newusers || $action eq 'create') {
        !          1207:         &display_navbuttons($r,$formname,$$states{$action}[$page-1],
        !          1208:                             $$navbuttons{'gtps'},$$states{$action}[$page+1],
        !          1209:                             $$navbuttons{'gtns'});
        !          1210:     } else {
        !          1211:         &display_navbuttons($r,$formname,$$states{$action}[$page-1],
        !          1212:                             $$navbuttons{'gtps'});
1.3       raeburn  1213:     }
1.5     ! raeburn  1214:     $r->print('</table>');
        !          1215:     return;
        !          1216: }
        !          1217: 
        !          1218: sub display_navbuttons {
        !          1219:     my ($r,$formname,$prev,$prevtext,$next,$nexttext) = @_;
        !          1220:     $r->print('
        !          1221:     <tr>
        !          1222:      <td colspan="4">&nbsp;</td>
        !          1223:     </tr>
        !          1224:     <tr>
        !          1225:      <td>&nbsp;</td>
        !          1226:      <td colspan="3">');
        !          1227:     if ($prev) {
        !          1228:         $r->print('
        !          1229:       <input type="button" name="previous" value = "'.$prevtext.'"
        !          1230:     onclick="javascript:backPage(document.'.$formname.','."'".$prev."'".')"/>
        !          1231:    &nbsp;&nbsp;&nbsp;');
        !          1232:     }
        !          1233:     if ($next) {
        !          1234:         $r->print('
        !          1235:       <input type="button" name="next" value="'.$nexttext.'"
        !          1236:  onclick="javascript:nextPage(document.'.$formname.','."'".$next."'".')" />');
        !          1237:     }
        !          1238:     $r->print('
        !          1239:      </td>
        !          1240:     </tr>
        !          1241: ');
        !          1242: }
        !          1243: 
        !          1244: sub check_tools {
        !          1245:     my ($functions,$tools,$available,$unavailable) = @_;
        !          1246:     foreach my $item (sort(keys(%{$functions}))) {
        !          1247:         if (grep/^$item$/,@{$tools}) {
        !          1248:             push(@{$available},$item);
        !          1249:         } else {
        !          1250:             push(@{$unavailable},$item);
        !          1251:         }
        !          1252:     }
        !          1253:     return;
        !          1254: }
        !          1255: 
        !          1256: sub print_current_settings {
        !          1257:     my ($r,$action,$tabcol,$rowColor1,$rowColor2,$functions,$startdate,$enddate,
        !          1258:            $groupname,$description,$granularity,$available,$unavailable) =@_;
        !          1259: 
        !          1260:     my %lt = &Apache::lonlocal::texthash(
        !          1261:         grna => 'Group Name',
        !          1262:         desc => 'Description',
        !          1263:         grfn => 'Group Functions',
        !          1264:         gran => 'Granularity',
        !          1265:         dfac => 'Default access dates',
        !          1266:         ygrs => 'Your group selections',
        !          1267:         tfwa => 'The following settings will apply to the group:',
        !          1268:         difn => 'Different functionality<br />for different users:',
        !          1269:         stda => 'Start date',
        !          1270:         enda => 'End date:',
        !          1271:     );
1.3       raeburn  1272:     my $showstart = &Apache::lonlocal::locallocaltime($startdate);
1.5     ! raeburn  1273:     my $showend;
        !          1274:     if ($enddate == 0) {
        !          1275:         $showend = &mt('No end date set'); 
        !          1276:     } else {
        !          1277:         $showend = &Apache::lonlocal::locallocaltime($enddate);
        !          1278:     }
        !          1279:     $r->print('<table border="0" cellpadding="0" cellspacing="20">');
        !          1280:     if ($action eq 'create') {
        !          1281:         $r->print('
1.3       raeburn  1282: <tr>
1.5     ! raeburn  1283:  <td><font face="arial,helvetica,sans-serif"><b>'.$lt{'ygrs'}.'</b></font>
        !          1284: <br />'.$lt{'tfwa'}.'
1.3       raeburn  1285:  </td>
1.5     ! raeburn  1286: </tr>');
        !          1287:     }
        !          1288:     $r->print('<tr><td>');
1.3       raeburn  1289:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
                   1290:     $r->print('
1.5     ! raeburn  1291: <tr>
        !          1292:  <td>
1.3       raeburn  1293: <table cellspacing="1" cellpadding="4">
                   1294:  <tr bgcolor="'.$tabcol.'" align="center">
1.5     ! raeburn  1295:   <td><b>'.$lt{'grna'}.'</b></td>
        !          1296:   <td><b>'.$lt{'desc'}.'</b></td>
        !          1297:   <td><b>'.$lt{'grfn'}.'</b></td>
        !          1298:   <td><b>'.$lt{'gran'}.'</b></td>
        !          1299:   <td><b>'.$lt{'dfac'}.'</b></td>
1.3       raeburn  1300:  </tr>
                   1301:  <tr bgcolor="'.$rowColor2.'">
                   1302:   <td valign="top"><small>'.$groupname.'</small></td>
                   1303:   <td valign="top"><small>'.$description.'</small></td>
                   1304:   <td>
                   1305: ');
1.5     ! raeburn  1306:     if (@{$available} > 0) {
1.3       raeburn  1307:         $r->print('<small><b>Available:</b></small>
                   1308:                     <table cellpadding="" cellspacing="1"><tr>');
1.5     ! raeburn  1309:         my $rowcell = int(@{$available}/2) + @{$available}%2;
        !          1310:         for (my $i=0; $i<@{$available}; $i++) {
        !          1311:             if (@{$available} > 3) {
1.3       raeburn  1312:                 if ($i==$rowcell) {
                   1313:                     $r->print('</tr><tr>');
                   1314:                 }
                   1315:             }
1.5     ! raeburn  1316:             $r->print('<td><small>'.$$functions{$$available[$i]}.
1.3       raeburn  1317:                                           '</small></td><td>&nbsp;</td>');
                   1318:         }
1.5     ! raeburn  1319:         if ((@{$available} > 3) && (@{$available}%2)) {
1.3       raeburn  1320:             $r->print('<td>&nbsp;</td><td>&nbsp;</td>');
                   1321:         }
                   1322:         $r->print('</tr></table><br />');
                   1323:     }
1.5     ! raeburn  1324:     if (@{$unavailable} > 0) {
1.3       raeburn  1325:         $r->print('<small><b>Unavailable:</b></small>
                   1326:                     <table cellpadding="0" cellspacing="1"  border="0"><tr>');
1.5     ! raeburn  1327:         my $rowcell = int(@{$unavailable}/2) + @{$unavailable}%2;
        !          1328:         for (my $j=0; $j<@{$unavailable}; $j++) {
        !          1329:             if (@{$unavailable} > 3) {
1.3       raeburn  1330:                 if ($j==$rowcell) {
                   1331:                     $r->print('</tr><tr>');
                   1332:                 }
                   1333:             }
1.5     ! raeburn  1334:             $r->print('<td><small>'.$$functions{$$unavailable[$j]}.
1.3       raeburn  1335:                                               '</small></td><td>&nbsp;</td>');
                   1336:         }
1.5     ! raeburn  1337:         if ((@{$unavailable} > 3) && (@{$unavailable}%2)) {
1.3       raeburn  1338:             $r->print('<td>&nbsp;</td><td>&nbsp;</td>');
                   1339:         }
                   1340:         $r->print('</tr></table>');
                   1341:     }
                   1342:     $r->print(<<"END");
                   1343:   </td>
1.5     ! raeburn  1344:   <td valign="top"><small><b>$lt{'difn'}
        !          1345:   </b> $granularity</small> 
        !          1346:   <td valign="top"><small><b>$lt{'stda'}</b> $showstart<br />
        !          1347:       <b>$lt{'enda'}</b> $showend</small>
1.3       raeburn  1348:   </td>
                   1349:  </tr>
                   1350: </table>
1.5     ! raeburn  1351: </td>
        !          1352: </tr>
1.3       raeburn  1353: END
                   1354:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.5     ! raeburn  1355:     $r->print('</td></tr></table><br />');
        !          1356:     return;
        !          1357: }
        !          1358: 
        !          1359: sub pick_new_members {
        !          1360:     my ($r,$action,$formname,$tabcol,$rowColor1,$rowColor2,$available,$idx,
        !          1361:         $stored,$img,$users,$userdata,$granularity,$origmembers) = @_;
        !          1362:     my %lt = &Apache::lonlocal::texthash(
        !          1363:           'gpme' => 'Group membership',
        !          1364:           'addm' => 'Add members',
        !          1365:           'setf' => 'Set functionality',
        !          1366:           'func' => 'Functionality',
        !          1367:           'nome' => 'No members to add at this time.',
        !          1368:           'nnew' => 'There are no users to add as new members, as all users'.
        !          1369:                     ' matching the specified type(s), role(s), and/or '.
        !          1370:                     'section(s) are already affiliated with this group.',
        !          1371:           'yoma' =>  'You may need to use the '."'".'modify existing, past or '.
        !          1372:                      'future members'."'".' page if you need to re-enable '.
        !          1373:                      'or activate access for previous or future members.',
        !          1374:     );
        !          1375:     my %members;
        !          1376:     my $totalusers = 0;
        !          1377:     my $newusers = 0;
1.3       raeburn  1378:     foreach my $role (keys(%{$users})) {
                   1379:         foreach my $user (keys(%{$$users{$role}})) {
1.5     ! raeburn  1380:             $totalusers ++;
        !          1381:             if (ref($origmembers) eq 'HASH') {
        !          1382:                 if (exists($$origmembers{$user})) {
        !          1383:                     next;
        !          1384:                 }
        !          1385:             }    
1.3       raeburn  1386:             unless (defined($members{$user})) {
                   1387:                 @{$members{$user}} = @{$$userdata{$user}};
1.5     ! raeburn  1388:                 $newusers ++;
1.3       raeburn  1389:             }
                   1390:         }
                   1391:     }
                   1392:     if (keys(%members) > 0) {
1.5     ! raeburn  1393:         if (@{$available} > 0 && $granularity eq 'Yes') {
        !          1394:             $r->print(&check_uncheck_tools($r,$available));
        !          1395:         }
        !          1396:     }
        !          1397:     &topic_bar($r,$tabcol,$img,$lt{'gpme'});
        !          1398:     if (keys(%members) > 0) {
        !          1399:         $r->print('
1.1       raeburn  1400:  <tr>
1.3       raeburn  1401:   <td>&nbsp;</td>
1.5     ! raeburn  1402:   <td colspan="3">
1.3       raeburn  1403:     <table>
1.5     ! raeburn  1404:      <tr>');
        !          1405:         &check_uncheck_buttons($r,$formname,'member',$lt{'addm'});
        !          1406:         if (@{$available} > 0 && $granularity eq 'Yes') {
        !          1407:             $r->print('<td><nobr>
        !          1408:      <fieldset><legend><b>'.$lt{'setf'}.'</b></legend>
        !          1409:       <input type="button" value="check all"
        !          1410:         onclick="javascript:checkAllTools(document.'.$formname.')" />
        !          1411:         &nbsp;&nbsp;
        !          1412:       <input type="button" value="uncheck all"
1.3       raeburn  1413:         onclick="javascript:uncheckAllTools(document.'.$formname.')" />
1.5     ! raeburn  1414:      </fieldset></nobr></td>');
1.3       raeburn  1415:         }
                   1416:         $r->print('</tr></table>
                   1417:   </td>
                   1418:  </tr>
                   1419:  <tr>
                   1420:   <td colspan="4">&nbsp;</td>
                   1421:  </tr>
                   1422:  <tr>
                   1423:   <td>&nbsp;</td>
                   1424:   <td colspan="3">
                   1425:         ');
                   1426:         $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.5     ! raeburn  1427:         $r->print('
1.3       raeburn  1428:    <table border="0" cellpadding="4" cellspacing="1">
1.5     ! raeburn  1429:     <tr bgcolor="'.$tabcol.'" align="center">
        !          1430:      <td><b>'.&mt('Add?').'</b></td>
        !          1431:      <td><b><a href="javascript:changeSort('."'fullname'".')">'.&mt('Name').'</a></b></td>
        !          1432:      <td><b><a href="javascript:changeSort('."'username'".')">'.&mt('Username').'</a></b>
1.3       raeburn  1433:      </td>
1.5     ! raeburn  1434:      <td><b><a href="javascript:changeSort('."'domain'".')">'.&mt('Domain').'</a></b></td>
        !          1435:      <td><b><a href="javascript:changeSort('."'id'".')">ID</a></b></td>
        !          1436: ');
        !          1437:         if (@{$available} > 0) {
        !          1438:             $r->print('<td><b>'.$lt{'func'}.'</b></td>');
1.3       raeburn  1439:         }
                   1440:         $r->print('</tr>');
1.5     ! raeburn  1441:         if (@{$available} > 0) {
        !          1442:             if ($granularity eq 'Yes') {
        !          1443:                 $r->print('<tr bgcolor="#cccccc">
        !          1444:  <td colspan="5">&nbsp;</td>
        !          1445:  <td align="center"><small><nobr><b>All:</b>&nbsp;');
        !          1446:                 foreach my $tool (@{$available}) {
        !          1447:                     $r->print('<input type="checkbox" name="togglefunc" '.
        !          1448:    'onclick="javascript:toggleTools(document.'.$formname.'.user_'.$tool.',this);">'.
        !          1449:    '<b>'.$tool.'</b>&nbsp;&nbsp;&nbsp;');
        !          1450:                 }
        !          1451:                 $r->print('</nobr></small></td></tr>');
        !          1452:             }
        !          1453:         }
1.3       raeburn  1454:         my %Sortby = ();
                   1455:         foreach my $user (sort(keys(%members))) {
                   1456:             if ($env{'form.sortby'} eq 'fullname') {
                   1457:                 push(@{$Sortby{$members{$user}[$$idx{fullname}]}},$user);
                   1458:             } elsif ($env{'form.sortby'} eq 'username') {
                   1459:                 push(@{$Sortby{$members{$user}[$$idx{uname}]}},$user);
                   1460:             } elsif ($env{'form.sortby'} eq 'domain') {
                   1461:                 push(@{$Sortby{$members{$user}[$$idx{udom}]}},$user);
                   1462:             } elsif ($env{'form.sortby'} eq 'id') {
                   1463:                 push(@{$Sortby{$members{$user}[$$idx{id}]}},$user);
                   1464:             } else {
                   1465:                 push(@{$Sortby{$members{$user}[$$idx{fullname}]}},$user);
                   1466:             }
                   1467:         }
                   1468:         my $rowNum = 0;
                   1469:         my $rowColor;
                   1470:         foreach my $key (sort(keys(%Sortby))) {
                   1471:             foreach my $user (@{$Sortby{$key}}) {
                   1472:                 if ($rowNum %2 == 1) {
                   1473:                     $rowColor = $rowColor1;
                   1474:                 } else {
                   1475:                     $rowColor = $rowColor2;
                   1476:                 }
                   1477:                 my $id = $members{$user}[$$idx{id}];
                   1478:                 my $fullname = $members{$user}[$$idx{fullname}];
                   1479:                 my $udom = $members{$user}[$$idx{udom}];
                   1480:                 my $uname = $members{$user}[$$idx{uname}];
                   1481:                 $r->print('<tr bgcolor="'.$rowColor.'"><td align="right">
                   1482:    <input type="checkbox" name="member" value="'.$user.'" /></td><td><small>'.
                   1483:     $fullname.'</small></td><td><small>'.$uname.'</small></td><td><small>'.
                   1484:     $udom.'</small></td><td><small>'.$id.'</small></td>');
1.5     ! raeburn  1485:                 if (@{$available} > 0) {
        !          1486:                     $r->print('<td align="center"><nobr><small>'.
        !          1487:                               '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');
        !          1488:                     foreach my $tool (@{$available}) {
        !          1489:                         if ($granularity eq 'Yes') {
1.3       raeburn  1490:                             $r->print('<input type="checkbox" name="user_'.
                   1491:                           $tool.'" value="'.$user.'" />'.$tool.'&nbsp;&nbsp;&nbsp;');
                   1492:                         } else {
                   1493:                             $r->print('<input type="hidden" name="user_'.
                   1494:                           $tool.'" value="'.$user.'" />'.$tool.'&nbsp;&nbsp;&nbsp;');
                   1495:                         }
                   1496:                     }
1.5     ! raeburn  1497:                     $r->print('</small></nobr></td>');
1.3       raeburn  1498:                 }
                   1499:                 $r->print('</tr>'."\n");
                   1500:                 $rowNum ++;
                   1501:             }
                   1502:         }
                   1503:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   1504:         $r->print('
1.5     ! raeburn  1505:      </td>
        !          1506:     </tr>');
        !          1507:     } else {
        !          1508:         $r->print('
        !          1509:     <tr>
        !          1510:      <td>&nbsp;</td>
        !          1511:      <td colspan="3">
        !          1512: ');
        !          1513:         if ($totalusers > 0) {
        !          1514:             $r->print($lt{'nnew'}.'<br /><br />'.$lt{'yoma'});
        !          1515:         } else { 
        !          1516:             $r->print($lt{'nome'});
        !          1517:         }
        !          1518:         $r->print('
        !          1519:      </td>
        !          1520:     </tr>');
        !          1521:     }
        !          1522:     return $newusers;
        !          1523: }
        !          1524: 
        !          1525: sub privilege_specificity {
        !          1526:     my ($r,$tabcol,$rowColor1,$rowColor2,$action,$img,$tools,$stored,
        !          1527:         $toolprivs,$fixedprivs,$available,$formname) = @_;
        !          1528:     my %lt = &Apache::lonlocal::texthash (
        !          1529:       'uprv' => 'User privileges',
        !          1530:       'frty' => 'For each type of functionality you have chosen to include, '.
        !          1531:                 'there is a set of standard privileges which apply to all '.
        !          1532:                 'of those for whom the functionality is enabled.',
        !          1533:       'thar' => 'There are also additional privileges which can be set for '.
        !          1534:                 'some, or all, members. Please choose one of the following:',
        !          1535:       'fort' => 'For the types of functionality you have chosen to include '.
        !          1536:                 'there are no additional privileges which can be set for some '.
        !          1537:                 'or all members.',
        !          1538:       'eaty' => 'Each of the types of functionality includes standard '.
        !          1539:                 'privileges which apply to members with access to that '.
        !          1540:                 'functionality, and may also include additional privileges '.
        !          1541:                 'which can be set for specific members.',
        !          1542:       'cutg' => 'Currently the group is configured ',
        !          1543:       'sdif' => 'so different group members can receive different privileges.',
        !          1544:       'sall' => 'so all group members will receive the same privileges.',
        !          1545:       'algm' => 'All group members will receive the same privileges.',
        !          1546:       'smgp' => 'Some group members will receive different privileges from '.
        !          1547:                 'others.',
        !          1548:       'thwi' => 'These will be the privileges all group members receive, '. 
        !          1549:                 'if you selected the first option above.',
        !          1550:       'thes' => 'These will be the privileges given to members assigned '.   
        !          1551:                 'in the future, including via automatic group assignment '.
        !          1552:                 'for specific sections/roles ',
        !          1553:       'asyo' => 'As you have chosen not to include any functionality in the '.
        !          1554:                 'group, no default user privileges settings need to be set.',
        !          1555:       'plin' => 'Please indicate which <b>optional</b> privileges members '.
        !          1556:                 'will receive by default.',
        !          1557:       'oppr' => 'Optional privileges',
        !          1558:       'defp' => 'The default privileges new members will receive are:', 
        !          1559:     );
        !          1560:     my $totaloptionalprivs = 0;
        !          1561:     foreach my $tool (@{$tools}) {
        !          1562:         foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
        !          1563:             if (!exists($$fixedprivs{$tool}{$priv})) {
        !          1564:                 $totaloptionalprivs ++;
        !          1565:             }
        !          1566:         }
        !          1567:     }
        !          1568:     &topic_bar($r,$tabcol,$img,$lt{'uprv'});
        !          1569:     $r->print('
        !          1570:  <tr>
        !          1571:   <td>&nbsp;</td>
        !          1572:   <td colspan="3">
        !          1573:   ');
        !          1574:     if ((($action eq 'create') && (@{$available} > 0)) || 
        !          1575:         (($action eq 'modify') && ($formname eq 'change_settings'))) {  
        !          1576:         my %specific = (
        !          1577:                       'No'  => 'checked="checked"',
        !          1578:                       'Yes' => '',
        !          1579:                   );
        !          1580:         if ($action eq 'create') {
        !          1581:             $r->print($lt{'frty'}.'<br />');
        !          1582:             if ($totaloptionalprivs) {
        !          1583:                 $r->print($lt{'thar'});
        !          1584:             } else {
        !          1585:                 $r->print($lt{'fort'});
        !          1586:             }
        !          1587:         } else {
        !          1588:             $r->print($lt{'eaty'}.'&nbsp;'.$lt{cutg});
        !          1589:             if ($$stored{'specificity'} eq 'Yes') {
        !          1590:                 $r->print($lt{'sdif'});
        !          1591:                 $specific{'Yes'} = $specific{'No'};
        !          1592:                 $specific{'No'} = '';
        !          1593:             } else {
        !          1594:                 $r->print($lt{'sall'});
        !          1595:             }
        !          1596:         }
        !          1597:         if ($totaloptionalprivs) {
        !          1598:             $r->print('
        !          1599: <br /><br /><nobr><input type="radio" name="specificity" value="No" '.$specific{'No'}.' />&nbsp;'.$lt{'algm'}.'</nobr><br/>
        !          1600: <nobr><input type="radio" name="specificity" value="Yes" '.$specific{'Yes'}.' />&nbsp;'.$lt{'smgp'}.'</nobr>
1.3       raeburn  1601:   </td>
                   1602:  </tr>
                   1603:  <tr>
                   1604:   <td colspan="4">&nbsp;</td>
                   1605:  </tr>');
1.5     ! raeburn  1606:         } else {
        !          1607:             $r->print('<input type="hidden" name="specificity" value="No" />');
        !          1608:         }
        !          1609:         if ($totaloptionalprivs) {
1.3       raeburn  1610:             $r->print('
1.5     ! raeburn  1611:  <tr>
1.3       raeburn  1612:   <td>&nbsp;</td>
1.5     ! raeburn  1613:   <td colspan="3">'.$lt{'plin'});
        !          1614:             if ($action eq 'create') {
        !          1615:                 $r->print(' '.$lt{'thwi'});
        !          1616:             }
        !          1617:             $r->print('<br />'.$lt{'thes'});
        !          1618:             if ($action eq 'create') {
        !          1619:                 $r->print('('.&mt('if enabled on the next page').').');
        !          1620:             } else {
        !          1621:                 $r->print('('.&mt('if enabled below').').');
        !          1622:             }
        !          1623:             $r->print('<br /><br />
1.3       raeburn  1624:   </td>
1.5     ! raeburn  1625:  </tr>
        !          1626:  <tr>
        !          1627:   <td>&nbsp;</td>
        !          1628:   <td colspan="2"><table><tr>');
        !          1629:         &check_uncheck_buttons($r,$formname,'defpriv',$lt{'oppr'});
        !          1630:         $r->print('
        !          1631:     </tr>
        !          1632:    </table>
1.3       raeburn  1633:   </td>
                   1634:   <td width="100%">&nbsp;</td>
1.5     ! raeburn  1635:  </tr><tr>
1.3       raeburn  1636:   <td>&nbsp;</td>
                   1637:   <td colspan="3">
                   1638:    <br />
                   1639: ');
1.5     ! raeburn  1640:         } else {
        !          1641:             $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'algm'}.'<br /><br />');
1.3       raeburn  1642:         }
1.5     ! raeburn  1643:         &default_privileges($r,$action,$tabcol,$rowColor1,$rowColor2,
        !          1644:                             $tools,$toolprivs,$fixedprivs,$available);
1.3       raeburn  1645:     } else {
1.5     ! raeburn  1646:         if ($action eq 'create') {
        !          1647:             $r->print($lt{'asyo'});
        !          1648:         } elsif ($action eq 'modify' && $formname eq 'pick_members') {
        !          1649:             my @defprivs;
        !          1650:             if (ref($$stored{'defpriv'}) eq 'ARRAY') {
        !          1651:                 @defprivs = @{$$stored{'defpriv'}};
        !          1652:             }
        !          1653:             $r->print($lt{'eaty'}.'&nbsp;'.$lt{cutg});
        !          1654:             if ($$stored{'specificity'} eq 'Yes') {
        !          1655:                 $r->print($lt{'sdif'});
        !          1656:             } else {
        !          1657:                 $r->print($lt{'sall'});
        !          1658:             }
        !          1659:             $r->print(' '.$lt{'defp'}.'<br /><br />');
        !          1660:             &display_defprivs($r,$tabcol,$rowColor1,$rowColor2,$tools,
        !          1661:                               $toolprivs,\@defprivs);
        !          1662:         }
1.3       raeburn  1663:     }
                   1664:     $r->print('
                   1665:   </td>
                   1666:  </tr>
1.5     ! raeburn  1667: ');
1.3       raeburn  1668:     return;
                   1669: }
                   1670: 
1.5     ! raeburn  1671: sub default_privileges {
        !          1672:     my ($r,$action,$tabcol,$rowColor1,$rowColor2,$tools,$toolprivs,
        !          1673:         $fixedprivs,$available) = @_;
        !          1674:     my %lt = &Apache::lonlocal::texthash(
        !          1675:                                 'addp' => 'Additional privileges',
        !          1676:                                 'fixp' => 'Fixed privileges',
        !          1677:                                 'oppr' => 'Optional privileges',
        !          1678:                                 'func' => 'Function',
        !          1679:     );
        !          1680:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
        !          1681:     $r->print('<tr>
        !          1682:                 <td bgcolor="'.$tabcol.'" valign="top">
        !          1683:                  <table cellspacing="0" cellpadding="1">
        !          1684:                   <tr>
        !          1685:                    <td valign="top"><b>'.$lt{'func'}.'</b></td>
        !          1686:                   </tr>
        !          1687:                   <tr>
        !          1688:                    <td valign="top"><b>'.$lt{'fixp'}.'</b></td>
        !          1689:                   </tr>
        !          1690:                   <tr>
        !          1691:                    <td valign="top"><b>'.$lt{'oppr'}.'</b></td>
        !          1692:                   </tr>
        !          1693:                  </table>
        !          1694:                 </td>
        !          1695:     ');
1.3       raeburn  1696:     foreach my $tool (@{$tools}) {
1.5     ! raeburn  1697:         $r->print('<td align="center" valign="top">
        !          1698:                     <table cellspacing="0" cellpadding="1">
        !          1699:                      <tr bgcolor="#cccccc">
        !          1700:                       <td colspan="2" align="center"><b>'.$tool.'</b></td>
        !          1701:                      </tr>
        !          1702:         ');
        !          1703:         my $privcount = 0;
        !          1704:         my $fixed = '';
        !          1705:         my $dynamic = '';
        !          1706:         foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
        !          1707:             if (exists($$fixedprivs{$tool}{$priv})) {
        !          1708:                 $fixed .= '<input type="hidden" name="defpriv" value="'.$priv.'" />'.$$toolprivs{$tool}{$priv}.'&nbsp;';
        !          1709:                 if ($action eq 'modify') {
        !          1710:                     if (grep/^$tool$/,@{$available}) {
        !          1711:                         $fixed .= '<small>'.&mt('(on)').'<small>&nbsp;';
        !          1712:                     } else {
        !          1713:                         $fixed .= '<small>'.&mt('(off)').'<small>&nbsp;';
1.3       raeburn  1714:                     }
                   1715:                 }
1.5     ! raeburn  1716:             } else {
        !          1717:                 $privcount ++;
        !          1718:                 if ($privcount == 3) {
        !          1719:                     $dynamic .= '</tr>
        !          1720:                                  <tr bgcolor="'.$rowColor1.'">'."\n";
        !          1721:                 }
        !          1722:                 $dynamic .= '<td><input type="checkbox" name="defpriv" value="'.$priv.'" />'.$$toolprivs{$tool}{$priv}.'</td>'."\n";
1.3       raeburn  1723:             }
                   1724:         }
1.5     ! raeburn  1725:         if ($dynamic eq '') {
        !          1726:             $dynamic = '<td>None</td>'."\n";
        !          1727:         }
        !          1728:         if ($privcount < 3) {
        !          1729:             $dynamic .= '</tr>
        !          1730:                          <tr bgcolor="'.$rowColor1.'">
        !          1731:                           <td colspan="2">&nbsp;</td>'."\n";
        !          1732:         } elsif ($privcount%2) {
        !          1733:             $dynamic = '<td>&nbsp;</td>'."\n";
        !          1734:         }
        !          1735:         $r->print('<tr bgcolor="'.$rowColor2.'">
        !          1736:                     <td colspan="2" align="center"><nobr>'.$fixed.'</nobr></td>
        !          1737:                    </tr>
        !          1738:                    <tr bgcolor="'.$rowColor1.'">'."\n".$dynamic.'</tr>'."\n".'</table>'."\n".'</td>
        !          1739:         ');
1.3       raeburn  1740:     }
1.5     ! raeburn  1741:     $r->print('</tr>'."\n");
        !          1742:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
        !          1743:     $r->print('<br />');
        !          1744:     return;
        !          1745: }
        !          1746: 
        !          1747: sub display_defprivs {
        !          1748:     my ($r,$tabcol,$rowColor1,$rowColor2,$tools,$toolprivs,$defprivs) = @_;
        !          1749:     my %lt = &Apache::lonlocal::texthash(
        !          1750:                                 'priv' => 'Privileges',
        !          1751:                                 'func' => 'Function',
        !          1752:     );
        !          1753:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
        !          1754:     $r->print('<tr>');
        !          1755:     my $numrows = 0;
        !          1756:     my %currprivs;
        !          1757:     foreach my $tool (@{$tools}) {
        !          1758:         @{$currprivs{$tool}} = ();
        !          1759:         foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
        !          1760:             if (ref($defprivs) eq 'ARRAY') {
        !          1761:                 if (grep/^\Q$priv\E$/,@{$defprivs}) {
        !          1762:                     push(@{$currprivs{$tool}},$priv);
        !          1763:                 }
1.3       raeburn  1764:             }
                   1765:         }
1.5     ! raeburn  1766:         my $rowcount = int(@{$currprivs{$tool}}/3);
        !          1767:         if (@{$currprivs{$tool}}%3 > 0) {
        !          1768:             $rowcount ++;
        !          1769:         }
        !          1770:         if ($rowcount > $numrows) {
        !          1771:             $numrows = $rowcount;
        !          1772:         }
        !          1773:     }
        !          1774:     my @rowCols = ($rowColor1,$rowColor2);
        !          1775:     foreach my $tool (@{$tools}) {
        !          1776:         $r->print('<td align="center" valign="top">
        !          1777:                     <table cellspacing="0" cellpadding="5">
        !          1778:                      <tr bgcolor="#cccccc">
        !          1779:                       <td colspan="3" align="center"><b>'.$tool.'</b></td>
        !          1780:                      </tr>
        !          1781:         ');
        !          1782:         my $rownum = 1;
        !          1783:         my $privcount = 0;
        !          1784:         $r->print('<tr bgcolor="'.$rowColor1.'">');
        !          1785:         foreach my $priv (@{$currprivs{$tool}}) {
        !          1786:             $privcount ++;
        !          1787:             if ($privcount%4 == 0) {
        !          1788:                 $rownum ++;
        !          1789:                 my $bgcol = $rownum%2; 
        !          1790:                 $r->print('</tr>
        !          1791:                              <tr bgcolor="'.$rowCols[$bgcol].'">'."\n");
        !          1792:             }
        !          1793:             $r->print('<td>'.$$toolprivs{$tool}{$priv}.'</td>'."\n");
        !          1794:         }
        !          1795:         if ($privcount%3 > 0) {
        !          1796:             my $emptycells = 3-($privcount%3);
        !          1797:             while($emptycells > 0) {
        !          1798:                 $r->print('<td>&nbsp;</td>'."\n");
        !          1799:                 $emptycells --;
        !          1800:             }
        !          1801:         }
        !          1802:         while ($rownum < $numrows) {
        !          1803:             $rownum ++;
        !          1804:             my $bgcol = $rownum%2;
        !          1805:             $r->print('<tr bgcolor="'.$rowCols[$bgcol].'"><td colspan="3">&nbsp;</td></tr>');
1.3       raeburn  1806:         }
1.5     ! raeburn  1807:         $r->print('</table>'."\n".'</td>');
        !          1808:     }
        !          1809:     $r->print('</tr>'."\n");
        !          1810:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
        !          1811:     $r->print('<br />');
        !          1812:     return;
1.3       raeburn  1813: }
1.5     ! raeburn  1814: 
        !          1815: 
        !          1816: sub change_members_form {
        !          1817:     my ($r,$cdom,$cnum,$tabcol,$action,$formname,$page,$groupname,$description,
        !          1818:         $startdate,$enddate,$tools,$fixedprivs,$functions,$users,$userdata,
        !          1819:         $granularity,$specificity,$idx,$states,$navbuttons,$rowColor1,
        !          1820:         $rowColor2) = @_;
        !          1821:     my %lt = &Apache::lonlocal::texthash(
        !          1822:                                          grse => 'Group settings',
        !          1823:                                          mogm => 'Modify group membership',
        !          1824:                                         );
        !          1825:     my @regexps = ('user_','userpriv_');
        !          1826:     $r->print(&Apache::lonhtmlcommon::echo_form_input(
        !          1827:                          ['origin','action','state','page','expire','delete',
        !          1828:                           'changefunc','changepriv'],\@regexps));
        !          1829:     my $rowimg = 1;
        !          1830:     my @available = ();
        !          1831:     my @unavailable = ();
        !          1832:     &check_tools($functions,$tools,\@available,\@unavailable);
        !          1833:     my $nexttext = $$navbuttons{'gtns'};
        !          1834:     my $prevtext = $$navbuttons{'gtpp'};
        !          1835:     $r->print('
1.3       raeburn  1836: <br />
                   1837: <table width="100%" cellpadding="0" cellspacing="0" border="0">
1.5     ! raeburn  1838: ');
        !          1839:     &topic_bar($r,$tabcol,1,$lt{'grse'});
        !          1840:     $r->print('
        !          1841:  <tr>
1.1       raeburn  1842:   <td>&nbsp;</td>
1.5     ! raeburn  1843:   <td colspan="3">
        !          1844: ');
        !          1845:     &print_current_settings($r,$action,$tabcol,$rowColor1,$rowColor2,
        !          1846:                             $functions,$startdate,$enddate,$groupname,
        !          1847:                           $description,$granularity,\@available,\@unavailable);
        !          1848: $r->print('
        !          1849: </td></tr><tr><td colspan="4">&nbsp;</td></tr>');
        !          1850:     &topic_bar($r,$tabcol,2,$lt{'mogm'});
        !          1851:     $r->print('
1.3       raeburn  1852:  <tr>
                   1853:   <td>&nbsp;</td>
                   1854:   <td colspan="3">
                   1855: ');
1.5     ! raeburn  1856:     &current_membership($r,$cdom,$cnum,$formname,$tabcol,$rowColor1,
        !          1857:                         $rowColor2,$groupname,\@available,\@unavailable,
        !          1858:                         $fixedprivs,$granularity,$specificity);
        !          1859:     $r->print('</td>');
        !          1860:     &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
        !          1861:                         $$states{$action}[$page+1],$nexttext);
        !          1862:     $r->print('</table>');
        !          1863:     return;
        !          1864: }
        !          1865: 
        !          1866: sub current_membership {
        !          1867:     my ($r,$cdom,$cnum,$formname,$tabcol,$rowColor1,$rowColor2,$groupname,
        !          1868:         $available,$unavailable,$fixedprivs,$granularity,$specificity) = @_;
        !          1869:     my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
        !          1870:                                                                    $groupname);
        !          1871:     my %lt = &Apache::lonlocal::texthash(
        !          1872:                                           'expi' => 'Expire',
        !          1873:                                           'reen' => 'Re-enable',
        !          1874:                                           'acti' => 'Activate',
        !          1875:                                           'dele' => 'Delete',
        !          1876:                                           'curf' => 'Current Functionality',
        !          1877:                                           'chfn' => 'Change Functions',
        !          1878:                                           'chpr' => 'Change Privileges' 
        !          1879:                                         );
        !          1880:     if (keys(%membership) > 0) {
        !          1881:         my %current = ();
        !          1882:         my %allnames = ();
        !          1883:         my $hastools = 0;
        !          1884:         my $addtools = 0;
        !          1885:         my $num_reenable = 0;
        !          1886:         my $num_activate = 0;
        !          1887:         my $num_expire - 0;
        !          1888:         foreach my $key (sort(keys(%membership))) {
        !          1889:             if ($key =~ /^\Q$groupname\E:([^:]+):([^:]+)$/) {
        !          1890:                 my $uname = $1;
        !          1891:                 my $udom = $2;
        !          1892:                 my $user = $uname.':'.$udom;
        !          1893:                 my($end,$start,@userprivs) = split(/:/,$membership{$key});
        !          1894:                 unless ($start == -1) {
        !          1895:                     $allnames{$udom}{$uname} = 1;
        !          1896:                     %{$current{$user}} = ();
        !          1897:                     $current{$user}{uname} = $uname;
        !          1898:                     $current{$user}{udom} = $udom;
        !          1899:                     $current{$user}{start} = 
        !          1900:                                      &Apache::lonlocal::locallocaltime($start);
        !          1901:                     if ($end == 0) {
        !          1902:                         $current{$user}{end} =  'No end date';
        !          1903:                     } else {
        !          1904:                         $current{$user}{end} = 
        !          1905:                                      &Apache::lonlocal::locallocaltime($end);
        !          1906:                     }
        !          1907:                     my $now = time;
        !          1908:                     if (($end > 0) && ($end < $now)) {
        !          1909:                         $current{$user}{changestate} = 'reenable';
        !          1910:                         $num_reenable++;
        !          1911:                     } elsif (($start > $now)) {
        !          1912:                         $current{$user}{changestate} = 'activate';
        !          1913:                         $num_activate ++;
        !          1914:                     } else {
        !          1915:                         $current{$user}{changestate} = 'expire';
        !          1916:                         $num_expire ++;
        !          1917:                     }
        !          1918:                     @{$current{$user}{currtools}} = ();
        !          1919:                     @{$current{$user}{newtools}} = ();
        !          1920:                     if (@userprivs > 0) {
        !          1921:                         foreach my $tool (sort(keys(%{$fixedprivs}))) {
        !          1922:                             foreach my $priv (keys(%{$$fixedprivs{$tool}})) {
        !          1923:                                 if (grep/^$priv$/,@userprivs) {
        !          1924:                                     push(@{$current{$user}{currtools}},$tool);
        !          1925:                                     last;
        !          1926:                                 }
        !          1927:                             }
        !          1928:                         }
        !          1929:                         $hastools = 1;
        !          1930:                     }
        !          1931:                     if (@{$available} > 0) {
        !          1932:                         if (@{$current{$user}{currtools}} > 0) {
        !          1933:                             if ("@{$available}" ne "@{$current{$user}{currtools}}") {
        !          1934:                                 foreach my $tool (@{$available}) {
        !          1935:                                     unless (grep/^$tool$/,@{$current{$user}{currtools}}) {
        !          1936:                                         push(@{$current{$user}{newtools}},$tool);
        !          1937:                                     }
        !          1938:                                 }
        !          1939:                             }
        !          1940:                         } else {
        !          1941:                             @{$current{$user}{newtools}} = @{$available};
        !          1942:                         }
        !          1943:                         if (@{$current{$user}{newtools}} > 0) {
        !          1944:                             $addtools = 1;
        !          1945:                         }
1.3       raeburn  1946:                     }
                   1947:                 }
                   1948:             }
1.5     ! raeburn  1949:         }
        !          1950:         if (keys(%current) > 0) {
        !          1951:             my %idhash;
        !          1952:             foreach my $udom (keys(%allnames)) {
        !          1953:                 %{$idhash{$udom}} = &Apache::lonnet::idrget($udom,
        !          1954:                                                 keys(%{$allnames{$udom}}));
        !          1955:                 foreach my $uname (keys(%{$idhash{$udom}})) {
        !          1956:                     $current{$uname.':'.$udom}{'id'} = $idhash{$udom}{$uname};
        !          1957:                 }
        !          1958:                 foreach my $uname (keys(%{$allnames{$udom}})) {
        !          1959:                     $current{$uname.':'.$udom}{'fullname'} =
        !          1960:                                 &Apache::loncommon::plainname($uname,$udom,
        !          1961:                                                                   'lastname');
        !          1962:                 }
1.3       raeburn  1963:             }
1.5     ! raeburn  1964:             $r->print('
        !          1965:  <tr>
        !          1966:   <td>&nbsp;</td>
        !          1967:   <td colspan="2">
        !          1968:    <table>
        !          1969:     <tr>');
        !          1970:             if ($num_expire) {
        !          1971:                 &check_uncheck_buttons($r,$formname,'expire',$lt{'expi'});
        !          1972:             }
        !          1973:             if ($num_reenable) {
        !          1974:                 &check_uncheck_buttons($r,$formname,'reenable',$lt{'reen'});
        !          1975:             }
        !          1976:             if ($num_activate) {
        !          1977:                 &check_uncheck_buttons($r,$formname,'activate',$lt{'acti'});
        !          1978:             }
        !          1979:             &check_uncheck_buttons($r,$formname,'delete',$lt{'dele'});
        !          1980:             if (@{$available} > 0) {
        !          1981:                 if ($granularity eq 'Yes') {
        !          1982:                     &check_uncheck_buttons($r,$formname,'changefunc',$lt{'chfn'});
        !          1983:                 }
        !          1984:                 if ($specificity eq 'Yes') {
        !          1985:                     &check_uncheck_buttons($r,$formname,'changepriv',$lt{'chpr'});
        !          1986:                 }
        !          1987:                 if ($granularity eq 'Yes') {
        !          1988:                     $r->print(&check_uncheck_tools($r,$available));
        !          1989:                     $r->print('
        !          1990:      <td>
        !          1991:       <nobr>
        !          1992:        <fieldset><legend><b>'.$lt{'curf'}.'</b></legend>
        !          1993:        <input type="button" value="check all"
        !          1994:        onclick="javascript:checkAllTools(document.'.$formname.')" />
        !          1995:        &nbsp;&nbsp;
        !          1996:        <input type="button" value="uncheck all"
        !          1997:         onclick="javascript:uncheckAllTools(document.'.$formname.')" />
        !          1998:       </fieldset>
        !          1999:      </nobr>
        !          2000:     </td>
        !          2001: ');
        !          2002:                 }
1.3       raeburn  2003:             }
1.5     ! raeburn  2004:             $r->print(<<"END");
        !          2005:    </tr>
        !          2006:   </table>
        !          2007:   </td>
        !          2008:   <td width="100%">&nbsp;</td>
        !          2009:  </tr>
1.3       raeburn  2010:  <tr>
                   2011:   <td colspan="4">&nbsp;</td>
                   2012:  </tr>
                   2013:  <tr>
                   2014:   <td>&nbsp;</td>
                   2015:   <td colspan="3">
1.5     ! raeburn  2016: END
        !          2017:             $r->print(&Apache::lonhtmlcommon::start_pick_box());
        !          2018:             $r->print(<<"END");
        !          2019:    <table border="0" cellpadding="4" cellspacing="1">
        !          2020:     <tr bgcolor="$tabcol" align="center">
        !          2021:      <td><b>Action?</b></td>
        !          2022:      <td><b><a href="javascript:changeSort('fullname')">Name</a></b></td>
        !          2023:      <td><b><a href="javascript:changeSort('username')">Username</a></b>
        !          2024:      </td>
        !          2025:      <td><b><a href="javascript:changeSort('domain')">Domain</a></b></td>
        !          2026:      <td><b><a href="javascript:changeSort('id')">ID</a></b></td>
        !          2027:      <td><b><a href="javascript:changeSort('start')">Start Date</a></b></td>
        !          2028:      <td><b><a href="javascript:changeSort('end')">End Date</a></b></td>
        !          2029: END
        !          2030:             if ($hastools) {
        !          2031:                 $r->print('<td><b>'.$lt{'curf'}.'</b></td>');
        !          2032:             }
        !          2033:             if ($addtools) {
        !          2034:                 $r->print('<td><b>Additional Functionality</b></td>');
        !          2035:             }
        !          2036:             $r->print('</tr>');
        !          2037:             my %Sortby = ();
        !          2038:             foreach my $user (sort(keys(%current))) {
        !          2039:                 if ($env{'form.sortby'} eq 'fullname') {
        !          2040:                     push(@{$Sortby{$current{$user}{fullname}}},$user);
        !          2041:                 } elsif ($env{'form.sortby'} eq 'username') {
        !          2042:                     push(@{$Sortby{$current{$user}{uname}}},$user);
        !          2043:                 } elsif ($env{'form.sortby'} eq 'domain') {
        !          2044:                     push(@{$Sortby{$current{$user}{udom}}},$user);
        !          2045:                 } elsif ($env{'form.sortby'} eq 'id') {
        !          2046:                     push(@{$Sortby{$current{$user}{id}}},$user);
        !          2047:                 } else {
        !          2048:                     push(@{$Sortby{$current{$user}{fullname}}},$user);
        !          2049:                 }
        !          2050:             }
        !          2051:             my $rowNum = 0;
        !          2052:             my $rowColor;
        !          2053:             foreach my $key (sort(keys(%Sortby))) {
        !          2054:                 foreach my $user (@{$Sortby{$key}}) {
        !          2055:                     if ($rowNum %2 == 1) {
        !          2056:                         $rowColor = $rowColor1;
        !          2057:                     } else {
        !          2058:                         $rowColor = $rowColor2;
        !          2059:                     }
        !          2060:                     my $id = $current{$user}{id};
        !          2061:                     my $fullname = $current{$user}{fullname};
        !          2062:                     my $udom = $current{$user}{udom};
        !          2063:                     my $uname = $current{$user}{uname};
        !          2064:                     my $start = $current{$user}{start};
        !          2065:                     my $end = $current{$user}{end};
        !          2066:                     $r->print('<tr bgcolor="'.$rowColor.'">
        !          2067:                                 <td><small>');
        !          2068:                     if ($current{$user}{changestate} eq 'reenable') {
        !          2069:                         $r->print('<nobr>'. 
        !          2070:    '<input type="checkbox" name="reenable" value="'.$user.'" />'.
        !          2071:    $lt{'reen'}.'</nobr><br />');
        !          2072:                     } elsif ($current{$user}{changestate} eq 'expire') {
        !          2073:                         $r->print('<nobr>'.
        !          2074:    '<input type="checkbox" name="expire" value="'.$user.'" />'.
        !          2075:    $lt{'expi'}.'</nobr><br />');
        !          2076:                     } elsif ($current{$user}{changestate} eq 'activate') {
        !          2077:                         $r->print('<nobr>'.
        !          2078:    '<input type="checkbox" name="activate" value="'.$user.'" />'.
        !          2079:    $lt{'acti'}.'</nobr><br />');
        !          2080:                     }
        !          2081:                     $r->print('<nobr>'.
        !          2082:    '<input type="checkbox" name="delete" value="'.$user.'" />'.
        !          2083:    $lt{'dele'}.'</nobr>');
        !          2084:                     if ($granularity eq 'Yes') {
        !          2085:                         $r->print('<br /><nobr>'.
        !          2086:    '<input type="checkbox" name="changefunc" value="'.$user.'" />'.$lt{'chfn'}.
        !          2087:    '</nobr>');
        !          2088:                     }
        !          2089:                     if ($specificity eq 'Yes') {
        !          2090:                         $r->print('<br /><nobr>'.
        !          2091:    '<input type="checkbox" name="changepriv" value="'.$user.'" />'.$lt{'chpr'}.
        !          2092:    '</nobr>');
        !          2093:                     }
        !          2094:                     $r->print('
        !          2095:    </td>
        !          2096:    <td><small>'.
        !          2097:     $fullname.'</small></td><td><small>'.$uname.'</small></td><td><small>'.
        !          2098:     $udom.'</small></td><td><small>'.$id.'</small></td><td><small>'.$start.
        !          2099:     '</small></td><td><small>'.$end.'</small></td>');
        !          2100:                     if ($hastools) {
        !          2101:                         $r->print('<td align="left"><small><nobr>');
        !          2102:                         foreach my $tool (@{$current{$user}{currtools}}) {
        !          2103:                             if ($granularity eq 'Yes') {
        !          2104:                                 $r->print('<input type="checkbox" 
        !          2105:                                        checked="checked"  
        !          2106:                                        name="user_'.$tool.'" value="'.
        !          2107:                                        $user.'" />');
        !          2108:                              } else {
        !          2109:                                $r->print('<input type="hidden"
        !          2110:                                        checked="checked"
        !          2111:                                        name="user_'.$tool.'" value="'.
        !          2112:                                        $user.'" />');
        !          2113:                              }
        !          2114:                              $r->print($tool.'&nbsp;&nbsp;&nbsp;');
        !          2115:                         }
        !          2116:                         $r->print('</nobr></small></td>');
        !          2117:                     }
        !          2118:                     if ($addtools) {
        !          2119:                         $r->print('<td align="left"><small>');
        !          2120:                         if ($granularity eq 'Yes') {
        !          2121:                             foreach my $tool (@{$current{$user}{newtools}}) {
        !          2122:                                 $r->print('<nobr><input type="checkbox"  
        !          2123:                                           name="user_'.$tool.'" value="'.
        !          2124:                                           $user.'" />'.$tool.
        !          2125:                                                   '</nobr>&nbsp;&nbsp;&nbsp;');
        !          2126:                             }
        !          2127:                         } else {
        !          2128:                             foreach my $tool (@{$current{$user}{newtools}}) {
        !          2129:                                 $r->print('<nobr><input type="hidden" 
        !          2130:                                           name="user_'. $tool.'" value="'.
        !          2131:                                           $user.'" />'.$tool.
        !          2132:                                           '</nobr>&nbsp;&nbsp;&nbsp;');
        !          2133:                             }
        !          2134:                         }
        !          2135:                         $r->print('</small></td>');
        !          2136:                     }
        !          2137:                     $r->print('</tr>'."\n");
        !          2138:                     $rowNum ++;
        !          2139:                 }
        !          2140:             }
        !          2141:             $r->print(&Apache::lonhtmlcommon::end_pick_box());
        !          2142:             $r->print('
1.3       raeburn  2143:   </td>
1.5     ! raeburn  2144:  </tr>');
        !          2145:         }
        !          2146:     }
        !          2147:     return;
        !          2148: }
        !          2149: 
        !          2150: sub check_uncheck_buttons {
        !          2151:     my ($r,$formname,$field,$title,$colspan) = @_;
        !          2152:     $r->print('
        !          2153:      <td '.$colspan.'>
        !          2154:       <nobr>
        !          2155:        <fieldset>
        !          2156:        <legend><b>'.$title.'</b></legend>
        !          2157:        <input type="button" value="check all"
        !          2158:        onclick="javascript:checkAll(document.'.$formname.'.'.$field.')" />
        !          2159:        &nbsp;&nbsp;
        !          2160:        <input type="button" value="uncheck all"
        !          2161:        onclick="javascript:uncheckAll(document.'.$formname.'.'.$field.')" />
        !          2162:        </fieldset>
        !          2163:       </nobr>
        !          2164:      </td>
        !          2165: ');
        !          2166: }
        !          2167: 
        !          2168: 
        !          2169: sub change_privs_form {
        !          2170:     my ($r,$cdom,$cnum,$tabcol,$action,$formname,$page,$startdate,$enddate,
        !          2171:        $tools,$functions,$toolprivs,$fixedprivs,$userdata,$usertools,
        !          2172:        $memchg,$idx,$states,$stored,$sectioncount,$navbuttons,$rowColor1,
        !          2173:        $rowColor2) = @_;
        !          2174:     my @regexps = ('userpriv_');
        !          2175:     my $nexttext;
        !          2176:                                                                                       
        !          2177:     $r->print(&Apache::lonhtmlcommon::echo_form_input(
        !          2178:          ['origin','action','state','page'],\@regexps));
        !          2179:     $nexttext = $$navbuttons{'adme'};
        !          2180:                                                                                       
        !          2181:     $r->print('<br /><table width="100%" cellpadding="0" cellspacing="0" border="0">');
        !          2182:     
        !          2183:     &topic_bar($r,$tabcol,3,&mt('Group member privileges'));
        !          2184:                                                                                       
        !          2185:     &member_privileges_form($r,$tabcol,$action,$formname,$tools,$toolprivs,
        !          2186:                             $fixedprivs,$userdata,$usertools,$idx,$memchg,
        !          2187:                             $states,$stored,$rowColor1,$rowColor2);
        !          2188:                                                                                       
        !          2189:     $r->print('</td></tr><tr><td colspan="4">&nbsp;</td></tr>');
        !          2190:     my $prevtext = $$navbuttons{'gtps'};
        !          2191:     &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
        !          2192:                         $$states{$action}[$page+1],$nexttext);
        !          2193:     $r->print('</table>');
        !          2194:     return;
        !          2195: }
        !          2196: 
        !          2197: sub add_members_form {
        !          2198:     my ($r,$tabcol,$action,$formname,$page,$startdate,$enddate,$groupname,
        !          2199:         $description,$granularity,$sectioncount,$tools,$functions,$stored,
        !          2200:         $states,$navbuttons,$rowColor1,$rowColor2) = @_; 
        !          2201:     $r->print(' <br />
        !          2202: <table width="100%" cellpadding="0" cellspacing="0" border="0">
        !          2203:  <tr>
        !          2204:   <td>&nbsp;</td>
        !          2205:   <td colspan="3">
        !          2206: ');
        !          2207:     my @available = ();
        !          2208:     my @unavailable = ();
        !          2209:     &check_tools($functions,$tools,\@available,\@unavailable);
        !          2210:     &print_current_settings($r,$action,$tabcol,$rowColor1,$rowColor2,
        !          2211:                             $functions,$startdate,$enddate,$groupname,
        !          2212:                             $description,$granularity,\@available,\@unavailable);
        !          2213:     $r->print('
        !          2214:    </td>
        !          2215:   </tr>
        !          2216:   <tr>
        !          2217:    <td colspan="4">&nbsp;</td>
        !          2218:   </tr>');
        !          2219: 
        !          2220:     &membership_options($r,$action,$formname,$tabcol,$sectioncount,1);
        !          2221:     my $nexttext = $$navbuttons{'gtns'};
        !          2222:     my $prevtext = $$navbuttons{'gtpp'};
        !          2223:     &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
        !          2224:                         $$states{$action}[$page+1],$nexttext);
1.3       raeburn  2225:     $r->print('
1.5     ! raeburn  2226:  </table>');
        !          2227:     return;
        !          2228: }
        !          2229: 
        !          2230: sub choose_privs_form {
        !          2231:     my ($r,$cdom,$cnum,$tabcol,$action,$formname,$page,$startdate,$enddate,
        !          2232:        $tools,$functions,$toolprivs,$fixedprivs,$userdata,$usertools,$idx,
        !          2233:        $states,$stored,$sectioncount,$navbuttons,$rowColor1,$rowColor2) = @_;
        !          2234: 
        !          2235:     my @regexps = ('userpriv_');
        !          2236:     my $nexttext;
        !          2237:     
        !          2238:     if ($action eq 'create') {
        !          2239:         push(@regexps,'sec_');
        !          2240:         $r->print(&Apache::lonhtmlcommon::echo_form_input(
        !          2241:          ['origin','action','state','page','autoadd','autodrop'],
        !          2242:          \@regexps));
        !          2243:         $nexttext = $$navbuttons{'crgr'};
        !          2244:     } else {
        !          2245:         $r->print(&Apache::lonhtmlcommon::echo_form_input(
        !          2246:          ['origin','action','state','page'],\@regexps));
        !          2247:         $nexttext = $$navbuttons{'adme'};
        !          2248:     }
        !          2249: 
        !          2250:     $r->print('<br /><table width="100%" cellpadding="0" cellspacing="0" border="0">');
        !          2251:     &topic_bar($r,$tabcol,6,&mt('Group member privileges'));
        !          2252: 
        !          2253:     &member_privileges_form($r,$tabcol,$action,$formname,$tools,$toolprivs,
        !          2254:                             $fixedprivs,$userdata,$usertools,$idx,undef,
        !          2255:                             $states,$stored,$rowColor1,$rowColor2);
        !          2256: 
        !          2257:     $r->print('</td></tr><tr><td colspan="4">&nbsp;</td></tr>');
        !          2258:     if ($action eq 'create') {
        !          2259:         if (keys(%{$sectioncount}) > 0) {
        !          2260:             my $img1 = 7;
        !          2261:             my $img2 = 8;
        !          2262:             &mapping_options($r,$action,$formname,$page,$tabcol,$sectioncount,
        !          2263:                              $states,$stored,$navbuttons,$img1,$img2,
        !          2264:                              $rowColor1,$rowColor2);
        !          2265:         }
        !          2266:     }
        !          2267:     my $prevtext = $$navbuttons{'gtps'};
        !          2268:     &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
        !          2269:                         $$states{$action}[$page+1],$nexttext);
        !          2270:     $r->print('</table>');
        !          2271:     return;
        !          2272: }
        !          2273: 
        !          2274: sub build_boxes {
        !          2275:     my ($r,$tools,$usertools,$fixedprivs,$toolprivs,$showtools,
        !          2276:         $showboxes,$prefix,$specificity) = @_;
        !          2277:     my $totalboxes = 0;
        !          2278:     if (@{$tools} > 0) {
        !          2279:         if ($specificity eq 'Yes') {
        !          2280:             foreach my $tool (@{$tools}) {
        !          2281:                 @{$$showboxes{$tool}} = ();
        !          2282:                 foreach my $user (sort(keys(%{$usertools}))) {
        !          2283:                     unless (grep/^$tool$/,@{$showtools}) {
        !          2284:                         push(@{$showtools},$tool);
        !          2285:                     }
        !          2286:                     foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
        !          2287:                         unless (exists($$fixedprivs{$tool}{$priv})) {
        !          2288:                             unless(grep(/^$priv$/,@{$$showboxes{$tool}})) {
        !          2289:                                 push(@{$$showboxes{$tool}},$priv);
        !          2290:                                 $totalboxes ++;
        !          2291:                             }
        !          2292:                         }
        !          2293:                     }
        !          2294:                 }
        !          2295:             }
        !          2296:             if ($totalboxes > 0) {
        !          2297:                 $r->print('
        !          2298: <script type="text/javascript">
        !          2299: function checkAllTools(formname) {
        !          2300: ');
        !          2301:                 foreach my $tool (sort(keys(%{$showboxes}))) {
        !          2302:                     foreach my $priv (@{$$showboxes{$tool}}) {
        !          2303:                         $r->print('  checkAll(formname.'.$prefix.$priv.');'."\n");
        !          2304:                     }
        !          2305:                 }
        !          2306:                 $r->print('
        !          2307: }
        !          2308: function uncheckAllTools(formname) {
        !          2309: ');
        !          2310:                 foreach my $tool (sort(keys(%{$showboxes}))) {
        !          2311:                     foreach my $priv (@{$$showboxes{$tool}}) {
        !          2312:                         $r->print('  uncheckAll(formname'.$prefix.$priv.');'."\n");
        !          2313:                     }
        !          2314:                 }
        !          2315:                 $r->print('
        !          2316: }
        !          2317: </script>
        !          2318:                 ');
        !          2319:             }
        !          2320:         }
        !          2321:     }
        !          2322:     return $totalboxes;
        !          2323: }
        !          2324: 
        !          2325: sub member_privileges_form {
        !          2326:     my ($r,$tabcol,$action,$formname,$tools,$toolprivs,$fixedprivs,$userdata,
        !          2327:         $usertools,$idx,$memchg,$states,$stored,$rowColor1,$rowColor2) = @_;
        !          2328:     my %lt = &Apache::lonlocal::texthash(
        !          2329:             'addp' => 'Additional privileges',
        !          2330:             'fixp' => 'Fixed privileges',
        !          2331:             'oppr' => 'Optional privileges',
        !          2332:             'func' => 'Function',
        !          2333:             'forf' => 'For the functionality you have chosen to include '.
        !          2334:                       'there are no optional privileges to set besides '.
        !          2335:                       'the standard privileges.',
        !          2336:             'algr' => 'All group members will receive the same privileges.',
        !          2337:             'asno' => 'As no group members are being added, '.
        !          2338:                       'there are no specific user privileges to set.',
        !          2339:             'asng' => 'As no group tools will be made available to users, '.
        !          2340:                       'there are no specific user privileges to set.',
        !          2341:             'full' => 'Fullname',
        !          2342:             'user' => 'Username',
        !          2343:             'doma' => 'Domain',
        !          2344:     );
        !          2345:     my @defprivs;
        !          2346:     my $specificity;
        !          2347:     if ($action eq 'create') {
        !          2348:         if (defined($env{'form.defpriv'})) {
        !          2349:             @defprivs = &Apache::loncommon::get_env_multiple('form.defpriv');
        !          2350:         }
        !          2351:         $specificity = $env{'form.specificity'};
        !          2352:     } else {
        !          2353:         @defprivs = @{$$stored{'defpriv'}};
        !          2354:         $specificity = $$stored{'specificity'};
        !          2355:     }
        !          2356:     my @showtools;
        !          2357:     my %showboxes = ();
        !          2358:     my $totalboxes = 0;
        !          2359:     my $numtools = 1 + @{$tools};
1.3       raeburn  2360: 
1.5     ! raeburn  2361:     $totalboxes = &build_boxes($r,$tools,$usertools,$fixedprivs,$toolprivs,
        !          2362:                                \@showtools,\%showboxes,'userpriv_',
        !          2363:                                $specificity);
        !          2364:     if (@{$tools} > 0) {
        !          2365:         if ($specificity eq 'Yes') {
        !          2366:             if ($totalboxes > 0) {
        !          2367:                 my $numcells = 2;
        !          2368:                 my $colspan = $numcells + 1;
        !          2369:                 my %total;
        !          2370:                 $r->print('
        !          2371:  <tr>
        !          2372:   <td>&nbsp;</td>
        !          2373:   <td colspan="3">
        !          2374:    <table border="0" cellspacing="2" cellpadding="2" border="0">
        !          2375:     <tr>
        !          2376: ');
        !          2377:                 foreach my $tool (@{$tools}) {
        !          2378:                     if (@{$showboxes{$tool}} > 0) {
        !          2379:                         $r->print('<td valign="top">');
        !          2380:                         $r->print('<table class="thinborder"><tr bgcolor="'.$tabcol.
        !          2381:                       '"><th colspan="'.$colspan.'">'.$tool.'</th></tr><tr>');
        !          2382:                         my $privcount = 0;
        !          2383:                         foreach my $priv (@{$showboxes{$tool}}) {
        !          2384:                             $privcount ++;
        !          2385:                             if (($privcount == @{$showboxes{$tool}}) && ($privcount > 1)) {
        !          2386:                                 if ($privcount%$numcells) {
        !          2387:                                     $r->print('<td colspan="'.$colspan.'">');
        !          2388:                                 } else {
        !          2389:                                     $r->print('<td>');
        !          2390:                                 }
        !          2391:                             } else {
        !          2392:                                 $r->print('<td>');
        !          2393:                             }
        !          2394:                             $r->print(qq|
        !          2395:        <fieldset><legend><b>$$toolprivs{$tool}{$priv}</b></legend>
        !          2396:        <nobr>
        !          2397:        <input type="button" value="check all"
        !          2398:          onclick="javascript:checkAll(document.$formname.userpriv_$priv)" />
        !          2399:        &nbsp;
        !          2400:        <input type="button" value="uncheck all"
        !          2401:         onclick="javascript:uncheckAll(document.$formname.userpriv_$priv)" />
        !          2402:       </nobr></fieldset><br />|);
        !          2403:                             $r->print('</td>');
        !          2404:                             if ($privcount < @{$showboxes{$tool}}) {
        !          2405:                                 if (@{$showboxes{$tool}} > 2) {
        !          2406:                                     if ($privcount%$numcells == 0) {
        !          2407:                                         $r->print('</tr><tr>');
        !          2408:                                     }
        !          2409:                                 } else {
        !          2410:                                     $r->print('<tr></tr>');
        !          2411:                                 }
        !          2412:                             }
        !          2413:                         }
        !          2414:                         $r->print('</tr></table></td><td>&nbsp;</td>');
        !          2415:                     }
        !          2416:                 }
        !          2417:                 $r->print('</tr></table></td></tr>');
        !          2418:                 $r->print('<tr><td colspan="4">&nbsp;</td></tr><tr><td>&nbsp;</td><td colspan="3">');
        !          2419:                 $r->print(&Apache::lonhtmlcommon::start_pick_box());
        !          2420:                 $r->print(<<"END");
        !          2421:    <tr bgcolor="$tabcol">
        !          2422:     <th><b>$lt{'full'}</th>
        !          2423:     <th><b>$lt{'user'}</th>
        !          2424:     <th>$lt{'doma'}</th>
        !          2425:     <th colspan="$numtools">$lt{'addp'}</th>
        !          2426:   </tr>
        !          2427: END
        !          2428:                 &member_privs_entries($r,$tabcol,$rowColor1,$rowColor2,
        !          2429:                                       $usertools,$toolprivs,$fixedprivs,
        !          2430:                                       $userdata,$idx,\@showtools,\@defprivs);
        !          2431:                 $r->print('</td>');
        !          2432:                 $r->print(&Apache::lonhtmlcommon::end_pick_box());
        !          2433:                 $r->print('</td></tr>
        !          2434:  <tr>
        !          2435:   <td colspan="4">&nbsp;</td>
        !          2436:  </tr>
        !          2437: ');
        !          2438:             } else {
        !          2439:                 $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'forf'}.
        !          2440:                           '<br />');
        !          2441:                 &display_defprivs($r,$tabcol,$rowColor1,$rowColor2,$tools,
        !          2442:                             $toolprivs,\@defprivs);
        !          2443:                                                                                       
        !          2444:             }
        !          2445:         } else {
        !          2446:             if (keys(%{$usertools}) > 0) {
        !          2447:                 $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'algr'}.
        !          2448:                           '<br /><br />');
        !          2449:                 &display_defprivs($r,$tabcol,$rowColor1,$rowColor2,$tools,
        !          2450:                             $toolprivs,\@defprivs);
        !          2451:             } else {
        !          2452:                 $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'asno'}.
        !          2453:                           '<br />');
        !          2454:             }
        !          2455:         }
        !          2456:     } else {
        !          2457:         $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'asng'});
        !          2458:     }
1.1       raeburn  2459:     return;
                   2460: }
                   2461: 
1.5     ! raeburn  2462: sub process_request {
        !          2463:     my ($r,$cdom,$cnum,$tabcol,$action,$state,$page,$groupname,$description,
        !          2464:         $specificity,$userdata,$startdate,$enddate,$tools,$functions,$toolprivs,
        !          2465:         $usertools,$idx,$types,$roles,$sections,$states,$navbuttons,$memchg,
        !          2466:         $sectioncount,$stored,$rowColor1,$rowColor2) = @_;
1.3       raeburn  2467: 
                   2468:     $r->print(&Apache::lonhtmlcommon::echo_form_input(
1.5     ! raeburn  2469:                                         ['origin','action','state','page']));
        !          2470: 
        !          2471:     my $earlyout = &validate_groupname($groupname,$action,$cdom,$cnum);
        !          2472:     if ($earlyout) {
        !          2473:         $r->print('
        !          2474: <table width="100%" cellpadding="0" cellspacing="0" border="0">
        !          2475:  <tr>
        !          2476:   <td>&nbsp;</td>
        !          2477:   <td colspan="3">
        !          2478: '.$earlyout.'</td></tr>');
        !          2479:         &display_navbuttons($r,$state,$$states{$action}[$page-1],
        !          2480:                             $$navbuttons{'gtps'});
        !          2481:         $r->print('</table>');
        !          2482:         return;
        !          2483:     }
        !          2484: 
        !          2485:     my @defprivs = ();
        !          2486:     if ($action eq 'create' || $state eq 'chgresult') { 
        !          2487:         if (defined($env{'form.defpriv'})) {
        !          2488:             @defprivs = &Apache::loncommon::get_env_multiple('form.defpriv');
        !          2489:         }
        !          2490:         if ($state eq 'chgresult') {
        !          2491:             my @okprivs = ();
        !          2492:             foreach my $tool (@{$tools}) {
        !          2493:                 foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
        !          2494:                     push(@okprivs,$priv);
        !          2495:                 }
        !          2496:             }
        !          2497:             my @temp = ();
        !          2498:             foreach my $defpriv (@defprivs) {
        !          2499:                 if (grep/^$defpriv$/,@okprivs) {
        !          2500:                     push(@temp,$defpriv);
        !          2501:                 }
        !          2502:             }
        !          2503:             @defprivs = @temp; 
        !          2504:         }
        !          2505:     } else {
        !          2506:         @defprivs = @{$$stored{'defpriv'}};
        !          2507:     }
        !          2508: 
        !          2509:     my $outcome;
        !          2510:     if ($action eq 'create' || $state eq 'chgresult') {
        !          2511:         $outcome = &write_group_data($r,$cdom,$cnum,$action,$state,$groupname,
        !          2512:                                      $description,$startdate,$enddate,
        !          2513:                                      $specificity,$functions,$tools,
        !          2514:                                      $sectioncount,$roles,$types,$sections,
        !          2515:                                      \@defprivs,$stored); 
        !          2516:     }
        !          2517:     if (($action eq 'create' && $outcome eq 'ok') || (($action eq 'modify') && 
        !          2518:        (($state eq 'memresult') || ($state eq 'addresult')))) {
        !          2519:         &process_membership($r,$cdom,$cnum,$groupname,$tools,$enddate,
        !          2520:                             $startdate,$userdata,$idx,$toolprivs,$usertools,
        !          2521:                             $specificity,\@defprivs);
        !          2522:     }
        !          2523:     return;
        !          2524: }
        !          2525: 
        !          2526: sub write_group_data {
        !          2527:     my ($r,$cdom,$cnum,$action,$state,$groupname,$description,$startdate,
        !          2528:         $enddate,$specificity,$functions,$tools,$sectioncount,$roles,$types,
        !          2529:         $sections,$defprivs,$stored) = @_;
        !          2530:     my $now = time;
        !          2531:     my $creation = $now;
        !          2532:     my $creator = $env{'user.name'}.':'.$env{'user.domain'};
        !          2533:     if ($state eq 'chgresult') {
        !          2534:         $creation = $$stored{'creation'};
        !          2535:         $creator = $$stored{'creator'};
        !          2536:     }
        !          2537:     my $esc_description = &Apache::lonnet::escape($description);
        !          2538:     my @single_attributes = ('description','functions','startdate','enddate',
        !          2539:                              'creation','modified','creator','granularity',
        !          2540:                              'specificity','autoadd','autodrop');
        !          2541:     my @mult_attributes = ('roles','types','sectionpick','defpriv');
        !          2542:                                                                                     
        !          2543:     my %groupinfo = (
        !          2544:                      description => $esc_description,
        !          2545:                      startdate => $startdate,
        !          2546:                      enddate => $enddate,
        !          2547:                      creation => $creation,
        !          2548:                      modified => $now,
        !          2549:                      creator => $creator,
        !          2550:                      granularity => $env{'form.granularity'},
        !          2551:                      specificity => $specificity,
        !          2552:                      autoadd => $env{'form.autoadd'},
        !          2553:                      autodrop => $env{'form.autodrop'},
        !          2554:                    );
        !          2555:     foreach my $func (keys(%{$functions})) {
        !          2556:         my $status;
        !          2557:         if (grep(/^$func$/,@{$tools})) {
        !          2558:             $status = 'on';
        !          2559:         } else {
        !          2560:             $status = 'off';
        !          2561:         }
        !          2562:         $groupinfo{'functions'} .=  qq|<name id="$func">$status</name>|;
        !          2563:     }
        !          2564: 
        !          2565:     $groupinfo{'roles'} = $roles;
        !          2566:     $groupinfo{'types'} = $types;
        !          2567:     $groupinfo{'sectionpick'} = $sections;
        !          2568:     $groupinfo{'defpriv'} = $defprivs;
        !          2569: 
        !          2570:     my %groupsettings = ();
        !          2571:     foreach my $item (@single_attributes) {
        !          2572:         $groupsettings{$groupname} .= qq|<$item>$groupinfo{$item}</$item>|;
        !          2573:     }
        !          2574:     foreach my $item (@mult_attributes) {
        !          2575:         foreach my $entry (@{$groupinfo{$item}}) {
        !          2576:             $groupsettings{$groupname} .= qq|<$item>$entry</$item>|;
        !          2577:         }
        !          2578:     }
        !          2579:     my $autosec;
        !          2580:     my @autorole = &Apache::loncommon::get_env_multiple('form.autorole');
        !          2581:                                                                                     
        !          2582:     foreach my $role (@autorole) {
        !          2583:         if (defined($env{'form.sec_'.$role})) {
        !          2584:             my @autosections=&Apache::loncommon::get_env_multiple('form.sec_'.
        !          2585:                                                                   $role);
        !          2586:             if (grep/^_all$/,@autosections) {
        !          2587:                 @autosections = sort {$a cmp $b} keys(%{$sectioncount});
        !          2588:             }
        !          2589:             $autosec .= '<role id="'.$role.'">';
        !          2590:             foreach my $sec (@autosections) {
        !          2591:                 $autosec .= '<section>'.$sec.'</section>';
        !          2592:             }
        !          2593:             $autosec .= '</role>';
        !          2594:         }
        !          2595:     }
        !          2596:     if ($autosec) {
        !          2597:         $groupsettings{$groupname} .= qq|<autosec>$autosec</autosec>|;
        !          2598:     }
        !          2599:     my $result = &Apache::lonnet::modify_coursegroup($cdom,$cnum,
        !          2600:                                                      \%groupsettings);
        !          2601: 
        !          2602:     if ($result eq 'ok') {
        !          2603:         if ($action eq 'create') {
        !          2604:             my $put_result = &create_homepage($cdom,$cnum,$groupname,
        !          2605:                                               \%groupinfo,$tools);
        !          2606:             $r->print('Group '.$groupname.' was created.<br />');
        !          2607:         } else {
        !          2608:             $r->print('Group '.$groupname.' was updated.<br />');
        !          2609:         }
        !          2610:     } else {
        !          2611:         my %actiontype = (
        !          2612:                           'create' => 'creating',
        !          2613:                           'modify' => 'modifying',
        !          2614:                          );
        !          2615:         &Apache::lonnet::logthis('Failed to store group '.$groupname.
        !          2616:                                  'in course: '.$cnum.' in domain: '.$cdom);
        !          2617:         $r->print(&mt('An error occurred when [_1] the new group. '.
        !          2618:                       'Please try again.',$actiontype{$action}));
        !          2619:     }
        !          2620:     return $result;
        !          2621: }
        !          2622: 
        !          2623: sub process_membership {
        !          2624:     my ($r,$cdom,$cnum,$groupname,$tools,$enddate,$startdate,$userdata,$idx,
        !          2625:         $toolprivs,$usertools,$specificity,$defprivs) = @_;
        !          2626:     my %usersettings = ();
1.3       raeburn  2627:     my @added= ();
                   2628:     my @failed = ();
                   2629:     my %group_privs = ();
                   2630:     my %tooltype = ();
1.5     ! raeburn  2631: 
1.3       raeburn  2632:     foreach my $tool (@{$tools}) {
                   2633:         foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
                   2634:             $tooltype{$priv} = $tool;
1.5     ! raeburn  2635:             if ($specificity eq 'Yes') {
1.3       raeburn  2636:                 my @users =
                   2637:                   &Apache::loncommon::get_env_multiple('form.userpriv_'.$priv);
                   2638:                 foreach my $user (@users) {
                   2639:                     $group_privs{$user} .= $priv.':';
                   2640:                 }
                   2641:             } else {
1.5     ! raeburn  2642:                 if (@{$defprivs} > 0) {
        !          2643:                     foreach my $priv (@{$defprivs}) {
        !          2644:                         foreach my $user (sort(keys(%{$usertools}))) {
        !          2645:                             if ($$usertools{$user}{$tool}) {
        !          2646:                                 $group_privs{$user} .= $priv.':';
        !          2647:                             }
1.3       raeburn  2648:                         }
                   2649:                     }
                   2650:                 }
                   2651:             }
                   2652:         }
                   2653:     }
                   2654:     foreach my $user (keys(%group_privs)) {
                   2655:         $group_privs{$user} =~ s/:$//;
                   2656:     }
1.5     ! raeburn  2657: 
        !          2658:     foreach my $user (sort(keys(%{$usertools}))) {
        !          2659:         $usersettings{$groupname.':'.$user} = $enddate.':'.$startdate.':'.
        !          2660:                                               $group_privs{$user};
        !          2661:         if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname,
        !          2662:                                                 $user,$enddate,$startdate,
        !          2663:                                                 $group_privs{$user}) eq 'ok') {
        !          2664:             push(@added,$user);
1.3       raeburn  2665:         } else {
1.5     ! raeburn  2666:             push(@failed,$user);
        !          2667:         }
        !          2668:     }
        !          2669:     my $roster_result = &Apache::lonnet::modify_coursegroup_membership($cdom,
        !          2670:                                                        $cnum,\%usersettings);
        !          2671:     if (@added > 0) {
        !          2672:         $r->print('Users were added with following privileges:<br />');
        !          2673:         foreach my $user (@added) {
        !          2674:             my @privs = split(/:/,$group_privs{$user});
        !          2675:             my $privlist= '';
        !          2676:             my $curr_tool = '';
        !          2677:             foreach my $priv (@privs) {
        !          2678:                 unless ($curr_tool eq $tooltype{$priv}) {
        !          2679:                     $curr_tool = $tooltype{$priv};
        !          2680:                     $privlist .= '<b>'.$curr_tool.'</b>: ';
        !          2681:                 }
        !          2682:                 $privlist .= $$toolprivs{$curr_tool}{$priv}.', ';
        !          2683:             }
        !          2684:             $privlist =~ s/, $//;
        !          2685:             $r->print($$userdata{$user}[$$idx{fullname}].'&nbsp;-&nbsp;'.$user.': '.$privlist.'<br />');
        !          2686:         }
        !          2687:     }
        !          2688:     if (@failed > 0) {
        !          2689:         $r->print('Addition of the following users was unsuccessful:<br />');
        !          2690:         foreach my $user (@failed) {
        !          2691:             $r->print($$userdata{$user}[$$idx{fullname}].' - '.$user.'<br />');
        !          2692:         }
        !          2693:     }
        !          2694:     if ($roster_result eq 'ok') {
        !          2695:         $r->print('<br />Group membership list updated.');
        !          2696:     } else {
        !          2697:         $r->print('<br />An error occurred while updating the group membership list -'.$roster_result.'<br />');
        !          2698:     }
        !          2699:     return;
        !          2700: }
        !          2701: 
        !          2702: sub mapping_options {
        !          2703:     my ($r,$action,$formname,$page,$tabcol,$sectioncount,$states,$stored,
        !          2704:         $navbuttons,$img1,$img2,$rowColor1,$rowColor2) = @_;
        !          2705:     my %lt = &Apache::lonlocal::texthash(
        !          2706:         'auto' => 'Settings for automatic group enrollment',
        !          2707:         'gmma' => 'Group membership mapping to specific sections/roles',
        !          2708:         'endi' => 'Enable/disable automatic group enrollment for '.
        !          2709:                           'users in specified roles and sections',
        !          2710:         'adds'  => 'If automatic group enrollment is enabled, when a user is assigned a course-wide or section-specific role, he/she will automatically be added as a member of the group, with start and end access dates defined by the default dates set for the group, unless he/she is already a group member, with access dates that permit either current or future group access.',
        !          2711:         'drops'  => "If automatic group disenrollment is enabled, when a user's role is expired, access to the group will be terminated unless the user continues to have other course-wide or section-specific active or future roles which receive automatic membership in the group.",
        !          2712:         'pirs' => 'Pick roles and sections for automatic group enrollment',
        !          2713:         'curr' => 'Currently set to',
        !          2714:         'on' => 'on',
        !          2715:         'off' => 'off',
        !          2716:         'auad' => 'Automatically enable group membership when roles are added?',
        !          2717:         'auex' => 'Automatically expire group membership when roles are removed?',
        !          2718:         'mapr' => 'Mapping of roles and sections affected by automatic group enrollment/disenrollment follows scheme chosen below.',
        !          2719:     );
        !          2720:     &automapping($r,$action,$tabcol,$stored,\%lt,$img1);
        !          2721:     $r->print('
        !          2722:    <tr>
        !          2723:     <td colspan="4">&nbsp;</td>
        !          2724:    </tr>');
        !          2725:     &mapping_settings($r,$tabcol,$rowColor1,$rowColor2,$sectioncount,\%lt,
        !          2726:                                                        $stored,$img2);
        !          2727:     return;
        !          2728: }
        !          2729: 
        !          2730: sub automapping {
        !          2731:     my ($r,$action,$tabcol,$stored,$lt,$image) = @_;
        !          2732:     my $add = 'off';
        !          2733:     my $drop = 'off';
        !          2734:     if (exists($$stored{'autoadd'})) {
        !          2735:         $add = $$stored{'autoadd'};
        !          2736:     }
        !          2737:     if (exists($$stored{'autodrop'})) {
        !          2738:         $drop = $$stored{'autodrop'};
        !          2739:     }
        !          2740:     &topic_bar($r,$tabcol,$image,$$lt{'endi'});
        !          2741:     $r->print('
        !          2742:   <tr>
        !          2743:    <td>&nbsp;</td>
        !          2744:    <td colspan="3">
        !          2745:     <b>'.$$lt{'gmma'}.':</b><br />'.$$lt{'adds'}.'<br />'.$$lt{'drops'}.'<br />
        !          2746:    </td>
        !          2747:   </tr>
        !          2748:   <tr>
        !          2749:    <td colspan="4">&nbsp;</td>
        !          2750:   </tr>
        !          2751:   <tr>
        !          2752:    <td>&nbsp;</td>
        !          2753:    <td colspan="3">
        !          2754:    <nobr>'.$$lt{'auad'}.':&nbsp;
        !          2755:     <input type="radio" name="autoadd" value="on" />on&nbsp;&nbsp;<input type="radio" name="autoadd" value="off" />off');
        !          2756:     if ($action eq 'modify') {
        !          2757:         $r->print('&nbsp;&nbsp;&nbsp;&nbsp;('.$$lt{'curr'}.' <b>'.$$lt{$add}.'</b>)');
        !          2758:     }
        !          2759:     $r->print('
        !          2760:     </nobr>
        !          2761:    </td>
        !          2762:   </tr>
        !          2763:   <tr>
        !          2764:    <td>&nbsp;</td>
        !          2765:    <td colspan="3">
        !          2766:     <nobr>'.$$lt{'auex'}.':&nbsp;
        !          2767:     <input type="radio" name="autodrop" value="on" />on&nbsp;&nbsp;<input type="radio" name="autodrop" value="off" />off');
        !          2768:     if ($action eq 'modify') {
        !          2769:         $r->print('&nbsp;&nbsp;&nbsp;&nbsp;('.$$lt{'curr'}.' <b>'.$$lt{$drop}.'</b>)');
1.3       raeburn  2770:     }
1.5     ! raeburn  2771:     $r->print('</nobr>
        !          2772:    </td>
        !          2773:   </tr>
        !          2774:   <tr>
        !          2775:    <td colspan="4">&nbsp;</td>
        !          2776:   </tr>
        !          2777:   <tr>
        !          2778:    <td>&nbsp;</td>
        !          2779:    <td colspan="3">'.$$lt{'mapr'}.'
        !          2780:    </td>
        !          2781:   </tr>
        !          2782: ');
        !          2783: }
1.3       raeburn  2784: 
1.5     ! raeburn  2785: sub mapping_settings {
        !          2786:     my ($r,$tabcol,$rowColor1,$rowColor2,$sectioncount,$lt,$stored,$image) = @_;
        !          2787:     my @sections = keys(%{$sectioncount});
        !          2788:     if (@sections > 0) {
        !          2789:         @sections = sort {$a cmp $b} @sections;
        !          2790:         unshift(@sections,'_nosec'); # Put 'no sections' next
        !          2791:         unshift(@sections,'_all'); # Put 'all' at the front of the list
1.3       raeburn  2792:     }
1.5     ! raeburn  2793:     &topic_bar($r,$tabcol,$image,$$lt{'pirs'});
        !          2794:     $r->print('
        !          2795:    <tr>
        !          2796:     <td>&nbsp;</td>
        !          2797:     <td colspan="3">
        !          2798: ');
        !          2799:     my @roles = &standard_roles();
        !          2800:     my %customroles = &my_custom_roles();
        !          2801:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
        !          2802:     $r->print('
        !          2803:                 <tr bgcolor="'.$tabcol.'">
        !          2804:                  <th>'.&mt('Active?').'</th>
        !          2805:                  <th>'.&mt('Role').'</th>');
        !          2806:     if (@sections > 0) {
        !          2807:         $r->print('<th>'.&mt('Sections').'</th></tr>'."\n");
1.3       raeburn  2808:     }
1.5     ! raeburn  2809:     my $rowNum = 0;
        !          2810:     my $rowColor;
        !          2811:     foreach my $role (@roles) {
        !          2812:         my $plrole=&Apache::lonnet::plaintext($role);
        !          2813:         my $sections_sel;
        !          2814:         if (@sections > 0) {
        !          2815:             $sections_sel='<td>'.&sections_selection(\@sections,'sec_'.$role).
        !          2816:                                                                        '</td>';
        !          2817:         }
        !          2818:         if ($rowNum %2 == 1) {
        !          2819:             $rowColor = $rowColor1;
        !          2820:         } else {
        !          2821:             $rowColor = $rowColor2;
1.3       raeburn  2822:         }
1.5     ! raeburn  2823:         $r->print('<tr bgcolor="'.$rowColor.'"><td><input type="checkbox" '.
        !          2824:                   'name="autorole" value="'.$role.'"></td><td>'.$plrole.
        !          2825:                   '</td>'.$sections_sel.'</tr>');
        !          2826:         $rowNum ++;
        !          2827:     }
        !          2828:     foreach my $role (sort(keys(%customroles))) {
        !          2829:         my $sections_sel;
        !          2830:         if (@sections > 0) {
        !          2831:             $sections_sel = '<td>'.&sections_selection(\@sections,'sec_'.$role).
        !          2832:                                                                         '</td>';
1.3       raeburn  2833:         }
1.5     ! raeburn  2834:         if ($rowNum %2 == 1) {
        !          2835:             $rowColor = $rowColor1;
1.3       raeburn  2836:         } else {
1.5     ! raeburn  2837:             $rowColor = $rowColor2;
        !          2838:         }
        !          2839:         $r->print('<tr bgcolor="'.$rowColor.'"><td><input type="checkbox" '.
        !          2840:                   'value="'.$role.'"></td><td>'.$role.'</td>'.
        !          2841:                   $sections_sel.'</tr>');
        !          2842:         $rowNum ++;
        !          2843:     }
        !          2844:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
        !          2845:     return;
        !          2846: }
1.3       raeburn  2847: 
1.5     ! raeburn  2848: sub standard_roles {
        !          2849:     my @roles = ('st','ep','ta','in','cc');
        !          2850:     return @roles;
        !          2851: }
        !          2852: 
        !          2853: sub my_custom_roles {
        !          2854:     my %returnhash=();
        !          2855:     my %rolehash=&Apache::lonnet::dump('roles');
        !          2856:     foreach (keys %rolehash) {
        !          2857:         if ($_=~/^rolesdef\_(\w+)$/) {
        !          2858:             $returnhash{$1}=$1;
        !          2859:         }
        !          2860:     }
        !          2861:     return %returnhash;
        !          2862: }
        !          2863: 
        !          2864: sub modify_menu {
        !          2865:     my ($r,$groupname,$page) = @_;
        !          2866:     my @menu =
        !          2867:         (
        !          2868:           { text => 'Modify default group settings',
        !          2869:             help => 'Course_Modify_Group',
        !          2870:             state => 'change_settings',
        !          2871:             branch => 'settings',
        !          2872:             },
        !          2873:           { text => 'Modify access, tools and/or privileges for previous,future'.
        !          2874:                     'or current members',
        !          2875:             help => 'Course_Modify_Group_Membership',
        !          2876:             state => 'change_members',
        !          2877:             branch => 'members',
        !          2878:             },
        !          2879:           { text => 'Add member(s) to the group',
        !          2880:             help => 'Course_Group_Add_Members',
        !          2881:             state => 'add_members',
        !          2882:             branch => 'adds',
        !          2883:             },
        !          2884:           );
        !          2885:     my $menu_html = '';
        !          2886:     foreach my $menu_item (@menu) {
        !          2887:         $menu_html .=
        !          2888:         '<p><font size="+1"><a href="/adm/coursegroups?action=modify&refpage='.$env{'form.refpage'}.'&groupname='.$groupname.'&state='.$menu_item->{'state'}.'&branch='.$menu_item->{'branch'}.'">';
        !          2889:         $menu_html.= &mt($menu_item->{'text'}).'</a></font>';
        !          2890:         if (exists($menu_item->{'help'})) {
        !          2891:             $menu_html.=
        !          2892:                 &Apache::loncommon::help_open_topic($menu_item->{'help'});
        !          2893:         }
        !          2894:         $menu_html.='</p>'.$/;
1.3       raeburn  2895:     }
1.5     ! raeburn  2896:     $r->print($menu_html);
1.3       raeburn  2897:     return;
                   2898: }
                   2899: 
                   2900: sub member_privs_entries {
1.5     ! raeburn  2901:     my ($r,$tabcol,$rowColor1,$rowColor2,$usertools,$toolprivs,
        !          2902:         $fixedprivs,$userdata,$idx,$showtools,$defprivs) = @_;
1.3       raeburn  2903:     my $rowColor;
                   2904:     my $rowNum = 0;
1.5     ! raeburn  2905:     foreach my $user (sort(keys(%{$usertools}))) {
        !          2906:         my ($uname,$udom) = split(/:/,$user);
1.3       raeburn  2907:         if ($rowNum %2 == 1) {
                   2908:             $rowColor = $rowColor1;
                   2909:         } else {
                   2910:             $rowColor = $rowColor2;
                   2911:         }
                   2912:         $r->print('<tr bgcolor="'.$rowColor.'">
1.5     ! raeburn  2913:                 <td>'.$$userdata{$user}[$$idx{fullname}].'</td>
1.3       raeburn  2914:                 <td>'.$uname.'</td>
                   2915:                 <td>'.$udom.'</td>
                   2916:                 <td valign="top"><table><tr><td><b>Function</b></td></tr><tr><td><b>Fixed</b></td></tr><tr><td><b>Optional</b></td></tr></table></td>');
1.5     ! raeburn  2917:         foreach my $tool (@{$showtools}) {
        !          2918:             if (exists($$usertools{$user}{$tool})) {
1.3       raeburn  2919:                 $r->print('<td valign="top"><table><tr bgcolor="'.$tabcol.'"><td colspan="2" align="center"><b>'.$tool.'</b></td></tr>');
                   2920:                 my $privcount = 0;
                   2921:                 my $fixed = '';
                   2922:                 my $dynamic = '';
                   2923:                 foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
                   2924:                     if (exists($$fixedprivs{$tool}{$priv})) {
1.5     ! raeburn  2925:                         $fixed .= '<input type="hidden" name="userpriv_'.$priv.'" value="'.$user.'" />'.$$toolprivs{$tool}{$priv}.'&nbsp;';
1.3       raeburn  2926:                     } else {
                   2927:                         $privcount ++;
                   2928:                         if ($privcount == 3) {
                   2929:                             $dynamic .= '</tr><tr>';
                   2930:                         }
1.5     ! raeburn  2931:                         $dynamic .='<td><nobr><input type="checkbox" '.
        !          2932:                                'name="userpriv_'.$priv.'" value="'.$user.'"';
        !          2933:                         if (grep/^\Q$priv\E$/,@{$defprivs}) {
        !          2934:                             $dynamic .= ' checked="checked" ';
        !          2935:                         }
        !          2936:                         $dynamic .= ' />'.$$toolprivs{$tool}{$priv}.
        !          2937:                                     '</nobr></td>';
1.3       raeburn  2938:                     }
                   2939:                 }
                   2940:                 $r->print('<tr><td colspan="2"><nobr>'.$fixed.'</nobr></td></tr><tr>'.$dynamic.'</tr></table></td>');
                   2941:             } else {
1.5     ! raeburn  2942:                 $r->print('<td valign="top"><table width="100%"><tr bgcolor="'.$tabcol.'"><td colspan="2" align="center"><b>'.$tool.'</b></td></tr><tr><td>&nbsp;</td></tr><tr><td>&nbsp;</td></tr></table></td>');
1.3       raeburn  2943:             }
                   2944:         }
                   2945:         $rowNum ++;
                   2946:     }
                   2947: }
                   2948: 
                   2949: sub get_dates_from_form {
                   2950:     my $startdate;
                   2951:     my $enddate;
                   2952:     $startdate = &Apache::lonhtmlcommon::get_date_from_form('startdate');
                   2953:     $enddate   = &Apache::lonhtmlcommon::get_date_from_form('enddate');
                   2954:     if ( exists ($env{'form.no_end_date'}) ) {
                   2955:         $enddate = 0;
                   2956:     }
                   2957:     return ($startdate,$enddate);
1.5     ! raeburn  2958: }
        !          2959: 
1.3       raeburn  2960: sub date_setting_table {
                   2961:     my ($starttime,$endtime,$formname) = @_;
                   2962:     my $startform = &Apache::lonhtmlcommon::date_setter($formname,
                   2963:                                                       'startdate',$starttime);
                   2964:     my $endform = &Apache::lonhtmlcommon::date_setter($formname,
                   2965:                                                       'enddate',$endtime);
                   2966:     my $perpetual = '<nobr><input type="checkbox" name="no_end_date" />
                   2967:                                                   no ending date</nobr>';
                   2968:     my $start_table = '';
                   2969:     $start_table .= "<table>\n";
                   2970:     $start_table .= '<tr><td align="right">Default starting date for 
                   2971:                                            member access</td>'.
                   2972:         '<td>'.$startform.'</td>'.
                   2973:         '<td>&nbsp;</td>'."</tr>\n";
                   2974:     $start_table .= "</table>";
                   2975:     my $end_table = '';
                   2976:     $end_table .= "<table>\n";
                   2977:     $end_table .= '<tr><td align="right">Default ending date for 
                   2978:                                          member access</td>'.
                   2979:         '<td>'.$endform.'</td>'.
                   2980:         '<td>'.$perpetual.'</td>'."</tr>\n";
                   2981:     $end_table .= "</table>\n";
                   2982:     return ($start_table, $end_table);
1.1       raeburn  2983: }
                   2984: 
1.3       raeburn  2985: sub create_homepage {
                   2986:     my ($cdom,$cnum,$name,$groupinfo,$tools) = @_;
                   2987:     my $functionality = join(',',@{$tools});
                   2988:     my $content = &Apache::lonnet::unescape($$groupinfo{description});
                   2989:     $content=~s/\s+$//s;
                   2990:     $content=~s/^\s+//s;
                   2991:     $content=~s/\<br\s*\/*\>$//s;
                   2992:     $content=&Apache::lonfeedback::clear_out_html($content,1);
                   2993: 
                   2994:     my %pageinfo = (
                   2995:                      'aaa_title' => 'Group: '.$name,
                   2996:                      'abb_links' => $functionality,
                   2997:                      'bbb_content' => $content,
                   2998:                      'ccc_webreferences' => '',
                   2999:                      'uploaded.lastmodified' => time,
                   3000:                    );
                   3001:    my $putresult = &Apache::lonnet::put('grppage_'.$name,\%pageinfo,$cdom,$cnum);
                   3002:    return $putresult;
1.1       raeburn  3003: }
                   3004: 
1.5     ! raeburn  3005: sub check_uncheck_tools {
        !          3006:     my ($r,$available) = @_;
        !          3007:     if (ref($available) eq 'ARRAY') { 
        !          3008:         $r->print('
        !          3009: <script type="text/javascript">
        !          3010: function checkAllTools(formname) {
        !          3011: ');
        !          3012:         foreach my $tool (@{$available}) {
        !          3013:             $r->print('  checkAll(formname.user_'.$tool.');'."\n");
        !          3014:         }
        !          3015:         $r->print(' checkAll(formname.togglefunc);'."\n");
        !          3016:         $r->print('
        !          3017: }
        !          3018: function uncheckAllTools(formname) {
        !          3019: ');
        !          3020:         foreach my $tool (@{$available}) {
        !          3021:             $r->print('  uncheckAll(formname.user_'.$tool.');'."\n");
        !          3022:         }
        !          3023:         $r->print(' uncheckAll(formname.togglefunc);'."\n");
        !          3024:         $r->print('
        !          3025: }
        !          3026: function toggleTools(field,caller) {
        !          3027:      if (caller.checked) {
        !          3028:          checkAll(field);
        !          3029:      } else {
        !          3030:          uncheckAll(field);
        !          3031:      }
        !          3032:      return;   
        !          3033: }
        !          3034: </script>
        !          3035: ');
        !          3036:     }
        !          3037:     return;
        !          3038: }
        !          3039: 
        !          3040: sub validate_groupname {
        !          3041:     my ($groupname,$action,$cdom,$cnum) = @_;
        !          3042:     my %sectioncount;
        !          3043:     my $numsec=&Apache::loncommon::get_sections($cdom,$cnum,\%sectioncount);
        !          3044:     my %curr_groups;
        !          3045:     my $numgroups=&Apache::loncommon::coursegroups(\%curr_groups,$cdom,$cnum);
        !          3046:                                                                                          
        !          3047:     my %lt = &Apache::lonlocal::texthash (
        !          3048:                       igna => 'Invalid group name',
        !          3049:                       tgne => 'The group name entered ',
        !          3050:                       grna => 'Group names and section names used in a course '.
        !          3051:                               'must be unique.',
        !          3052:                       isno => 'is not a valid name.',
        !          3053:                       gnmo => 'Group names may only contain letters, numbers '.
        !          3054:                               'or underscores.',
        !          3055:                       cnnb => 'can not be used as it is the name of ',
        !          3056:                       inth => ' in this course.',
        !          3057:                       thgr => '- does not correspond to the name of an existing'.  
        !          3058:                               ' group ',    
        !          3059:     );
        !          3060:                                                                                          
        !          3061:     my $exitmsg = '<b>'.$lt{'igna'}.'</b><br /><br />'.$lt{'tgne'}.' "'.
        !          3062:                   $groupname.'" ';
        !          3063:     my $dupmsg = $lt{'grna'};
        !          3064:     my $earlyout;
        !          3065:     if (($groupname eq '') || ($groupname =~ /\W/)) {
        !          3066:         $earlyout = $exitmsg.$lt{'isno'}.'<br />'.$lt{'gnmo'};
        !          3067:         return $earlyout;
        !          3068:     }
        !          3069:     if ($numsec) {
        !          3070:         if (exists($sectioncount{$groupname})) {
        !          3071:             $earlyout = $exitmsg.$lt{'cnnb'}.&mt('a section').$lt{'inth'}.
        !          3072:                         '<br />'.$lt{'grna'};
        !          3073:             return $earlyout;
        !          3074:         }
        !          3075:     }
        !          3076:     if ($action eq 'create') {
        !          3077:         if ($numgroups) {
        !          3078:             if (exists($curr_groups{$groupname})) {
        !          3079:                 $earlyout = $exitmsg.$lt{'cnnb'}.&mt('an existing group').
        !          3080:                             $lt{'inth'}.'<br />'.$lt{'grna'};
        !          3081:                 return $earlyout;
        !          3082:             }
        !          3083:         }
        !          3084:     } elsif ($action eq 'modify') {
        !          3085:         unless(exists($curr_groups{$groupname})) {
        !          3086:             $earlyout = &mt('Group name:').' '.$groupname.$lt{'thgr'}.$lt{'inth'};
        !          3087:             return $earlyout;
        !          3088:         }
        !          3089:     }
        !          3090:     return;
        !          3091: }
        !          3092: 
        !          3093: sub topic_bar {
        !          3094:     my ($r,$tabcol,$imgnum,$title) = @_;
        !          3095:     $r->print('
        !          3096:  <tr bgcolor="'.$tabcol.'">
        !          3097:   <td>&nbsp;</td>
        !          3098:   <td valign="middle" align="left">
        !          3099:    <nobr>
        !          3100:     <img src="/res/adm/pages/bl_step'.$imgnum.'.gif" valign="middle">&nbsp;
        !          3101:    </nobr>
        !          3102:   </td>
        !          3103:   <th align="left"><nobr>'.$title.'<nobr>
        !          3104:   </th>
        !          3105:   <td width="100%">&nbsp;</td>
        !          3106:  </tr>
        !          3107:  <tr>
        !          3108:   <td colspan="4">&nbsp;</td>
        !          3109:  </tr>
        !          3110: ');
        !          3111:     return;
        !          3112: }
        !          3113: 
        !          3114: sub check_changes {
        !          3115:     my ($member_changes,$memchg) = @_;
        !          3116:     my %exclusions;
        !          3117:     @{$exclusions{'changefunc'}} = ('expire');
        !          3118:     @{$exclusions{'changepriv'}} = ('expire','changefunc');
        !          3119: 
        !          3120:     foreach my $change (@{$member_changes}) {
        !          3121:         if ($change eq 'delete') {
        !          3122:             next;
        !          3123:         }
        !          3124:         my @checks = ('delete');
        !          3125:         if (exists($exclusions{$change})) {
        !          3126:             push(@checks,@{$exclusions{$change}});
        !          3127:         }
        !          3128:         my @temp = ();
        !          3129:         foreach my $item (@{$$memchg{$change}}) {
        !          3130:             my $match = 0;
        !          3131:             foreach my $check (@checks) {
        !          3132:                 if (@{$$memchg{$check}} > 0) {
        !          3133:                     if (grep/^$item$/,@{$$memchg{$check}}) {
        !          3134:                         $match = 1;
        !          3135:                         last;
        !          3136:                     }
        !          3137:                 }
        !          3138:             }
        !          3139:             if ($match) {
        !          3140:                 next;
        !          3141:             }
        !          3142:             push(@temp,$item);
        !          3143:         }
        !          3144:         @{$$memchg{$change}} = @temp;
        !          3145:     }
        !          3146: }
1.3       raeburn  3147: 
1.1       raeburn  3148: 1;

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