Annotation of loncom/interface/lonuserutils.pm, revision 1.51

1.1       raeburn     1: # The LearningOnline Network with CAPA
                      2: # Utility functions for managing LON-CAPA user accounts
                      3: #
1.51    ! raeburn     4: # $Id: lonuserutils.pm,v 1.50 2008/01/20 22:25:05 raeburn Exp $
1.1       raeburn     5: #
                      6: # Copyright Michigan State University Board of Trustees
                      7: #
                      8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      9: #
                     10: # LON-CAPA is free software; you can redistribute it and/or modify
                     11: # it under the terms of the GNU General Public License as published by
                     12: # the Free Software Foundation; either version 2 of the License, or
                     13: # (at your option) any later version.
                     14: #
                     15: # LON-CAPA is distributed in the hope that it will be useful,
                     16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     18: # GNU General Public License for more details.
                     19: #
                     20: # You should have received a copy of the GNU General Public License
                     21: # along with LON-CAPA; if not, write to the Free Software
                     22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA#
                     23: # /home/httpd/html/adm/gpl.txt
                     24: #
                     25: # http://www.lon-capa.org/
                     26: #
                     27: #
                     28: ###############################################################
                     29: ###############################################################
                     30: 
                     31: package Apache::lonuserutils;
                     32: 
                     33: use strict;
                     34: use Apache::lonnet;
                     35: use Apache::loncommon();
                     36: use Apache::lonhtmlcommon;
                     37: use Apache::lonlocal;
1.8       raeburn    38: use Apache::longroup;
                     39: use LONCAPA qw(:DEFAULT :match);
1.1       raeburn    40: 
                     41: ###############################################################
                     42: ###############################################################
                     43: # Drop student from all sections of a course, except optional $csec
                     44: sub modifystudent {
                     45:     my ($udom,$unam,$courseid,$csec,$desiredhost)=@_;
                     46:     # if $csec is undefined, drop the student from all the courses matching
                     47:     # this one.  If $csec is defined, drop them from all other sections of
                     48:     # this course and add them to section $csec
1.17      raeburn    49:     my ($cnum,$cdom) = &get_course_identity($courseid);
1.1       raeburn    50:     my %roles = &Apache::lonnet::dump('roles',$udom,$unam);
                     51:     my ($tmp) = keys(%roles);
                     52:     # Bail out if we were unable to get the students roles
                     53:     return "$1" if ($tmp =~ /^(con_lost|error|no_such_host)/i);
                     54:     # Go through the roles looking for enrollment in this course
                     55:     my $result = '';
                     56:     foreach my $course (keys(%roles)) {
                     57:         if ($course=~m{^/\Q$cdom\E/\Q$cnum\E(?:\/)*(?:\s+)*(\w+)*\_st$}) {
                     58:             # We are in this course
                     59:             my $section=$1;
                     60:             $section='' if ($course eq "/$cdom/$cnum".'_st');
                     61:             if (defined($csec) && $section eq $csec) {
                     62:                 $result .= 'ok:';
                     63:             } elsif ( ((!$section) && (!$csec)) || ($section ne $csec) ) {
                     64:                 my (undef,$end,$start)=split(/\_/,$roles{$course});
                     65:                 my $now=time;
                     66:                 # if this is an active role
                     67:                 if (!($start && ($now<$start)) || !($end && ($now>$end))) {
                     68:                     my $reply=&Apache::lonnet::modifystudent
                     69:                         # dom  name  id mode pass     f     m     l     g
                     70:                         ($udom,$unam,'',  '',  '',undef,undef,undef,undef,
1.22      raeburn    71:                          $section,time,undef,undef,$desiredhost,'','manual',
                     72:                          '',$courseid);
1.1       raeburn    73:                     $result .= $reply.':';
                     74:                 }
                     75:             }
                     76:         }
                     77:     }
                     78:     if ($result eq '') {
1.37      raeburn    79:         $result = &mt('Unable to find section for this student');
1.1       raeburn    80:     } else {
                     81:         $result =~ s/(ok:)+/ok/g;
                     82:     }
                     83:     return $result;
                     84: }
                     85: 
                     86: sub modifyuserrole {
                     87:     my ($context,$setting,$changeauth,$cid,$udom,$uname,$uid,$umode,$upass,
                     88:         $first,$middle,$last,$gene,$sec,$forceid,$desiredhome,$email,$role,
1.5       raeburn    89:         $end,$start,$checkid) = @_;
                     90:     my ($scope,$userresult,$authresult,$roleresult,$idresult);
1.1       raeburn    91:     if ($setting eq 'course' || $context eq 'course') {
                     92:         $scope = '/'.$cid;
                     93:         $scope =~ s/\_/\//g;
                     94:         if ($role ne 'cc' && $sec ne '') {
                     95:             $scope .='/'.$sec;
                     96:         }
1.5       raeburn    97:     } elsif ($context eq 'domain') {
1.1       raeburn    98:         $scope = '/'.$env{'request.role.domain'}.'/';
1.13      raeburn    99:     } elsif ($context eq 'author') {
1.1       raeburn   100:         $scope =  '/'.$env{'user.domain'}.'/'.$env{'user.name'};
                    101:     }
                    102:     if ($context eq 'domain') {
                    103:         my $uhome = &Apache::lonnet::homeserver($uname,$udom);
                    104:         if ($uhome ne 'no_host') {
1.5       raeburn   105:             if (($changeauth eq 'Yes') && (&Apache::lonnet::allowed('mau',$udom))) {
1.1       raeburn   106:                 if ((($umode =~ /^krb4|krb5|internal$/) && $upass ne '') ||
                    107:                     ($umode eq 'localauth')) {
                    108:                     $authresult = &Apache::lonnet::modifyuserauth($udom,$uname,$umode,$upass);
                    109:                 }
                    110:             }
1.5       raeburn   111:             if (($forceid) && (&Apache::lonnet::allowed('mau',$udom)) &&
                    112:                 ($env{'form.recurseid'}) && ($checkid)) {
                    113:                 my %userupdate = (
                    114:                                   lastname   => $last,
                    115:                                   middlename => $middle,
                    116:                                   firstname  => $first,
                    117:                                   generation => $gene,
                    118:                                   id         => $uid,
                    119:                                  );
                    120:                 $idresult = &propagate_id_change($uname,$udom,\%userupdate);
                    121:             }
1.1       raeburn   122:         }
                    123:     }
                    124:     $userresult =
                    125:         &Apache::lonnet::modifyuser($udom,$uname,$uid,$umode,$upass,$first,
                    126:                                     $middle,$last,$gene,$forceid,$desiredhome,
                    127:                                     $email,$role,$start,$end);
                    128:     if ($userresult eq 'ok') {
1.5       raeburn   129:         if ($role ne '') {
1.22      raeburn   130:             $role =~ s/_/\//g;
1.1       raeburn   131:             $roleresult = &Apache::lonnet::assignrole($udom,$uname,$scope,
                    132:                                                       $role,$end,$start);
                    133:         }
                    134:     }
1.5       raeburn   135:     return ($userresult,$authresult,$roleresult,$idresult);
1.1       raeburn   136: }
                    137: 
1.5       raeburn   138: sub propagate_id_change {
                    139:     my ($uname,$udom,$user) = @_;
1.12      raeburn   140:     my (@types,@roles);
1.5       raeburn   141:     @types = ('active','future');
                    142:     @roles = ('st');
                    143:     my $idresult;
                    144:     my %roleshash = &Apache::lonnet::get_my_roles($uname,
1.12      raeburn   145:                         $udom,'userroles',\@types,\@roles);
                    146:     my %args = (
                    147:                 one_time => 1,
                    148:                );
1.5       raeburn   149:     foreach my $item (keys(%roleshash)) {
1.22      raeburn   150:         my ($cnum,$cdom,$role) = split(/:/,$item,-1);
1.5       raeburn   151:         my ($start,$end) = split(/:/,$roleshash{$item});
                    152:         if (&Apache::lonnet::is_course($cdom,$cnum)) {
1.12      raeburn   153:             my $result = &update_classlist($cdom,$cnum,$udom,$uname,$user);
                    154:             my %coursehash = 
                    155:                 &Apache::lonnet::coursedescription($cdom.'_'.$cnum,\%args);
                    156:             my $cdesc = $coursehash{'description'};
                    157:             if ($cdesc eq '') { 
                    158:                 $cdesc = $cdom.'_'.$cnum;
                    159:             }
1.5       raeburn   160:             if ($result eq 'ok') {
1.12      raeburn   161:                 $idresult .= &mt('Classlist update for "[_1]" in "[_2]".',$uname.':'.$udom,$cdesc).'<br />'."\n";
1.5       raeburn   162:             } else {
1.12      raeburn   163:                 $idresult .= &mt('Error: "[_1]" during classlist update for "[_2]" in "[_3]".',$result,$uname.':'.$udom,$cdesc).'<br />'."\n";
1.5       raeburn   164:             }
                    165:         }
                    166:     }
                    167:     return $idresult;
                    168: }
                    169: 
                    170: sub update_classlist {
                    171:     my ($cdom,$cnum,$udom,$uname,$user) = @_;
1.6       albertel  172:     my ($uid,$classlistentry);
1.5       raeburn   173:     my $fullname =
                    174:         &Apache::lonnet::format_name($user->{'firstname'},$user->{'middlename'},
                    175:                                      $user->{'lastname'},$user->{'generation'},
                    176:                                      'lastname');
                    177:     my %classhash = &Apache::lonnet::get('classlist',[$uname.':'.$udom],
                    178:                                          $cdom,$cnum);
                    179:     my @classinfo = split(/:/,$classhash{$uname.':'.$udom});
                    180:     my $ididx=&Apache::loncoursedata::CL_ID() - 2;
                    181:     my $nameidx=&Apache::loncoursedata::CL_FULLNAME() - 2;
                    182:     for (my $i=0; $i<@classinfo; $i++) {
                    183:         if ($i == $ididx) {
                    184:             if (defined($user->{'id'})) {
                    185:                 $classlistentry .= $user->{'id'}.':';
                    186:             } else {
                    187:                 $classlistentry .= $classinfo[$i].':';
                    188:             }
                    189:         } elsif ($i == $nameidx) {
                    190:             $classlistentry .= $fullname.':';
                    191:         } else {
                    192:             $classlistentry .= $classinfo[$i].':';
                    193:         }
                    194:     }
                    195:     $classlistentry =~ s/:$//;
                    196:     my $reply=&Apache::lonnet::cput('classlist',
                    197:                                     {"$uname:$udom" => $classlistentry},
                    198:                                     $cdom,$cnum);
                    199:     if (($reply eq 'ok') || ($reply eq 'delayed')) {
                    200:         return 'ok';
                    201:     } else {
                    202:         return 'error: '.$reply;
                    203:     }
                    204: }
                    205: 
                    206: 
1.1       raeburn   207: ###############################################################
                    208: ###############################################################
1.2       raeburn   209: # build a role type and role selection form
                    210: sub domain_roles_select {
                    211:     # Set up the role type and role selection boxes when in 
                    212:     # domain context   
                    213:     #
                    214:     # Role types
1.13      raeburn   215:     my @roletypes = ('domain','author','course');
1.2       raeburn   216:     my %lt = &role_type_names();
1.1       raeburn   217:     #
                    218:     # build up the menu information to be passed to
                    219:     # &Apache::loncommon::linked_select_forms
                    220:     my %select_menus;
1.2       raeburn   221:     if ($env{'form.roletype'} eq '') {
                    222:         $env{'form.roletype'} = 'domain';
                    223:     }
                    224:     foreach my $roletype (@roletypes) {
1.1       raeburn   225:         # set up the text for this domain
1.2       raeburn   226:         $select_menus{$roletype}->{'text'}= $lt{$roletype};
1.1       raeburn   227:         # we want a choice of 'default' as the default in the second menu
1.2       raeburn   228:         if ($env{'form.roletype'} ne '') {
                    229:             $select_menus{$roletype}->{'default'} = $env{'form.showrole'};
                    230:         } else { 
                    231:             $select_menus{$roletype}->{'default'} = 'Any';
                    232:         }
1.1       raeburn   233:         # Now build up the other items in the second menu
1.2       raeburn   234:         my @roles;
                    235:         if ($roletype eq 'domain') {
                    236:             @roles = &domain_roles();
1.13      raeburn   237:         } elsif ($roletype eq 'author') {
1.2       raeburn   238:             @roles = &construction_space_roles();
                    239:         } else {
1.17      raeburn   240:             my $custom = 1;
                    241:             @roles = &course_roles('domain',undef,$custom);
1.1       raeburn   242:         }
1.2       raeburn   243:         my $order = ['Any',@roles];
                    244:         $select_menus{$roletype}->{'order'} = $order; 
                    245:         foreach my $role (@roles) {
1.5       raeburn   246:             if ($role eq 'cr') {
                    247:                 $select_menus{$roletype}->{'select2'}->{$role} =
                    248:                               &mt('Custom role');
                    249:             } else {
                    250:                 $select_menus{$roletype}->{'select2'}->{$role} = 
                    251:                               &Apache::lonnet::plaintext($role);
                    252:             }
1.2       raeburn   253:         }
                    254:         $select_menus{$roletype}->{'select2'}->{'Any'} = &mt('Any');
1.1       raeburn   255:     }
1.2       raeburn   256:     my $result = &Apache::loncommon::linked_select_forms
                    257:         ('studentform',('&nbsp;'x3).&mt('Role: '),$env{'form.roletype'},
1.13      raeburn   258:          'roletype','showrole',\%select_menus,['domain','author','course']);
1.1       raeburn   259:     return $result;
                    260: }
                    261: 
                    262: ###############################################################
                    263: ###############################################################
                    264: sub hidden_input {
                    265:     my ($name,$value) = @_;
                    266:     return '<input type="hidden" name="'.$name.'" value="'.$value.'" />'."\n";
                    267: }
                    268: 
                    269: sub print_upload_manager_header {
1.22      raeburn   270:     my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission)=@_;
1.1       raeburn   271:     my $javascript;
                    272:     #
                    273:     if (! exists($env{'form.upfile_associate'})) {
                    274:         $env{'form.upfile_associate'} = 'forward';
                    275:     }
                    276:     if ($env{'form.associate'} eq 'Reverse Association') {
                    277:         if ( $env{'form.upfile_associate'} ne 'reverse' ) {
                    278:             $env{'form.upfile_associate'} = 'reverse';
                    279:         } else {
                    280:             $env{'form.upfile_associate'} = 'forward';
                    281:         }
                    282:     }
                    283:     if ($env{'form.upfile_associate'} eq 'reverse') {
                    284:         $javascript=&upload_manager_javascript_reverse_associate();
                    285:     } else {
                    286:         $javascript=&upload_manager_javascript_forward_associate();
                    287:     }
                    288:     #
                    289:     # Deal with restored settings
                    290:     my $password_choice = '';
                    291:     if (exists($env{'form.ipwd_choice'}) &&
                    292:         $env{'form.ipwd_choice'} ne '') {
                    293:         # If a column was specified for password, assume it is for an
                    294:         # internal password.  This is a bug waiting to be filed (could be
                    295:         # local or krb auth instead of internal) but I do not have the
                    296:         # time to mess around with this now.
                    297:         $password_choice = 'int';
                    298:     }
                    299:     #
1.22      raeburn   300:     my $groupslist;
                    301:     if ($context eq 'course') {
                    302:         $groupslist = &get_groupslist();
                    303:     }
1.1       raeburn   304:     my $javascript_validations =
1.22      raeburn   305:         &javascript_validations('upload',$krbdefdom,$password_choice,undef,
                    306:                                 $env{'request.role.domain'},$context,
1.33      raeburn   307:                                 $groupslist);
1.1       raeburn   308:     my $checked=(($env{'form.noFirstLine'})?' checked="checked" ':'');
                    309:     $r->print(&mt('Total number of records found in file: <b>[_1]</b>.',$distotal).
                    310:               "<br />\n");
                    311:     $r->print('<div class="LC_left_float"><h3>'.
                    312:               &mt('Identify fields in uploaded list')."</h3>\n");
                    313:     $r->print(&mt('Enter as many fields as you can.<br /> The system will inform you and bring you back to this page, <br /> if the data selected are insufficient to add users.')."<br />\n");
                    314:     $r->print(&hidden_input('action','upload').
                    315:               &hidden_input('state','got_file').
                    316:               &hidden_input('associate','').
                    317:               &hidden_input('datatoken',$datatoken).
                    318:               &hidden_input('fileupload',$env{'form.fileupload'}).
                    319:               &hidden_input('upfiletype',$env{'form.upfiletype'}).
                    320:               &hidden_input('upfile_associate',$env{'form.upfile_associate'}));
                    321:     $r->print('<br /><input type="button" value="Reverse Association" '.
                    322:               'name="'.&mt('Reverse Association').'" '.
                    323:               'onClick="javascript:this.form.associate.value=\'Reverse Association\';submit(this.form);" />');
                    324:     $r->print('<label><input type="checkbox" name="noFirstLine"'.$checked.'/>'.
                    325:               &mt('Ignore First Line').'</label>');
                    326:     $r->print("<br /><br />\n".
                    327:               '<script type="text/javascript" language="Javascript">'."\n".
                    328:               $javascript."\n".$javascript_validations.'</script>');
                    329: }
                    330: 
                    331: ###############################################################
                    332: ###############################################################
                    333: sub javascript_validations {
1.22      raeburn   334:     my ($mode,$krbdefdom,$curr_authtype,$curr_authfield,$domain,
1.33      raeburn   335:         $context,$groupslist)=@_;
1.22      raeburn   336:     my %param = (
                    337:                   kerb_def_dom => $krbdefdom,
                    338:                   curr_authtype => $curr_authtype,
                    339:                 );
1.37      raeburn   340:     if ($mode eq 'upload') {
1.22      raeburn   341:         $param{'formname'} = 'studentform';
1.1       raeburn   342:     } elsif ($mode eq 'createcourse') {
1.22      raeburn   343:         $param{'formname'} = 'ccrs';
1.1       raeburn   344:     } elsif ($mode eq 'modifycourse') {
1.22      raeburn   345:         $param{'formname'} = 'cmod';
                    346:         $param{'mode'} = 'modifycourse',
                    347:         $param{'curr_autharg'} = $curr_authfield;
                    348:     }
                    349: 
                    350:     my ($setsection_call,$setsections_js);
                    351:     my $finish = "  vf.submit();\n";
                    352:     if ($mode eq 'upload') {
                    353:         if (($context eq 'course') || ($context eq 'domain')) {
                    354:             if ($context eq 'course') {
                    355:                 if ($env{'request.course.sec'} eq '') {
                    356:                     $setsection_call = 'setSections(document.'.$param{'formname'}.');';
                    357:                     $setsections_js =
                    358:                         &setsections_javascript($param{'formname'},$groupslist,
                    359:                                                 $mode);
                    360:                 } else {
                    361:                     $setsection_call = "'ok'";
                    362:                 }
                    363:             } elsif ($context eq 'domain') {
                    364:                 $setsection_call = 'setCourse()';
1.37      raeburn   365:                 $setsections_js = &dc_setcourse_js($param{'formname'},$mode,$context);
1.22      raeburn   366:             }
                    367:             $finish = "  var checkSec = $setsection_call\n".
                    368:                       "  if (checkSec == 'ok') {\n".
                    369:                       "      vf.submit();\n".
                    370:                       "   }\n";
                    371:         }
1.1       raeburn   372:     }
1.22      raeburn   373:     my $authheader = &Apache::loncommon::authform_header(%param);
1.1       raeburn   374: 
                    375:     my %alert = &Apache::lonlocal::texthash
                    376:         (username => 'You need to specify the username field.',
                    377:          authen   => 'You must choose an authentication type.',
                    378:          krb      => 'You need to specify the Kerberos domain.',
                    379:          ipass    => 'You need to specify the initial password.',
                    380:          name     => 'The optional name field was not specified.',
                    381:          snum     => 'The optional ID number field was not specified.',
                    382:          section  => 'The optional section field was not specified.',
                    383:          email    => 'The optional email address field was not specified.',
                    384:          role     => 'The optional role field was not specified.',
                    385:          continue => 'Continue adding users?',
                    386:          );
1.37      raeburn   387:     my $function_name = <<"END";
1.22      raeburn   388: $setsections_js
                    389: 
1.1       raeburn   390: function verify_message (vf,founduname,foundpwd,foundname,foundid,foundsec,foundemail) {
                    391: END
                    392:     my ($authnum,%can_assign) =  &Apache::loncommon::get_assignable_auth($domain);
                    393:     my $auth_checks;
                    394:     if ($mode eq 'createcourse') {
                    395:         $auth_checks .= (<<END);
                    396:     if (vf.autoadds[0].checked == true) {
                    397:         if (current.radiovalue == null || current.radiovalue == 'nochange') {
                    398:             alert('$alert{'authen'}');
                    399:             return;
                    400:         }
                    401:     }
                    402: END
                    403:     } else {
                    404:         $auth_checks .= (<<END);
                    405:     var foundatype=0;
                    406:     if (founduname==0) {
                    407:         alert('$alert{'username'}');
                    408:         return;
                    409:     }
                    410: 
                    411: END
                    412:         if ($authnum > 1) {
                    413:             $auth_checks .= (<<END);
                    414:     if (current.radiovalue == null || current.radiovalue == '' || current.radiovalue == 'nochange') {
                    415:         // They did not check any of the login radiobuttons.
                    416:         alert('$alert{'authen'}');
                    417:         return;
                    418:     }
                    419: END
                    420:         }
                    421:     }
                    422:     if ($mode eq 'createcourse') {
                    423:         $auth_checks .= "
                    424:     if ( (vf.autoadds[0].checked == true) &&
                    425:          (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '') ) {
                    426: ";
                    427:     } elsif ($mode eq 'modifycourse') {
                    428:         $auth_checks .= "
                    429:     if (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '') {
                    430: ";
                    431:     }
                    432:     if ( ($mode eq 'createcourse') || ($mode eq 'modifycourse') ) {
                    433:         $auth_checks .= (<<END);
                    434:         var alertmsg = '';
                    435:         switch (current.radiovalue) {
                    436:             case 'krb':
                    437:                 alertmsg = '$alert{'krb'}';
                    438:                 break;
                    439:             default:
                    440:                 alertmsg = '';
                    441:         }
                    442:         if (alertmsg != '') {
                    443:             alert(alertmsg);
                    444:             return;
                    445:         }
                    446:     }
                    447: END
                    448:     } else {
                    449:         $auth_checks .= (<<END);
                    450:     foundatype=1;
                    451:     if (current.argfield == null || current.argfield == '') {
                    452:         var alertmsg = '';
1.38      raeburn   453:         switch (current.radiovalue) {
1.1       raeburn   454:             case 'krb':
                    455:                 alertmsg = '$alert{'krb'}';
                    456:                 break;
                    457:             case 'loc':
                    458:             case 'fsys':
                    459:                 alertmsg = '$alert{'ipass'}';
                    460:                 break;
                    461:             case 'fsys':
                    462:                 alertmsg = '';
                    463:                 break;
                    464:             default:
                    465:                 alertmsg = '';
                    466:         }
                    467:         if (alertmsg != '') {
                    468:             alert(alertmsg);
                    469:             return;
                    470:         }
                    471:     }
                    472: END
                    473:     }
                    474:     my $section_checks;
                    475:     my $optional_checks = '';
                    476:     if ( ($mode eq 'createcourse') || ($mode eq 'modifycourse') ) {
                    477:         $optional_checks = (<<END);
                    478:     vf.submit();
                    479: }
                    480: END
                    481:     } else {
                    482:         $section_checks = &section_check_js();
                    483:         $optional_checks = (<<END);
                    484:     var message='';
                    485:     if (foundname==0) {
                    486:         message='$alert{'name'}';
                    487:     }
                    488:     if (foundid==0) {
                    489:         if (message!='') {
                    490:             message+='\\n';
                    491:         }
                    492:         message+='$alert{'snum'}';
                    493:     }
                    494:     if (foundsec==0) {
                    495:         if (message!='') {
                    496:             message+='\\n';
                    497:         }
                    498:     }
                    499:     if (foundemail==0) {
                    500:         if (message!='') {
                    501:             message+='\\n';
                    502:         }
                    503:         message+='$alert{'email'}';
                    504:     }
                    505:     if (message!='') {
                    506:         message+= '\\n$alert{'continue'}';
                    507:         if (confirm(message)) {
                    508:             vf.state.value='enrolling';
1.22      raeburn   509:             $finish
1.1       raeburn   510:         }
                    511:     } else {
                    512:         vf.state.value='enrolling';
1.22      raeburn   513:         $finish
1.1       raeburn   514:     }
                    515: }
                    516: END
                    517:     }
1.37      raeburn   518:     my $result = $function_name.$auth_checks.$optional_checks."\n".
                    519:                  $section_checks.$authheader;
1.1       raeburn   520:     return $result;
                    521: }
                    522: ###############################################################
                    523: ###############################################################
                    524: sub upload_manager_javascript_forward_associate {
                    525:     return(<<ENDPICK);
                    526: function verify(vf,sec_caller) {
                    527:     var founduname=0;
                    528:     var foundpwd=0;
                    529:     var foundname=0;
                    530:     var foundid=0;
                    531:     var foundsec=0;
                    532:     var foundemail=0;
                    533:     var foundrole=0;
                    534:     var tw;
                    535:     for (i=0;i<=vf.nfields.value;i++) {
                    536:         tw=eval('vf.f'+i+'.selectedIndex');
                    537:         if (tw==1) { founduname=1; }
                    538:         if ((tw>=2) && (tw<=6)) { foundname=1; }
                    539:         if (tw==7) { foundid=1; }
                    540:         if (tw==8) { foundsec=1; }
                    541:         if (tw==9) { foundpwd=1; }
                    542:         if (tw==10) { foundemail=1; }
                    543:         if (tw==11) { foundrole=1; }
                    544:     }
                    545:     verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec,foundemail,foundrole);
                    546: }
                    547: 
                    548: //
                    549: // vf = this.form
                    550: // tf = column number
                    551: //
                    552: // values of nw
                    553: //
                    554: // 0 = none
                    555: // 1 = username
                    556: // 2 = names (lastname, firstnames)
                    557: // 3 = fname (firstname)
                    558: // 4 = mname (middlename)
                    559: // 5 = lname (lastname)
                    560: // 6 = gen   (generation)
                    561: // 7 = id
                    562: // 8 = section
                    563: // 9 = ipwd  (password)
                    564: // 10 = email address
                    565: // 11 = role
                    566: 
                    567: function flip(vf,tf) {
                    568:    var nw=eval('vf.f'+tf+'.selectedIndex');
                    569:    var i;
                    570:    // make sure no other columns are labeled the same as this one
                    571:    for (i=0;i<=vf.nfields.value;i++) {
                    572:       if ((i!=tf) && (eval('vf.f'+i+'.selectedIndex')==nw)) {
                    573:           eval('vf.f'+i+'.selectedIndex=0;')
                    574:       }
                    575:    }
                    576:    // If we set this to 'lastname, firstnames', clear out all the ones
                    577:    // set to 'fname','mname','lname','gen' (3,4,5,6) currently.
                    578:    if (nw==2) {
                    579:       for (i=0;i<=vf.nfields.value;i++) {
                    580:          if ((eval('vf.f'+i+'.selectedIndex')>=3) &&
                    581:              (eval('vf.f'+i+'.selectedIndex')<=6)) {
                    582:              eval('vf.f'+i+'.selectedIndex=0;')
                    583:          }
                    584:       }
                    585:    }
                    586:    // If we set this to one of 'fname','mname','lname','gen' (3,4,5,6),
                    587:    // clear out any that are set to 'lastname, firstnames' (2)
                    588:    if ((nw>=3) && (nw<=6)) {
                    589:       for (i=0;i<=vf.nfields.value;i++) {
                    590:          if (eval('vf.f'+i+'.selectedIndex')==2) {
                    591:              eval('vf.f'+i+'.selectedIndex=0;')
                    592:          }
                    593:       }
                    594:    }
                    595:    // If we set the password, make the password form below correspond to
                    596:    // the new value.
                    597:    if (nw==9) {
                    598:        changed_radio('int',document.studentform);
                    599:        set_auth_radio_buttons('int',document.studentform);
                    600:        vf.intarg.value='';
                    601:        vf.krbarg.value='';
                    602:        vf.locarg.value='';
                    603:    }
                    604: }
                    605: 
                    606: function clearpwd(vf) {
                    607:     var i;
                    608:     for (i=0;i<=vf.nfields.value;i++) {
                    609:         if (eval('vf.f'+i+'.selectedIndex')==9) {
                    610:             eval('vf.f'+i+'.selectedIndex=0;')
                    611:         }
                    612:     }
                    613: }
                    614: 
                    615: ENDPICK
                    616: }
                    617: 
                    618: ###############################################################
                    619: ###############################################################
                    620: sub upload_manager_javascript_reverse_associate {
                    621:     return(<<ENDPICK);
                    622: function verify(vf,sec_caller) {
                    623:     var founduname=0;
                    624:     var foundpwd=0;
                    625:     var foundname=0;
                    626:     var foundid=0;
                    627:     var foundsec=0;
                    628:     var foundrole=0;
                    629:     var tw;
                    630:     for (i=0;i<=vf.nfields.value;i++) {
                    631:         tw=eval('vf.f'+i+'.selectedIndex');
                    632:         if (i==0 && tw!=0) { founduname=1; }
                    633:         if (((i>=1) && (i<=5)) && tw!=0 ) { foundname=1; }
                    634:         if (i==6 && tw!=0) { foundid=1; }
                    635:         if (i==7 && tw!=0) { foundsec=1; }
                    636:         if (i==8 && tw!=0) { foundpwd=1; }
                    637:         if (i==9 && tw!=0) { foundrole=1; }
                    638:     }
                    639:     verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec,foundrole);
                    640: }
                    641: 
                    642: function flip(vf,tf) {
                    643:    var nw=eval('vf.f'+tf+'.selectedIndex');
                    644:    var i;
                    645:    // picked the all one name field, reset the other name ones to blank
                    646:    if (tf==1 && nw!=0) {
                    647:       for (i=2;i<=5;i++) {
                    648:          eval('vf.f'+i+'.selectedIndex=0;')
                    649:       }
                    650:    }
                    651:    //picked one of the piecewise name fields, reset the all in
                    652:    //one field to blank
                    653:    if ((tf>=2) && (tf<=5) && (nw!=0)) {
                    654:       eval('vf.f1.selectedIndex=0;')
                    655:    }
                    656:    // intial password specified, pick internal authentication
                    657:    if (tf==8 && nw!=0) {
                    658:        changed_radio('int',document.studentform);
                    659:        set_auth_radio_buttons('int',document.studentform);
                    660:        vf.krbarg.value='';
                    661:        vf.intarg.value='';
                    662:        vf.locarg.value='';
                    663:    }
                    664: }
                    665: 
                    666: function clearpwd(vf) {
                    667:     var i;
                    668:     if (eval('vf.f8.selectedIndex')!=0) {
                    669:         eval('vf.f8.selectedIndex=0;')
                    670:     }
                    671: }
                    672: ENDPICK
                    673: }
                    674: 
                    675: ###############################################################
                    676: ###############################################################
                    677: sub print_upload_manager_footer {
1.22      raeburn   678:     my ($r,$i,$keyfields,$defdom,$today,$halfyear,$context,$permission) = @_;
                    679:     my $form = 'document.studentform';
                    680:     my $formname = 'studentform';
1.1       raeburn   681:     my ($krbdef,$krbdefdom) =
                    682:         &Apache::loncommon::get_kerberos_defaults($defdom);
1.22      raeburn   683:     my %param = ( formname => $form,
1.1       raeburn   684:                   kerb_def_dom => $krbdefdom,
                    685:                   kerb_def_auth => $krbdef
                    686:                   );
                    687:     if (exists($env{'form.ipwd_choice'}) &&
                    688:         defined($env{'form.ipwd_choice'}) &&
                    689:         $env{'form.ipwd_choice'} ne '') {
                    690:         $param{'curr_authtype'} = 'int';
                    691:     }
                    692:     my $krbform = &Apache::loncommon::authform_kerberos(%param);
                    693:     my $intform = &Apache::loncommon::authform_internal(%param);
                    694:     my $locform = &Apache::loncommon::authform_local(%param);
1.22      raeburn   695:     my $date_table = &date_setting_table(undef,undef,$context,undef,
                    696:                                          $formname,$permission);
1.1       raeburn   697:     my $Str = "\n".'<div class="LC_left_float">';
                    698:     $Str .= &hidden_input('nfields',$i);
                    699:     $Str .= &hidden_input('keyfields',$keyfields);
                    700:     $Str .= "<h3>".&mt('Login Type')."</h3>\n";
                    701:     if ($context eq 'domain') {
                    702:         $Str .= '<p>'.&mt('Change authentication for existing users to these settings?').'&nbsp;<span class="LC_nobreak"><label><input type="radio" name="changeauth" value="No" checked="checked" />'.&mt('No').'</label>&nbsp;&nbsp;<label><input type="radio" name="changeauth" value="Yes" />'.&mt('Yes').'</label></span></p>'; 
                    703:     } else {
                    704:         $Str .= "<p>\n".
                    705:             &mt('Note: this will not take effect if the user already exists').
                    706:             &Apache::loncommon::help_open_topic('Auth_Options').
                    707:             "</p>\n";
                    708:     }
                    709:     $Str .= &set_login($defdom,$krbform,$intform,$locform);
                    710:     my ($home_server_pick,$numlib) =
                    711:         &Apache::loncommon::home_server_form_item($defdom,'lcserver',
                    712:                                                   'default','hide');
                    713:     if ($numlib > 1) {
                    714:         $Str .= '<h3>'.&mt('LON-CAPA Home Server for New Users')."</h3>\n".
                    715:                 &mt('LON-CAPA domain: [_1] with home server: [_2]',$defdom,
                    716:                 $home_server_pick).'<br />';
                    717:     } else {
                    718:         $Str .= $home_server_pick;
                    719:     }
                    720:     $Str .= '<h3>'.&mt('Starting and Ending Dates').
                    721:             "</h3>\n";
                    722:     $Str .= "<p>\n".$date_table."</p>\n";
                    723:     if ($context eq 'domain') {
                    724:         $Str .= '<h3>'.&mt('Settings for assigning roles:').'</h3>'."\n".
                    725:                 &mt('Pick the action to take on roles for these users:').'<br /><span class="LC_nobreak"><label><input type="radio" name="roleaction" value="norole" checked="checked" />&nbsp;'.&mt('No role changes').'</label>&nbsp;&nbsp;&nbsp;<label><input type="radio" name="roleaction" value="domain" />&nbsp;'.&mt('Add a domain role').'</label>&nbsp;&nbsp;&nbsp;<label><input type="radio" name="roleaction" value="course" />&nbsp;'.&mt('Add a course role').'</label></span>';
                    726:     }
1.13      raeburn   727:     if ($context eq 'author') {
1.1       raeburn   728:         $Str .= '<h3>'.&mt('Default role')."</h3>\n".
1.25      raeburn   729:                 &mt('Choose the role to assign to users without a value specified in the uploaded file');
1.1       raeburn   730:     } elsif ($context eq 'course') {
                    731:         $Str .= '<h3>'.&mt('Default role and section')."</h3>\n".
1.25      raeburn   732:                 &mt('Choose the role and/or section(s) to assign to users without values specified in the uploaded file');
1.1       raeburn   733:     } else {
1.25      raeburn   734:         $Str .= '<br /><br /><b>'.&mt('Default role and/or section(s)')."</b><br />\n".
                    735:                 &mt('Role and/or section(s) for users without values specified in the uploaded file.');
1.1       raeburn   736:     }
1.22      raeburn   737:     $Str .= '<br />';
                    738:     if (($context eq 'domain') || ($context eq 'author')) {
                    739:         my ($options,$cb_script,$coursepick) = &default_role_selector($context,1);
                    740:         if ($context eq 'domain') {
                    741:             $Str .= '<span class="LC_role_level">'.&mt('Domain Level').'</span><br />'.$options.'<br /><br /><span class="LC_role_level">'.&mt('Course Level').'</span><br />'.$cb_script.$coursepick;
                    742:         } elsif ($context eq 'author') {
                    743:             $Str .= $options;
                    744:         }
1.1       raeburn   745:     } else {
1.22      raeburn   746:         my ($cnum,$cdom) = &get_course_identity();
                    747:         my $rowtitle = &mt('section');
                    748:         my $secbox = &section_picker($cdom,$cnum,'Any',$rowtitle,
                    749:                                      $permission,$context,'upload');
                    750:         $Str .= $secbox."<h3>".&mt('Full Update')."</h3>\n".
                    751:                 '<p><label><input type="checkbox" name="fullup" value="yes">'.
1.36      raeburn   752:                 ' '.&mt('Display students with current/future access who are not in the uploaded file.').'</label><br />'.&mt('Students selected from this list can be dropped.').'</p>'."\n";
1.1       raeburn   753:     }
1.5       raeburn   754:     if ($context eq 'course' || $context eq 'domain') {
                    755:         $Str .= &forceid_change($context);
                    756:     }
1.1       raeburn   757:     $Str .= '</div><div class="LC_clear_float_footer"><br /><input type="button"'.
                    758:               'onClick="javascript:verify(this.form,this.form.csec)" '.
                    759:         'value="Update Users" />'."<br />\n";
                    760:     if ($context eq 'course') {
                    761:         $Str .= &mt('Note: for large courses, this operation may be time '.
                    762:                     'consuming');
                    763:     }
                    764:     $Str .= '</div>';
                    765:     $r->print($Str);
                    766:     return;
                    767: }
                    768: 
1.5       raeburn   769: sub forceid_change {
                    770:     my ($context) = @_;
                    771:     my $output = 
                    772:         "<h3>".&mt('ID/Student Number')."</h3>\n".
                    773:         "<p>\n".'<label><input type="checkbox" name="forceid" value="yes">'.
                    774:         &mt('Disable ID/Student Number Safeguard and Force Change '.
                    775:         'of Conflicting IDs').'</label><br />'."\n".
1.25      raeburn   776:         &mt('(only do if you know what you are doing.)')."\n";
1.5       raeburn   777:     if ($context eq 'domain') {
1.25      raeburn   778:         $output .= '<br /><label><input type="checkbox" name="recurseid"'.
1.5       raeburn   779:                    ' value="yes">'. 
1.13      raeburn   780:   &mt('Update ID/Student Number in courses in which user is Active/Future student,<br />(if forcing change).').
1.25      raeburn   781:                    '</label>'."\n";
1.5       raeburn   782:     }
1.25      raeburn   783:     $output .= '</p>';
1.5       raeburn   784:     return $output;
                    785: }
                    786: 
1.1       raeburn   787: ###############################################################
                    788: ###############################################################
                    789: sub print_upload_manager_form {
1.21      raeburn   790:     my ($r,$context,$permission) = @_;
1.1       raeburn   791:     my $firstLine;
                    792:     my $datatoken;
                    793:     if (!$env{'form.datatoken'}) {
                    794:         $datatoken=&Apache::loncommon::upfile_store($r);
                    795:     } else {
                    796:         $datatoken=$env{'form.datatoken'};
                    797:         &Apache::loncommon::load_tmp_file($r);
                    798:     }
                    799:     my @records=&Apache::loncommon::upfile_record_sep();
                    800:     if($env{'form.noFirstLine'}){
                    801:         $firstLine=shift(@records);
                    802:     }
                    803:     my $total=$#records;
                    804:     my $distotal=$total+1;
                    805:     my $today=time;
                    806:     my $halfyear=$today+15552000;
                    807:     #
                    808:     # Restore memorized settings
                    809:     my $col_setting_names =  { 'username_choice' => 'scalar', # column settings
                    810:                                'names_choice' => 'scalar',
                    811:                                'fname_choice' => 'scalar',
                    812:                                'mname_choice' => 'scalar',
                    813:                                'lname_choice' => 'scalar',
                    814:                                'gen_choice' => 'scalar',
                    815:                                'id_choice' => 'scalar',
                    816:                                'sec_choice' => 'scalar',
                    817:                                'ipwd_choice' => 'scalar',
                    818:                                'email_choice' => 'scalar',
                    819:                                'role_choice' => 'scalar',
                    820:                              };
                    821:     my $defdom = $env{'request.role.domain'};
                    822:     if ($context eq 'course') {
                    823:         &Apache::loncommon::restore_course_settings('enrollment_upload',
                    824:                                                     $col_setting_names);
                    825:     } else {
                    826:         &Apache::loncommon::restore_settings($context,'user_upload',
                    827:                                              $col_setting_names);
                    828:     }
                    829:     #
                    830:     # Determine kerberos parameters as appropriate
                    831:     my ($krbdef,$krbdefdom) =
                    832:         &Apache::loncommon::get_kerberos_defaults($defdom);
                    833:     #
1.22      raeburn   834:     &print_upload_manager_header($r,$datatoken,$distotal,$krbdefdom,$context,
                    835:                                  $permission);
1.1       raeburn   836:     my $i;
                    837:     my $keyfields;
                    838:     if ($total>=0) {
                    839:         my @field=
                    840:             (['username',&mt('Username'),     $env{'form.username_choice'}],
                    841:              ['names',&mt('Last Name, First Names'),$env{'form.names_choice'}],
                    842:              ['fname',&mt('First Name'),      $env{'form.fname_choice'}],
                    843:              ['mname',&mt('Middle Names/Initials'),$env{'form.mname_choice'}],
                    844:              ['lname',&mt('Last Name'),       $env{'form.lname_choice'}],
                    845:              ['gen',  &mt('Generation'),      $env{'form.gen_choice'}],
                    846:              ['id',   &mt('ID/Student Number'),$env{'form.id_choice'}],
                    847:              ['sec',  &mt('Section'),          $env{'form.sec_choice'}],
                    848:              ['ipwd', &mt('Initial Password'),$env{'form.ipwd_choice'}],
                    849:              ['email',&mt('E-mail Address'),   $env{'form.email_choice'}],
                    850:              ['role',&mt('Role'),             $env{'form.role_choice'}]);
                    851:         if ($env{'form.upfile_associate'} eq 'reverse') {
                    852:             &Apache::loncommon::csv_print_samples($r,\@records);
                    853:             $i=&Apache::loncommon::csv_print_select_table($r,\@records,
                    854:                                                           \@field);
                    855:             foreach (@field) {
                    856:                 $keyfields.=$_->[0].',';
                    857:             }
                    858:             chop($keyfields);
                    859:         } else {
                    860:             unshift(@field,['none','']);
                    861:             $i=&Apache::loncommon::csv_samples_select_table($r,\@records,
                    862:                                                             \@field);
                    863:             my %sone=&Apache::loncommon::record_sep($records[0]);
                    864:             $keyfields=join(',',sort(keys(%sone)));
                    865:         }
                    866:     }
                    867:     $r->print('</div>');
                    868:     &print_upload_manager_footer($r,$i,$keyfields,$defdom,$today,$halfyear,
1.22      raeburn   869:                                  $context,$permission);
1.1       raeburn   870: }
                    871: 
                    872: sub setup_date_selectors {
1.22      raeburn   873:     my ($starttime,$endtime,$mode,$nolink,$formname) = @_;
                    874:     if ($formname eq '') {
                    875:         $formname = 'studentform';
                    876:     }
1.1       raeburn   877:     if (! defined($starttime)) {
                    878:         $starttime = time;
                    879:         unless ($mode eq 'create_enrolldates' || $mode eq 'create_defaultdates') {
                    880:             if (exists($env{'course.'.$env{'request.course.id'}.
                    881:                             '.default_enrollment_start_date'})) {
                    882:                 $starttime = $env{'course.'.$env{'request.course.id'}.
                    883:                                   '.default_enrollment_start_date'};
                    884:             }
                    885:         }
                    886:     }
                    887:     if (! defined($endtime)) {
                    888:         $endtime = time+(6*30*24*60*60); # 6 months from now, approx
                    889:         unless ($mode eq 'createcourse') {
                    890:             if (exists($env{'course.'.$env{'request.course.id'}.
                    891:                             '.default_enrollment_end_date'})) {
                    892:                 $endtime = $env{'course.'.$env{'request.course.id'}.
                    893:                                 '.default_enrollment_end_date'};
                    894:             }
                    895:         }
                    896:     }
1.11      raeburn   897: 
                    898:     my $startdateform = 
1.22      raeburn   899:         &Apache::lonhtmlcommon::date_setter($formname,'startdate',$starttime,
1.11      raeburn   900:             undef,undef,undef,undef,undef,undef,undef,$nolink);
                    901: 
                    902:     my $enddateform = 
1.22      raeburn   903:         &Apache::lonhtmlcommon::date_setter($formname,'enddate',$endtime,
1.11      raeburn   904:             undef,undef,undef,undef,undef,undef,undef,$nolink);
                    905: 
1.1       raeburn   906:     if ($mode eq 'create_enrolldates') {
                    907:         $startdateform = &Apache::lonhtmlcommon::date_setter('ccrs',
                    908:                                                             'startenroll',
                    909:                                                             $starttime);
                    910:         $enddateform = &Apache::lonhtmlcommon::date_setter('ccrs',
                    911:                                                           'endenroll',
                    912:                                                           $endtime);
                    913:     }
                    914:     if ($mode eq 'create_defaultdates') {
                    915:         $startdateform = &Apache::lonhtmlcommon::date_setter('ccrs',
                    916:                                                             'startaccess',
                    917:                                                             $starttime);
                    918:         $enddateform = &Apache::lonhtmlcommon::date_setter('ccrs',
                    919:                                                           'endaccess',
                    920:                                                           $endtime);
                    921:     }
                    922:     return ($startdateform,$enddateform);
                    923: }
                    924: 
                    925: 
                    926: sub get_dates_from_form {
                    927:     my $startdate = &Apache::lonhtmlcommon::get_date_from_form('startdate');
                    928:     my $enddate   = &Apache::lonhtmlcommon::get_date_from_form('enddate');
                    929:     if ($env{'form.no_end_date'}) {
                    930:         $enddate = 0;
                    931:     }
                    932:     return ($startdate,$enddate);
                    933: }
                    934: 
                    935: sub date_setting_table {
1.22      raeburn   936:     my ($starttime,$endtime,$mode,$bulkaction,$formname,$permission) = @_;
1.11      raeburn   937:     my $nolink;
                    938:     if ($bulkaction) {
                    939:         $nolink = 1;
                    940:     }
                    941:     my ($startform,$endform) = 
1.22      raeburn   942:         &setup_date_selectors($starttime,$endtime,$mode,$nolink,$formname);
1.1       raeburn   943:     my $dateDefault;
                    944:     if ($mode eq 'create_enrolldates' || $mode eq 'create_defaultdates') {
                    945:         $dateDefault = '&nbsp;';
1.13      raeburn   946:     } elsif ($mode ne 'author' && $mode ne 'domain') {
1.11      raeburn   947:         if (($bulkaction eq 'reenable') || 
                    948:             ($bulkaction eq 'activate') || 
1.22      raeburn   949:             ($bulkaction eq 'chgdates') ||
                    950:             ($env{'form.action'} eq 'upload')) {
                    951:             if ($env{'request.course.sec'} eq '') {
                    952:                 $dateDefault = '<span class="LC_nobreak">'.
1.25      raeburn   953:                     '<label><input type="checkbox" name="makedatesdefault" value="1" /> '.
1.22      raeburn   954:                     &mt('make these dates the default access dates for future student enrollment').
                    955:                     '</label></span>';
                    956:             }
1.11      raeburn   957:         }
1.1       raeburn   958:     }
1.11      raeburn   959:     my $perpetual = '<span class="LC_nobreak"><label><input type="checkbox" name="no_end_date"';
1.1       raeburn   960:     if (defined($endtime) && $endtime == 0) {
                    961:         $perpetual .= ' checked';
                    962:     }
1.11      raeburn   963:     $perpetual.= ' /> '.&mt('no ending date').'</label></span>';
1.1       raeburn   964:     if ($mode eq 'create_enrolldates') {
                    965:         $perpetual = '&nbsp;';
                    966:     }
1.11      raeburn   967:     my $result = &Apache::lonhtmlcommon::start_pick_box()."\n";
                    968:     $result .= &Apache::lonhtmlcommon::row_title(&mt('Starting Date'),
                    969:                                                      'LC_oddrow_value')."\n".
                    970:                $startform."\n".
                    971:                &Apache::lonhtmlcommon::row_closure(1).
                    972:                &Apache::lonhtmlcommon::row_title(&mt('Ending Date'), 
                    973:                                                      'LC_oddrow_value')."\n".
                    974:                $endform.'&nbsp;'.$perpetual.
                    975:                &Apache::lonhtmlcommon::row_closure(1).
1.22      raeburn   976:                &Apache::lonhtmlcommon::end_pick_box();
1.1       raeburn   977:     if ($dateDefault) {
                    978:         $result .=  $dateDefault.'<br />'."\n";
                    979:     }
                    980:     return $result;
                    981: }
                    982: 
                    983: sub make_dates_default {
                    984:     my ($startdate,$enddate,$context) = @_;
                    985:     my $result = '';
                    986:     if ($context eq 'course') {
1.17      raeburn   987:         my ($cnum,$cdom) = &get_course_identity();
1.1       raeburn   988:         my $put_result = &Apache::lonnet::put('environment',
                    989:                 {'default_enrollment_start_date'=>$startdate,
1.17      raeburn   990:                  'default_enrollment_end_date'  =>$enddate},$cdom,$cnum);
1.1       raeburn   991:         if ($put_result eq 'ok') {
1.25      raeburn   992:             $result .= &mt('Set default start and end access dates for course.').
1.11      raeburn   993:                        '<br />'."\n";
1.1       raeburn   994:             #
                    995:             # Refresh the course environment
                    996:             &Apache::lonnet::coursedescription($env{'request.course.id'},
                    997:                                                {'freshen_cache' => 1});
                    998:         } else {
1.25      raeburn   999:             $result .= &mt('Unable to set default access dates for course.').":".$put_result.
1.1       raeburn  1000:                        '<br />';
                   1001:         }
                   1002:     }
                   1003:     return $result;
                   1004: }
                   1005: 
                   1006: sub default_role_selector {
1.2       raeburn  1007:     my ($context,$checkpriv) = @_;
1.1       raeburn  1008:     my %customroles;
                   1009:     my ($options,$coursepick,$cb_jscript);
1.13      raeburn  1010:     if ($context ne 'author') {
1.1       raeburn  1011:         %customroles = &my_custom_roles();
                   1012:     }
                   1013: 
                   1014:     my %lt=&Apache::lonlocal::texthash(
                   1015:                     'rol'  => "Role",
                   1016:                     'grs'  => "Section",
                   1017:                     'exs'  => "Existing sections",
                   1018:                     'new'  => "New section",
                   1019:                   );
                   1020:     $options = '<select name="defaultrole">'."\n".
                   1021:                ' <option value="">'.&mt('Please select').'</option>'."\n"; 
                   1022:     if ($context eq 'course') {
1.2       raeburn  1023:         $options .= &default_course_roles($context,$checkpriv,%customroles);
1.13      raeburn  1024:     } elsif ($context eq 'author') {
1.2       raeburn  1025:         my @roles = &construction_space_roles($checkpriv);
1.1       raeburn  1026:         foreach my $role (@roles) {
                   1027:            my $plrole=&Apache::lonnet::plaintext($role);
                   1028:            $options .= '  <option value="'.$role.'">'.$plrole.'</option>'."\n";
                   1029:         }
                   1030:     } elsif ($context eq 'domain') {
1.2       raeburn  1031:         my @roles = &domain_roles($checkpriv);
1.1       raeburn  1032:         foreach my $role (@roles) {
                   1033:            my $plrole=&Apache::lonnet::plaintext($role);
                   1034:            $options .= '  <option value="'.$role.'">'.$plrole.'</option>';
                   1035:         }
                   1036:         my $courseform = &Apache::loncommon::selectcourse_link
1.22      raeburn  1037:             ('studentform','dccourse','dcdomain','coursedesc',"$env{'request.role.domain'}",undef,'Course');
1.1       raeburn  1038:         $cb_jscript = 
1.22      raeburn  1039:             &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'},'currsec','studentform');
1.1       raeburn  1040:         $coursepick = &Apache::loncommon::start_data_table().
                   1041:                       &Apache::loncommon::start_data_table_header_row().
                   1042:                       '<th>'.$courseform.'</th><th>'.$lt{'rol'}.'</th>'.
                   1043:                       '<th>'.$lt{'grs'}.'</th>'.
                   1044:                       &Apache::loncommon::end_data_table_header_row().
                   1045:                       &Apache::loncommon::start_data_table_row()."\n".
1.22      raeburn  1046:                       '<td><input type="text" name="coursedesc" value="" onFocus="this.blur();opencrsbrowser('."'studentform','dccourse','dcdomain','coursedesc',''".')" /></td>'."\n".
1.1       raeburn  1047:                       '<td><select name="courserole">'."\n".
1.2       raeburn  1048:                       &default_course_roles($context,$checkpriv,%customroles)."\n".
1.1       raeburn  1049:                       '</select></td><td>'.
                   1050:                       '<table class="LC_createuser">'.
                   1051:                       '<tr class="LC_section_row"><td valign"top">'.
1.22      raeburn  1052:                       $lt{'exs'}.'<br /><select name="currsec">'.
1.1       raeburn  1053:                       ' <option value=""><--'.&mt('Pick course first').
                   1054:                       '</select></td>'.
                   1055:                       '<td>&nbsp;&nbsp;</td>'.
                   1056:                       '<td valign="top">'.$lt{'new'}.'<br />'.
                   1057:                       '<input type="text" name="newsec" value="" size="5" />'.
1.22      raeburn  1058:                       '<input type="hidden" name="groups" value="" />'.
                   1059:                       '<input type="hidden" name="sections" value="" />'.
                   1060:                       '<input type="hidden" name="origdom" value="'.
                   1061:                       $env{'request.role.domain'}.'" />'.
                   1062:                       '<input type="hidden" name="dccourse" value="" />'.
                   1063:                       '<input type="hidden" name="dcdomain" value="" />'.
                   1064:                       '</td></tr></table></td>'.
1.1       raeburn  1065:                       &Apache::loncommon::end_data_table_row().
1.22      raeburn  1066:                       &Apache::loncommon::end_data_table()."\n";
1.1       raeburn  1067:     }
                   1068:     $options .= '</select>';
                   1069:     return ($options,$cb_jscript,$coursepick);
                   1070: }
                   1071: 
                   1072: sub default_course_roles {
1.2       raeburn  1073:     my ($context,$checkpriv,%customroles) = @_;
1.1       raeburn  1074:     my $output;
1.17      raeburn  1075:     my $custom = 1;
                   1076:     my @roles = &course_roles($context,$checkpriv,$custom);
1.1       raeburn  1077:     foreach my $role (@roles) {
1.22      raeburn  1078:         if ($role ne 'cr') {
                   1079:             my $plrole=&Apache::lonnet::plaintext($role);
                   1080:             $output .= '  <option value="'.$role.'">'.$plrole.'</option>';
                   1081:         }
1.1       raeburn  1082:     }
                   1083:     if (keys(%customroles) > 0) {
1.22      raeburn  1084:         if (grep(/^cr$/,@roles)) {
                   1085:             foreach my $cust (sort(keys(%customroles))) {
                   1086:                 my $custrole='cr_'.$env{'user.domain'}.
                   1087:                              '_'.$env{'user.name'}.'_'.$cust;
                   1088:                 $output .= '  <option value="'.$custrole.'">'.$cust.'</option>';
                   1089:             }
1.1       raeburn  1090:         }
                   1091:     }
                   1092:     return $output;
                   1093: }
                   1094: 
                   1095: sub construction_space_roles {
1.2       raeburn  1096:     my ($checkpriv) = @_;
1.17      raeburn  1097:     my @allroles = &roles_by_context('author');
1.1       raeburn  1098:     my @roles;
1.2       raeburn  1099:     if ($checkpriv) {
                   1100:         foreach my $role (@allroles) {
                   1101:             if (&Apache::lonnet::allowed('c'.$role,$env{'user.domain'}.'/'.$env{'user.name'})) { 
                   1102:                 push(@roles,$role); 
                   1103:             }
1.1       raeburn  1104:         }
1.2       raeburn  1105:         return @roles;
                   1106:     } else {
                   1107:         return @allroles;
1.1       raeburn  1108:     }
                   1109: }
                   1110: 
                   1111: sub domain_roles {
1.2       raeburn  1112:     my ($checkpriv) = @_;
1.17      raeburn  1113:     my @allroles = &roles_by_context('domain');
1.1       raeburn  1114:     my @roles;
1.2       raeburn  1115:     if ($checkpriv) {
                   1116:         foreach my $role (@allroles) {
                   1117:             if (&Apache::lonnet::allowed('c'.$role,$env{'request.role.domain'})) {
                   1118:                 push(@roles,$role);
                   1119:             }
1.1       raeburn  1120:         }
1.2       raeburn  1121:         return @roles;
                   1122:     } else {
                   1123:         return @allroles;
1.1       raeburn  1124:     }
                   1125: }
                   1126: 
                   1127: sub course_roles {
1.17      raeburn  1128:     my ($context,$checkpriv,$custom) = @_;
                   1129:     my @allroles = &roles_by_context('course',$custom);
1.1       raeburn  1130:     my @roles;
                   1131:     if ($context eq 'domain') {
                   1132:         @roles = @allroles;
                   1133:     } elsif ($context eq 'course') {
                   1134:         if ($env{'request.course.id'}) {
1.2       raeburn  1135:             if ($checkpriv) { 
                   1136:                 foreach my $role (@allroles) {
                   1137:                     if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'})) {
                   1138:                         push(@roles,$role);
                   1139:                     } else {
1.22      raeburn  1140:                         if ($role ne 'cc' && $env{'request.course.sec'} ne '') {
                   1141:                             if (&Apache::lonnet::allowed('c'.$role,
1.2       raeburn  1142:                                              $env{'request.course.id'}.'/'.
1.22      raeburn  1143:                                              $env{'request.course.sec'})) {
1.2       raeburn  1144:                                 push(@roles,$role);
                   1145:                             }
1.1       raeburn  1146:                         }
                   1147:                     }
                   1148:                 }
1.2       raeburn  1149:             } else {
                   1150:                 @roles = @allroles;
1.1       raeburn  1151:             }
                   1152:         }
                   1153:     }
                   1154:     return @roles;
                   1155: }
                   1156: 
                   1157: sub curr_role_permissions {
1.2       raeburn  1158:     my ($context,$setting,$checkpriv) = @_; 
1.17      raeburn  1159:     my $custom = 1;
1.1       raeburn  1160:     my @roles;
1.13      raeburn  1161:     if ($context eq 'author') {
1.2       raeburn  1162:         @roles = &construction_space_roles($checkpriv);
1.1       raeburn  1163:     } elsif ($context eq 'domain') {
                   1164:         if ($setting eq 'course') {
1.17      raeburn  1165:             @roles = &course_roles($context,$checkpriv,$custom); 
1.1       raeburn  1166:         } else {
1.2       raeburn  1167:             @roles = &domain_roles($checkpriv);
1.1       raeburn  1168:         }
                   1169:     } elsif ($context eq 'course') {
1.17      raeburn  1170:         @roles = &course_roles($context,$checkpriv,$custom);
1.1       raeburn  1171:     }
                   1172:     return @roles;
                   1173: }
                   1174: 
                   1175: # ======================================================= Existing Custom Roles
                   1176: 
                   1177: sub my_custom_roles {
                   1178:     my %returnhash=();
                   1179:     my %rolehash=&Apache::lonnet::dump('roles');
                   1180:     foreach my $key (keys %rolehash) {
                   1181:         if ($key=~/^rolesdef\_(\w+)$/) {
                   1182:             $returnhash{$1}=$1;
                   1183:         }
                   1184:     }
                   1185:     return %returnhash;
                   1186: }
                   1187: 
1.2       raeburn  1188: sub print_userlist {
                   1189:     my ($r,$mode,$permission,$context,$formname,$totcodes,$codetitles,
                   1190:         $idlist,$idlist_titles) = @_;
                   1191:     my $format = $env{'form.output'};
1.1       raeburn  1192:     if (! exists($env{'form.sortby'})) {
                   1193:         $env{'form.sortby'} = 'username';
                   1194:     }
1.2       raeburn  1195:     if ($env{'form.Status'} !~ /^(Any|Expired|Active|Future)$/) {
                   1196:         $env{'form.Status'} = 'Active';
1.1       raeburn  1197:     }
                   1198:     my $status_select = &Apache::lonhtmlcommon::StatusOptions
1.2       raeburn  1199:         ($env{'form.Status'});
1.1       raeburn  1200: 
1.2       raeburn  1201:     if ($env{'form.showrole'} eq '') {
1.13      raeburn  1202:         if ($context eq 'course') {
                   1203:             $env{'form.showrole'} = 'st';
                   1204:         } else {
                   1205:             $env{'form.showrole'} = 'Any';            
                   1206:         }
1.2       raeburn  1207:     }
1.1       raeburn  1208:     if (! defined($env{'form.output'}) ||
                   1209:         $env{'form.output'} !~ /^(csv|excel|html)$/ ) {
                   1210:         $env{'form.output'} = 'html';
                   1211:     }
                   1212: 
1.2       raeburn  1213:     my @statuses;
                   1214:     if ($env{'form.Status'} eq 'Any') {
                   1215:         @statuses = ('previous','active','future');
                   1216:     } elsif ($env{'form.Status'} eq 'Expired') {
                   1217:         @statuses = ('previous');
                   1218:     } elsif ($env{'form.Status'} eq 'Active') {
                   1219:         @statuses = ('active');
                   1220:     } elsif ($env{'form.Status'} eq 'Future') {
                   1221:         @statuses = ('future');
                   1222:     }
1.1       raeburn  1223: 
1.2       raeburn  1224: #    if ($context eq 'course') { 
                   1225: #        $r->print(&display_adv_courseroles());
                   1226: #    }
1.1       raeburn  1227:     #
                   1228:     # Interface output
1.2       raeburn  1229:     $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n".
                   1230:               '<input type="hidden" name="action" value="'.
1.1       raeburn  1231:               $env{'form.action'}.'" />');
                   1232:     $r->print("<p>\n");
                   1233:     if ($env{'form.action'} ne 'modifystudent') {
                   1234:         my %lt=&Apache::lonlocal::texthash('csv' => "CSV",
                   1235:                                            'excel' => "Excel",
                   1236:                                            'html'  => 'HTML');
                   1237:         my $output_selector = '<select size="1" name="output" >';
                   1238:         foreach my $outputformat ('html','csv','excel') {
                   1239:             my $option = '<option value="'.$outputformat.'" ';
                   1240:             if ($outputformat eq $env{'form.output'}) {
                   1241:                 $option .= 'selected ';
                   1242:             }
                   1243:             $option .='>'.$lt{$outputformat}.'</option>';
                   1244:             $output_selector .= "\n".$option;
                   1245:         }
                   1246:         $output_selector .= '</select>';
                   1247:         $r->print('<label>'.&mt('Output Format: [_1]',$output_selector).'</label>'.('&nbsp;'x3));
                   1248:     }
1.2       raeburn  1249:     $r->print('<label>'.&mt('User Status: [_1]',$status_select).'</label>'.('&nbsp;'x3)."\n");
                   1250:     my $roleselected = '';
                   1251:     if ($env{'form.showrole'} eq 'Any') {
                   1252:        $roleselected = ' selected="selected" '; 
                   1253:     }
1.33      raeburn  1254:     my ($role_select,$cnum,$cdom);
1.2       raeburn  1255:     if ($context eq 'domain') {
                   1256:         $role_select = &domain_roles_select();
                   1257:         $r->print('<label>'.&mt('Role Type: [_1]',$role_select).'</label>');
                   1258:     } else {
                   1259:         $role_select = '<select name="showrole">'."\n".
                   1260:                        '<option value="Any" '.$roleselected.'>'.
                   1261:                        &mt('Any role').'</option>';
                   1262:         my @poss_roles = &curr_role_permissions($context);
                   1263:         foreach my $role (@poss_roles) {
                   1264:             $roleselected = '';
                   1265:             if ($role eq $env{'form.showrole'}) {
                   1266:                 $roleselected = ' selected="selected" ';
                   1267:             }
1.22      raeburn  1268:             my $plrole;
                   1269:             if ($role eq 'cr') {
                   1270:                 $plrole = &mt('Custom role');
                   1271:             } else {
                   1272:                 $plrole=&Apache::lonnet::plaintext($role);
                   1273:             }
1.2       raeburn  1274:             $role_select .= '<option value="'.$role.'"'.$roleselected.'>'.$plrole.'</option>';
                   1275:         }
1.22      raeburn  1276:         $role_select .= '</select>';
1.2       raeburn  1277:         $r->print('<label>'.&mt('Role: [_1]',$role_select).'</label>');
1.33      raeburn  1278:         if ($context eq 'course') {
                   1279:             ($cnum,$cdom) = &get_course_identity();
                   1280:             $r->print(&section_group_filter($cnum,$cdom));
                   1281:         }
1.2       raeburn  1282:     }
                   1283:     if (!(($context eq 'domain') && ($env{'form.roletype'} eq 'course'))) {
1.25      raeburn  1284:         $r->print('&nbsp;'.&list_submit_button(&mt('Update Display')).
                   1285:                   "\n</p>\n");
1.2       raeburn  1286:     }
                   1287:     my ($indexhash,$keylist) = &make_keylist_array();
                   1288:     my (%userlist,%userinfo);
1.3       raeburn  1289:     if ($context eq 'domain' && $env{'form.roletype'} eq 'course') {
                   1290:         my $courseform =
                   1291:             &Apache::lonhtmlcommon::course_selection($formname,$totcodes,
                   1292:                                          $codetitles,$idlist,$idlist_titles);
                   1293:         $r->print('<p>'.&Apache::lonhtmlcommon::start_pick_box()."\n".
                   1294:                   &Apache::lonhtmlcommon::start_pick_box()."\n".
                   1295:                   &Apache::lonhtmlcommon::row_title(&mt('Select Course(s)'),
                   1296:                                                     'LC_oddrow_value')."\n".
                   1297:                   $courseform."\n".
                   1298:                   &Apache::lonhtmlcommon::row_closure(1).
                   1299:                   &Apache::lonhtmlcommon::end_pick_box().'</p>'.
                   1300:                   '<p>'.&list_submit_button(&mt('Update Display')).
1.34      raeburn  1301:                   "\n".'</p><span class="LC_warning">'.&mt('Warning: data retrieval for multiple courses can take considerable time, as this operation is not currently optimized.').'</span>'."\n");
1.11      raeburn  1302:         if ($env{'form.coursepick'}) {
                   1303:             $r->print('<hr />'.&mt('Searching').' ...<br />&nbsp;<br />');
                   1304:         }
                   1305:     } else {
                   1306:         $r->print('<hr />'.&mt('Searching').' ...<br />&nbsp;<br />');
1.3       raeburn  1307:     }
                   1308:     $r->rflush();
1.1       raeburn  1309:     if ($context eq 'course') {
1.46      raeburn  1310:         if (($env{'form.showrole'} eq 'st') || ($env{'form.showrole'} eq 'Any')) { 
1.45      raeburn  1311:             my $classlist = &Apache::loncoursedata::get_classlist();
                   1312:             %userlist = %{$classlist};
                   1313:         }
1.43      raeburn  1314:         if ($env{'form.showrole'} ne 'st') {
                   1315:             my $showroles;
                   1316:             if ($env{'form.showrole'} ne 'Any') {
                   1317:                 $showroles = [$env{'form.showrole'}];
1.3       raeburn  1318:             } else {
1.43      raeburn  1319:                 $showroles = undef;
1.1       raeburn  1320:             }
1.43      raeburn  1321:             my $withsec = 1;
                   1322:             my $hidepriv = 1;
                   1323:             my %advrolehash = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,
                   1324:                               \@statuses,$showroles,undef,$withsec,$hidepriv);
                   1325:             &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo,
                   1326:                              \%advrolehash,$permission);
1.1       raeburn  1327:         }
1.2       raeburn  1328:     } else {
                   1329:         my (%cstr_roles,%dom_roles);
1.13      raeburn  1330:         if ($context eq 'author') {
1.2       raeburn  1331:             # List co-authors and assistant co-authors
1.17      raeburn  1332:             my @possroles = &roles_by_context($context);
1.2       raeburn  1333:             %cstr_roles = &Apache::lonnet::get_my_roles(undef,undef,undef,
                   1334:                                               \@statuses,\@possroles);
                   1335:             &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo,
1.11      raeburn  1336:                              \%cstr_roles,$permission);
1.2       raeburn  1337:         } elsif ($context eq 'domain') {
                   1338:             if ($env{'form.roletype'} eq 'domain') {
                   1339:                 %dom_roles = &Apache::lonnet::get_domain_roles($env{'request.role.domain'});
                   1340:                 foreach my $key (keys(%dom_roles)) {
                   1341:                     if (ref($dom_roles{$key}) eq 'HASH') {
                   1342:                         &gather_userinfo($context,$format,\%userlist,$indexhash,
1.11      raeburn  1343:                                          \%userinfo,$dom_roles{$key},$permission);
1.2       raeburn  1344:                     }
                   1345:                 }
1.13      raeburn  1346:             } elsif ($env{'form.roletype'} eq 'author') {
1.2       raeburn  1347:                 my %dom_roles = &Apache::lonnet::get_domain_roles($env{'request.role.domain'},['au']);
                   1348:                 my %coauthors;
                   1349:                 foreach my $key (keys(%dom_roles)) {
                   1350:                     if (ref($dom_roles{$key}) eq 'HASH') {
                   1351:                         if ($env{'form.showrole'} eq 'au') {
                   1352:                             &gather_userinfo($context,$format,\%userlist,$indexhash,
1.11      raeburn  1353:                                              \%userinfo,$dom_roles{$key},$permission);
1.2       raeburn  1354:                         } else {
                   1355:                             my @possroles;
                   1356:                             if ($env{'form.showrole'} eq 'Any') {
1.22      raeburn  1357:                                 @possroles = &roles_by_context('author');
1.2       raeburn  1358:                             } else {
                   1359:                                 @possroles = ($env{'form.showrole'}); 
                   1360:                             }
                   1361:                             foreach my $author (sort(keys(%{$dom_roles{$key}}))) {
1.22      raeburn  1362:                                 my ($role,$authorname,$authordom) = split(/:/,$author,-1);
1.2       raeburn  1363:                                 my $extent = '/'.$authordom.'/'.$authorname;
                   1364:                                 %{$coauthors{$extent}} =
                   1365:                                     &Apache::lonnet::get_my_roles($authorname,
                   1366:                                        $authordom,undef,\@statuses,\@possroles);
                   1367:                             }
                   1368:                             &gather_userinfo($context,$format,\%userlist,
1.11      raeburn  1369:                                      $indexhash,\%userinfo,\%coauthors,$permission);
1.2       raeburn  1370:                         }
                   1371:                     }
                   1372:                 }
                   1373:             } elsif ($env{'form.roletype'} eq 'course') {
                   1374:                 if ($env{'form.coursepick'}) {
                   1375:                     my %courses = &process_coursepick();
1.39      raeburn  1376:                     my %allusers;
                   1377:                     my $hidepriv = 1;
1.2       raeburn  1378:                     foreach my $cid (keys(%courses)) {
1.17      raeburn  1379:                         my ($cnum,$cdom,$cdesc) = &get_course_identity($cid);
1.11      raeburn  1380:                         next if ($cnum eq '' || $cdom eq '');
1.17      raeburn  1381:                         my $custom = 1;
1.2       raeburn  1382:                         my (@roles,@sections,%access,%users,%userdata,
1.6       albertel 1383:                             %statushash);
1.2       raeburn  1384:                         if ($env{'form.showrole'} eq 'Any') {
1.17      raeburn  1385:                             @roles = &course_roles($context,undef,$custom);
1.2       raeburn  1386:                         } else {
                   1387:                             @roles = ($env{'form.showrole'});
                   1388:                         }
                   1389:                         foreach my $role (@roles) {
                   1390:                             %{$users{$role}} = ();
                   1391:                         }
                   1392:                         foreach my $type (@statuses) {
                   1393:                             $access{$type} = $type;
                   1394:                         }
1.39      raeburn  1395:                         &Apache::loncommon::get_course_users($cdom,$cnum,\%access,\@roles,\@sections,\%users,\%userdata,\%statushash,$hidepriv);
1.2       raeburn  1396:                         foreach my $user (keys(%userdata)) {
                   1397:                             next if (ref($userinfo{$user}) eq 'HASH');
                   1398:                             foreach my $item ('fullname','id') {
                   1399:                                 $userinfo{$user}{$item} = $userdata{$user}[$indexhash->{$item}];
                   1400:                             }
                   1401:                         }
                   1402:                         foreach my $role (keys(%users)) {
                   1403:                             foreach my $user (keys(%{$users{$role}})) {
                   1404:                                 my $uniqid = $user.':'.$role;
                   1405:                                 $allusers{$uniqid}{$cid} = { desc => $cdesc,
                   1406:                                                              secs  => $statushash{$user}{$role},
                   1407:                                                            };
                   1408:                             }
                   1409:                         }
                   1410:                     }
                   1411:                     &gather_userinfo($context,$format,\%userlist,$indexhash,
1.11      raeburn  1412:                                      \%userinfo,\%allusers,$permission);
1.2       raeburn  1413:                 } else {
1.10      raeburn  1414:                     $r->print('<input type="hidden" name="phase" value="'.
                   1415:                               $env{'form.phase'}.'" /></form>');
1.2       raeburn  1416:                     return;
                   1417:                 }
1.1       raeburn  1418:             }
                   1419:         }
1.3       raeburn  1420:     }
                   1421:     if (keys(%userlist) == 0) {
1.13      raeburn  1422:         if ($context eq 'author') {
1.3       raeburn  1423:             $r->print(&mt('There are no co-authors to display.')."\n");
                   1424:         } elsif ($context eq 'domain') {
                   1425:             if ($env{'form.roletype'} eq 'domain') {
                   1426:                 $r->print(&mt('There are no users with domain roles to display.')."\n");
1.13      raeburn  1427:             } elsif ($env{'form.roletype'} eq 'author') {
1.3       raeburn  1428:                 $r->print(&mt('There are no authors or co-authors to display.')."\n");
                   1429:             } elsif ($env{'form.roletype'} eq 'course') {
                   1430:                 $r->print(&mt('There are no course users to display')."\n"); 
1.2       raeburn  1431:             }
1.3       raeburn  1432:         } elsif ($context eq 'course') {
                   1433:             $r->print(&mt('There are no course users to display.')."\n");
                   1434:         }
                   1435:     } else {
                   1436:         # Print out the available choices
1.4       raeburn  1437:         my $usercount;
1.3       raeburn  1438:         if ($env{'form.action'} eq 'modifystudent') {
1.10      raeburn  1439:             ($usercount) = &show_users_list($r,$context,'view',$permission,
1.4       raeburn  1440:                                  $env{'form.Status'},\%userlist,$keylist);
1.1       raeburn  1441:         } else {
1.4       raeburn  1442:             ($usercount) = &show_users_list($r,$context,$env{'form.output'},
1.10      raeburn  1443:                                $permission,$env{'form.Status'},\%userlist,$keylist);
1.4       raeburn  1444:         }
                   1445:         if (!$usercount) {
                   1446:             $r->print('<br />'.&mt('There are no users matching the search criteria.')); 
1.2       raeburn  1447:         }
                   1448:     }
1.10      raeburn  1449:     $r->print('<input type="hidden" name="phase" value="'.
                   1450:               $env{'form.phase'}.'" /></form>');
1.2       raeburn  1451: }
                   1452: 
1.33      raeburn  1453: sub section_group_filter {
                   1454:     my ($cnum,$cdom) = @_;
                   1455:     my @filters;
                   1456:     if ($env{'request.course.sec'} eq '') {
                   1457:         @filters = ('sec');
                   1458:     }
                   1459:     push(@filters,'grp');
                   1460:     my %name = (
                   1461:                  sec => 'secfilter',
                   1462:                  grp => 'grpfilter',
                   1463:                );
                   1464:     my %title = &Apache::lonlocal::texthash (
                   1465:                                               sec  => 'Section(s)',
                   1466:                                               grp  => 'Group(s)',
                   1467:                                               all  => 'all',
                   1468:                                               none => 'none',
                   1469:                                             );
1.47      raeburn  1470:     my $output;
1.33      raeburn  1471:     foreach my $item (@filters) {
1.47      raeburn  1472:         my ($markup,@options); 
1.33      raeburn  1473:         if ($env{'form.'.$name{$item}} eq '') {
                   1474:             $env{'form.'.$name{$item}} = 'all';
                   1475:         }
                   1476:         if ($item eq 'sec') {
                   1477:             if ($env{'form.showrole'} eq 'cc') {
                   1478:                 $env{'form.'.$name{$item}} = 'none';
                   1479:             }
                   1480:             my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum);
                   1481:             @options = sort(keys(%sections_count));
                   1482:         } elsif ($item eq 'grp') {
                   1483:             my %curr_groups = &Apache::longroup::coursegroups();
                   1484:             @options = sort(keys(%curr_groups));
                   1485:         }
                   1486:         if (@options > 0) {
                   1487:             my $currsel;
                   1488:             $markup = '<select name="'.$name{$item}.'" />'."\n";
                   1489:             foreach my $option ('all','none',@options) { 
                   1490:                 $currsel = '';
                   1491:                 if ($env{'form.'.$name{$item}} eq $option) {
                   1492:                     $currsel = ' selected="selected" ';
                   1493:                 }
                   1494:                 $markup .= ' <option value="'.$option.'"'.$currsel.'>';
                   1495:                 if (($option eq 'all') || ($option eq 'none')) {
                   1496:                     $markup .= $title{$option};
                   1497:                 } else {
                   1498:                     $markup .= $option;
                   1499:                 }   
                   1500:                 $markup .= '</option>'."\n";
                   1501:             }
                   1502:             $markup .= '</select>'."\n";
                   1503:             $output .= ('&nbsp;'x3).'<label>'.$title{$item}.': '.$markup.'</label>';
                   1504:         }
                   1505:     }
                   1506:     return $output;
                   1507: }
                   1508: 
1.2       raeburn  1509: sub list_submit_button {
                   1510:     my ($text) = @_;
1.11      raeburn  1511:     return '<input type="button" name="updatedisplay" value="'.$text.'" onclick="javascript:display_update()" />';
1.2       raeburn  1512: }
                   1513: 
                   1514: sub gather_userinfo {
1.11      raeburn  1515:     my ($context,$format,$userlist,$indexhash,$userinfo,$rolehash,$permission) = @_;
1.2       raeburn  1516:     foreach my $item (keys(%{$rolehash})) {
                   1517:         my %userdata;
1.22      raeburn  1518:         if ($context eq 'author') { 
1.2       raeburn  1519:             ($userdata{'username'},$userdata{'domain'},$userdata{'role'}) =
                   1520:                 split(/:/,$item);
                   1521:             ($userdata{'start'},$userdata{'end'})=split(/:/,$rolehash->{$item});
1.24      raeburn  1522:             &build_user_record($context,\%userdata,$userinfo,$indexhash,
                   1523:                                $item,$userlist);
1.22      raeburn  1524:         } elsif ($context eq 'course') {
                   1525:             my $viewablesec = &viewable_section($permission);
                   1526:             ($userdata{'username'},$userdata{'domain'},$userdata{'role'},
                   1527:              $userdata{'section'}) = split(/:/,$item,-1);
                   1528:             ($userdata{'start'},$userdata{'end'})=split(/:/,$rolehash->{$item});
                   1529:             if (($viewablesec ne '') && ($userdata{'section'} ne '')) {
                   1530:                 next if ($viewablesec ne $userdata{'section'});
                   1531:             }
1.24      raeburn  1532:             &build_user_record($context,\%userdata,$userinfo,$indexhash,
                   1533:                                $item,$userlist);
1.2       raeburn  1534:         } elsif ($context eq 'domain') {
                   1535:             if ($env{'form.roletype'} eq 'domain') {
                   1536:                 ($userdata{'role'},$userdata{'username'},$userdata{'domain'}) =
                   1537:                     split(/:/,$item);
                   1538:                 ($userdata{'end'},$userdata{'start'})=split(/:/,$rolehash->{$item});
1.24      raeburn  1539:                 &build_user_record($context,\%userdata,$userinfo,$indexhash,
                   1540:                                    $item,$userlist);
1.13      raeburn  1541:             } elsif ($env{'form.roletype'} eq 'author') {
1.2       raeburn  1542:                 if (ref($rolehash->{$item}) eq 'HASH') {
                   1543:                     $userdata{'extent'} = $item;
                   1544:                     foreach my $key (keys(%{$rolehash->{$item}})) {
                   1545:                         ($userdata{'username'},$userdata{'domain'},$userdata{'role'}) =  split(/:/,$key);
                   1546:                         ($userdata{'start'},$userdata{'end'}) = 
                   1547:                             split(/:/,$rolehash->{$item}{$key});
                   1548:                         my $uniqid = $key.':'.$item;
1.25      raeburn  1549:                         &build_user_record($context,\%userdata,$userinfo,
                   1550:                                            $indexhash,$uniqid,$userlist);
1.2       raeburn  1551:                     }
                   1552:                 }
                   1553:             } elsif ($env{'form.roletype'} eq 'course') {
                   1554:                 ($userdata{'username'},$userdata{'domain'},$userdata{'role'}) =
                   1555:                     split(/:/,$item);
                   1556:                 if (ref($rolehash->{$item}) eq 'HASH') {
1.11      raeburn  1557:                     my $numcids = keys(%{$rolehash->{$item}});
1.2       raeburn  1558:                     foreach my $cid (sort(keys(%{$rolehash->{$item}}))) {
                   1559:                         if (ref($rolehash->{$item}{$cid}) eq 'HASH') {
                   1560:                             my $spanstart = '';
                   1561:                             my $spanend = '; ';
                   1562:                             my $space = ', ';
                   1563:                             if ($format eq 'html' || $format eq 'view') {
                   1564:                                 $spanstart = '<span class="LC_nobreak">';
1.23      raeburn  1565:                                 # FIXME: actions on courses disabled for now
                   1566: #                                if ($permission->{'cusr'}) {
                   1567: #                                    if ($numcids > 1) {
1.25      raeburn  1568: #                                        $spanstart .= '<input type="radio" name="'.$item.'" value="'.$cid.'" />&nbsp;';
1.23      raeburn  1569: #                                    } else {
1.25      raeburn  1570: #                                        $spanstart .= '<input type="hidden" name="'.$item.'" value="'.$cid.'" />&nbsp;';
1.23      raeburn  1571: #                                    }
                   1572: #                                }
1.2       raeburn  1573:                                 $spanend = '</span><br />';
                   1574:                                 $space = ',&nbsp;';
                   1575:                             }
                   1576:                             $userdata{'extent'} .= $spanstart.
                   1577:                                     $rolehash->{$item}{$cid}{'desc'}.$space;
                   1578:                             if (ref($rolehash->{$item}{$cid}{'secs'}) eq 'HASH') { 
                   1579:                                 foreach my $sec (sort(keys(%{$rolehash->{$item}{$cid}{'secs'}}))) {
1.25      raeburn  1580:                                     if (($env{'form.Status'} eq 'Any') ||
                   1581:                                         ($env{'form.Status'} eq $rolehash->{$item}{$cid}{'secs'}{$sec})) {
                   1582:                                         $userdata{'extent'} .= $sec.$space.$rolehash->{$item}{$cid}{'secs'}{$sec}.$spanend;
                   1583:                                         $userdata{'status'} = $rolehash->{$item}{$cid}{'secs'}{$sec};
                   1584:                                     }
1.2       raeburn  1585:                                 }
                   1586:                             }
                   1587:                         }
                   1588:                     }
                   1589:                 }
1.25      raeburn  1590:                 if ($userdata{'status'} ne '') {
                   1591:                     &build_user_record($context,\%userdata,$userinfo,
                   1592:                                        $indexhash,$item,$userlist);
                   1593:                 }
1.2       raeburn  1594:             }
                   1595:         }
                   1596:     }
                   1597:     return;
                   1598: }
                   1599: 
                   1600: sub build_user_record {
1.24      raeburn  1601:     my ($context,$userdata,$userinfo,$indexhash,$record_key,$userlist) = @_;
1.11      raeburn  1602:     next if ($userdata->{'start'} eq '-1' && $userdata->{'end'} eq '-1');
1.24      raeburn  1603:     if (!(($context eq 'domain') && ($env{'form.roletype'} eq 'course'))) {
                   1604:         &process_date_info($userdata);
                   1605:     }
1.2       raeburn  1606:     my $username = $userdata->{'username'};
                   1607:     my $domain = $userdata->{'domain'};
                   1608:     if (ref($userinfo->{$username.':'.$domain}) eq 'HASH') {
1.24      raeburn  1609:         $userdata->{'fullname'} = $userinfo->{$username.':'.$domain}{'fullname'};
1.2       raeburn  1610:         $userdata->{'id'} = $userinfo->{$username.':'.$domain}{'id'};
                   1611:     } else {
                   1612:         &aggregate_user_info($domain,$username,$userinfo);
                   1613:         $userdata->{'fullname'} = $userinfo->{$username.':'.$domain}{'fullname'};
                   1614:         $userdata->{'id'} = $userinfo->{$username.':'.$domain}{'id'};
                   1615:     }
                   1616:     foreach my $key (keys(%{$indexhash})) {
                   1617:         if (defined($userdata->{$key})) {
                   1618:             $userlist->{$record_key}[$indexhash->{$key}] = $userdata->{$key};
                   1619:         }
                   1620:     }
                   1621:     return;
                   1622: }
                   1623: 
                   1624: sub courses_selector {
                   1625:     my ($cdom,$formname) = @_;
                   1626:     my %coursecodes = ();
                   1627:     my %codes = ();
                   1628:     my @codetitles = ();
                   1629:     my %cat_titles = ();
                   1630:     my %cat_order = ();
                   1631:     my %idlist = ();
                   1632:     my %idnums = ();
                   1633:     my %idlist_titles = ();
                   1634:     my $caller = 'global';
                   1635:     my $format_reply;
                   1636:     my $jscript = '';
                   1637: 
1.7       albertel 1638:     my $totcodes = 0;
                   1639:     $totcodes =
1.2       raeburn  1640:         &Apache::courseclassifier::retrieve_instcodes(\%coursecodes,
                   1641:                                                       $cdom,$totcodes);
                   1642:     if ($totcodes > 0) {
                   1643:         $format_reply =
                   1644:              &Apache::lonnet::auto_instcode_format($caller,$cdom,\%coursecodes,
                   1645:                                 \%codes,\@codetitles,\%cat_titles,\%cat_order);
                   1646:         if ($format_reply eq 'ok') {
                   1647:             my $numtypes = @codetitles;
                   1648:             &Apache::courseclassifier::build_code_selections(\%codes,\@codetitles,\%cat_titles,\%cat_order,\%idlist,\%idnums,\%idlist_titles);
                   1649:             my ($scripttext,$longtitles) = &Apache::courseclassifier::javascript_definitions(\@codetitles,\%idlist,\%idlist_titles,\%idnums,\%cat_titles);
                   1650:             my $longtitles_str = join('","',@{$longtitles});
                   1651:             my $allidlist = $idlist{$codetitles[0]};
                   1652:             $jscript .= &Apache::courseclassifier::courseset_js_start($formname,$longtitles_str,$allidlist);
                   1653:             $jscript .= $scripttext;
                   1654:             $jscript .= &Apache::courseclassifier::javascript_code_selections($formname,@codetitles);
                   1655:         }
                   1656:     }
                   1657:     my $cb_jscript = &Apache::loncommon::coursebrowser_javascript($cdom);
                   1658: 
                   1659:     my %elements = (
                   1660:                      Year => 'selectbox',
                   1661:                      coursepick => 'radio',
                   1662:                      coursetotal => 'text',
                   1663:                      courselist => 'text',
                   1664:                    );
                   1665:     $jscript .= &Apache::lonhtmlcommon::set_form_elements(\%elements);
                   1666:     if ($env{'form.coursepick'} eq 'category') {
                   1667:         $jscript .= qq|
                   1668: function setCourseCat(formname) {
                   1669:     if (formname.Year.options[formname.Year.selectedIndex].value == -1) {
                   1670:         return;
                   1671:     }
                   1672:     courseSet('Year');
                   1673:     for (var j=0; j<formname.Semester.length; j++) {
                   1674:         if (formname.Semester.options[j].value == "$env{'form.Semester'}") {
                   1675:             formname.Semester.options[j].selected = true;
                   1676:         }
                   1677:     }
                   1678:     if (formname.Semester.options[formname.Semester.selectedIndex].value == -1) {
                   1679:         return;
                   1680:     }
                   1681:     courseSet('Semester');
                   1682:     for (var j=0; j<formname.Department.length; j++) {
                   1683:         if (formname.Department.options[j].value == "$env{'form.Department'}") {            formname.Department.options[j].selected = true;
                   1684:         }
                   1685:     }
                   1686:     if (formname.Department.options[formname.Department.selectedIndex].value == -1) {
                   1687:         return;
                   1688:     }
                   1689:     courseSet('Department');
                   1690:     for (var j=0; j<formname.Number.length; j++) {
                   1691:         if (formname.Number.options[j].value == "$env{'form.Number'}") {
                   1692:             formname.Number.options[j].selected = true;
                   1693:         }
                   1694:     }
                   1695: }
                   1696: |;
                   1697:     }
                   1698:     return ($cb_jscript,$jscript,$totcodes,\@codetitles,\%idlist,
                   1699:             \%idlist_titles);
                   1700: }
                   1701: 
                   1702: sub course_selector_loadcode {
                   1703:     my ($formname) = @_;
                   1704:     my $loadcode;
                   1705:     if ($env{'form.coursepick'} ne '') {
                   1706:         $loadcode = 'javascript:setFormElements(document.'.$formname.')';
                   1707:         if ($env{'form.coursepick'} eq 'category') {
                   1708:             $loadcode .= ';javascript:setCourseCat(document.'.$formname.')';
                   1709:         }
                   1710:     }
                   1711:     return $loadcode;
                   1712: }
                   1713: 
                   1714: sub process_coursepick {
                   1715:     my $coursefilter = $env{'form.coursepick'};
                   1716:     my $cdom = $env{'request.role.domain'};
                   1717:     my %courses;
                   1718:     if ($coursefilter eq 'all') {
                   1719:         %courses = &Apache::lonnet::courseiddump($cdom,'.','.','.','.','.',
                   1720:                                                  undef,undef,'Course');
                   1721:     } elsif ($coursefilter eq 'category') {
                   1722:         my $instcode = &instcode_from_coursefilter();
                   1723:         %courses = &Apache::lonnet::courseiddump($cdom,'.','.',$instcode,'.','.',
                   1724:                                                  undef,undef,'Course');
                   1725:     } elsif ($coursefilter eq 'specific') {
                   1726:         if ($env{'form.coursetotal'} > 1) {
                   1727:             my @course_ids = split(/&&/,$env{'form.courselist'});
                   1728:             foreach my $cid (@course_ids) {
                   1729:                 $courses{$cid} = '';
1.1       raeburn  1730:             }
1.2       raeburn  1731:         } else {
                   1732:             $courses{$env{'form.courselist'}} = '';
1.1       raeburn  1733:         }
1.2       raeburn  1734:     }
                   1735:     return %courses;
                   1736: }
                   1737: 
                   1738: sub instcode_from_coursefilter {
                   1739:     my $instcode = '';
                   1740:     my @cats = ('Semester','Year','Department','Number');
                   1741:     foreach my $category (@cats) {
                   1742:         if (defined($env{'form.'.$category})) {
                   1743:             unless ($env{'form.'.$category} eq '-1') {
                   1744:                 $instcode .= $env{'form.'.$category};
                   1745:            }
                   1746:         }
                   1747:     }
                   1748:     if ($instcode eq '') {
                   1749:         $instcode = '.';
                   1750:     }
                   1751:     return $instcode;
                   1752: }
                   1753: 
                   1754: sub display_adv_courseroles {
                   1755:     my $output;
                   1756:     #
                   1757:     # List course personnel
                   1758:     my %coursepersonnel = 
                   1759:        &Apache::lonnet::get_course_adv_roles($env{'request.course.id'});
                   1760:     #
                   1761:     $output = '<br />'.&Apache::loncommon::start_data_table();
                   1762:     foreach my $role (sort(keys(%coursepersonnel))) {
                   1763:         next if ($role =~ /^\s*$/);
                   1764:         $output .= &Apache::loncommon::start_data_table_row().
                   1765:                   '<td>'.$role.'</td><td>';
                   1766:         foreach my $user (split(',',$coursepersonnel{$role})) {
                   1767:             my ($puname,$pudom)=split(':',$user);
                   1768:             $output .= ' '.&Apache::loncommon::aboutmewrapper(
                   1769:                        &Apache::loncommon::plainname($puname,$pudom),
                   1770:                        $puname,$pudom);
                   1771:         }
                   1772:         $output .= '</td>'.&Apache::loncommon::end_data_table_row();
                   1773:     }
                   1774:     $output .= &Apache::loncommon::end_data_table();
                   1775: }
                   1776: 
                   1777: sub make_keylist_array {
                   1778:     my ($index,$keylist);
                   1779:     $index->{'domain'} = &Apache::loncoursedata::CL_SDOM();
                   1780:     $index->{'username'} = &Apache::loncoursedata::CL_SNAME();
                   1781:     $index->{'end'} = &Apache::loncoursedata::CL_END();
                   1782:     $index->{'start'} = &Apache::loncoursedata::CL_START();
                   1783:     $index->{'id'} = &Apache::loncoursedata::CL_ID();
                   1784:     $index->{'section'} = &Apache::loncoursedata::CL_SECTION();
                   1785:     $index->{'fullname'} = &Apache::loncoursedata::CL_FULLNAME();
                   1786:     $index->{'status'} = &Apache::loncoursedata::CL_STATUS();
                   1787:     $index->{'type'} = &Apache::loncoursedata::CL_TYPE();
                   1788:     $index->{'lockedtype'} = &Apache::loncoursedata::CL_LOCKEDTYPE();
                   1789:     $index->{'groups'} = &Apache::loncoursedata::CL_GROUP();
                   1790:     $index->{'email'} = &Apache::loncoursedata::CL_PERMANENTEMAIL();
                   1791:     $index->{'role'} = &Apache::loncoursedata::CL_ROLE();
                   1792:     $index->{'extent'} = &Apache::loncoursedata::CL_EXTENT();
1.44      raeburn  1793:     $index->{'photo'} = &Apache::loncoursedata::CL_PHOTO();
1.47      raeburn  1794:     $index->{'thumbnail'} = &Apache::loncoursedata::CL_THUMBNAIL();
1.2       raeburn  1795:     foreach my $key (keys(%{$index})) {
                   1796:         $keylist->[$index->{$key}] = $key;
                   1797:     }
                   1798:     return ($index,$keylist);
                   1799: }
                   1800: 
                   1801: sub aggregate_user_info {
                   1802:     my ($udom,$uname,$userinfo) = @_;
                   1803:     my %info=&Apache::lonnet::get('environment',
                   1804:                                   ['firstname','middlename',
                   1805:                                    'lastname','generation','id'],
                   1806:                                    $udom,$uname);
                   1807:     my ($tmp) = keys(%info);
                   1808:     my ($fullname,$id);
                   1809:     if ($tmp =~/^(con_lost|error|no_such_host)/i) {
                   1810:         $fullname = 'not available';
                   1811:         $id = 'not available';
                   1812:         &Apache::lonnet::logthis('unable to retrieve environment '.
                   1813:                                  'for '.$uname.':'.$udom);
1.1       raeburn  1814:     } else {
1.2       raeburn  1815:         $fullname = &Apache::lonnet::format_name(@info{qw/firstname middlename lastname generation/},'lastname');
                   1816:         $id = $info{'id'};
                   1817:     }
                   1818:     $userinfo->{$uname.':'.$udom} = { 
                   1819:                                       fullname => $fullname,
                   1820:                                       id       => $id,
                   1821:                                     };
                   1822:     return;
                   1823: }
1.1       raeburn  1824: 
1.2       raeburn  1825: sub process_date_info {
                   1826:     my ($userdata) = @_;
                   1827:     my $now = time;
                   1828:     $userdata->{'status'} = 'Active';
                   1829:     if ($userdata->{'start'} > 0) {
                   1830:         if ($now < $userdata->{'start'}) {
                   1831:             $userdata->{'status'} = 'Future';
                   1832:         }
1.1       raeburn  1833:     }
1.2       raeburn  1834:     if ($userdata->{'end'} > 0) {
                   1835:         if ($now > $userdata->{'end'}) {
                   1836:             $userdata->{'status'} = 'Expired';
                   1837:         }
                   1838:     }
                   1839:     return;
1.1       raeburn  1840: }
                   1841: 
                   1842: sub show_users_list {
1.10      raeburn  1843:     my ($r,$context,$mode,$permission,$statusmode,$userlist,$keylist)=@_;
1.1       raeburn  1844:     #
                   1845:     # Variables for excel output
                   1846:     my ($excel_workbook, $excel_sheet, $excel_filename,$row,$format);
                   1847:     #
                   1848:     # Variables for csv output
                   1849:     my ($CSVfile,$CSVfilename);
                   1850:     #
                   1851:     my $sortby = $env{'form.sortby'};
1.3       raeburn  1852:     my @sortable = ('username','domain','id','fullname','start','end','email','role');
1.2       raeburn  1853:     if ($context eq 'course') {
1.3       raeburn  1854:         push(@sortable,('section','groups','type'));
1.2       raeburn  1855:     } else {
1.3       raeburn  1856:         push(@sortable,'extent');
                   1857:     }
                   1858:     if (!grep(/^\Q$sortby\E$/,@sortable)) {
                   1859:         $sortby = 'username';
1.1       raeburn  1860:     }
1.22      raeburn  1861:     my $setting = $env{'form.roletype'};
1.35      raeburn  1862:     my ($cid,$cdom,$cnum,$classgroups,$displayphotos,$displayclickers);
1.1       raeburn  1863:     if ($context eq 'course') {
1.22      raeburn  1864:         $cid = $env{'request.course.id'};
1.17      raeburn  1865:         ($cnum,$cdom) = &get_course_identity($cid);
1.2       raeburn  1866:         ($classgroups) = &Apache::loncoursedata::get_group_memberships(
                   1867:                                      $userlist,$keylist,$cdom,$cnum);
1.16      raeburn  1868:         if ($mode eq 'autoenroll') {
                   1869:             $env{'form.showrole'} = 'st';
                   1870:         } else {
                   1871:             if (! exists($env{'form.displayphotos'})) {
                   1872:                 $env{'form.displayphotos'} = 'off';
                   1873:             }
                   1874:             $displayphotos = $env{'form.displayphotos'};
                   1875:             if (! exists($env{'form.displayclickers'})) {
                   1876:                 $env{'form.displayclickers'} = 'off';
                   1877:             }
                   1878:             $displayclickers = $env{'form.displayclickers'};
                   1879:             if ($env{'course.'.$cid.'.internal.showphoto'}) {
                   1880:                 $r->print('
1.1       raeburn  1881: <script type="text/javascript">
                   1882: function photowindow(photolink) {
                   1883:     var title = "Photo_Viewer";
                   1884:     var options = "scrollbars=1,resizable=1,menubar=0";
                   1885:     options += ",width=240,height=240";
                   1886:     stdeditbrowser = open(photolink,title,options,"1");
                   1887:     stdeditbrowser.focus();
                   1888: }
                   1889: </script>
1.16      raeburn  1890:                ');
                   1891:             }
                   1892:             $r->print(<<END);
1.1       raeburn  1893: <input type="hidden" name="displayphotos" value="$displayphotos" />
                   1894: <input type="hidden" name="displayclickers" value="$displayclickers" />
                   1895: END
1.16      raeburn  1896:         }
1.1       raeburn  1897:     }
1.16      raeburn  1898:     if ($mode ne 'autoenroll') {
1.11      raeburn  1899:         my $check_uncheck_js = &Apache::loncommon::check_uncheck_jscript();
                   1900:         my $alert = &mt("You must select at least one user by checking a user's 'Select' checkbox");
1.25      raeburn  1901:         my $singconfirm = &mt(' for a single user?');
                   1902:         my $multconfirm = &mt(' for multiple users?');
1.40      raeburn  1903:         my $date_sec_selector = &date_section_javascript($context,$setting,$statusmode);
                   1904:         my %lt = &Apache::lonlocal::texthash( 
                   1905:               acwi => 'Access will be set to start immediately',
                   1906:               asyo => 'as you did not select an end date in the pop-up window',
                   1907:               accw => 'Access will be set to continue indefinitely',
                   1908:               asyd => 'as you did not select an end date in the pop-up window',
                   1909:               sewi => "Sections will be switched to 'No section'",
                   1910:               ayes => "as you either selected the 'No section' option",
                   1911:               oryo => 'or you did not select a section in the pop-up window',
                   1912:               arol => 'A role with no section will be added',
                   1913:               swbs => 'Sections will be switched to:',
                   1914:               rwba => 'Roles will be added for section(s):',
                   1915:         );
1.1       raeburn  1916:         $r->print(<<END);
1.10      raeburn  1917: 
                   1918: <script type="text/javascript" language="Javascript">
1.11      raeburn  1919: $check_uncheck_js
                   1920: 
                   1921: function verify_action (field) {
                   1922:     var numchecked = 0;
                   1923:     var singconf = '$singconfirm';
                   1924:     var multconf = '$multconfirm';
                   1925:     if (field.length > 0) {
                   1926:         for (i = 0; i < field.length; i++) {
                   1927:             if (field[i].checked == true) {
                   1928:                numchecked ++;
                   1929:             }
                   1930:         }
                   1931:     } else {
                   1932:         if (field.checked == true) {
                   1933:             numchecked ++;
                   1934:         }
                   1935:     }
                   1936:     if (numchecked == 0) {
                   1937:         alert("$alert");
                   1938:     } 
                   1939:     else {
                   1940:         var message = document.studentform.bulkaction[document.studentform.bulkaction.selectedIndex].text;
1.40      raeburn  1941:         var choice = document.studentform.bulkaction[document.studentform.bulkaction.selectedIndex].value;
1.11      raeburn  1942:         if (numchecked == 1) { 
                   1943:             message += singconf;
                   1944:         } 
                   1945:         else {
                   1946:             message += multconf; 
                   1947:         }
1.40      raeburn  1948:         if (choice == 'chgdates' || choice == 'reenable' || choice == 'activate') {
                   1949:             var datemsg = '';
                   1950:             if ((document.studentform.startdate_month.value == '') && 
                   1951:                 (document.studentform.startdate_day.value  == '') &&
                   1952:                 (document.studentform.startdate_year.value == '')) {
                   1953:                 datemsg = "\\n$lt{'acwi'},\\n$lt{'asyo'}.\\n";
                   1954:             }
                   1955:             if ((document.studentform.enddate_month.value == '') &&
                   1956:                 (document.studentform.enddate_day.value  == '') &&
                   1957:                 (document.studentform.enddate_year.value == '')) {
                   1958:                 datemsg += "\\n$lt{'accw'},\\n$lt{'asyd'}.\\n";
                   1959:             }
                   1960:             if (datemsg != '') {
                   1961:                 message += "\\n"+datemsg;
                   1962:             }
                   1963:         }
                   1964:         if (choice == 'chgsec') {
                   1965:             var rolefilter = document.studentform.showrole.options[document.studentform.showrole.selectedIndex].value;
                   1966:             var retained =  document.studentform.retainsec.value;
                   1967:             var secshow = document.studentform.newsecs.value;
                   1968:             if (secshow == '') {
                   1969:                 if (rolefilter == 'st' || retained == 0 || retained == "") {
                   1970:                     message += "\\n\\n$lt{'sewi'},\\n$lt{'ayes'},\\n$lt{'oryo'}.\\n"; 
                   1971:                 } else {
                   1972:                     message += "\\n\\n$lt{'arol'}\\n$lt{'ayes'},\\n$lt{'oryo'}.\\n";
                   1973:                 }
                   1974:             } else {
                   1975:                 if (rolefilter == 'st' || retained == 0 || retained == "") {
                   1976:                     message += "\\n\\n$lt{'swbs'} "+secshow+".\\n";
                   1977:                 } else {
                   1978:                     message += "\\n\\n$lt{'rwba'} "+secshow+".\\n";
                   1979:                 }
                   1980:             }
                   1981:         }
1.11      raeburn  1982:         if (confirm(message)) {
                   1983:             document.studentform.phase.value = 'bulkchange';
                   1984:             document.studentform.submit();
                   1985:         }
                   1986:     }
                   1987: }
1.10      raeburn  1988: 
                   1989: function username_display_launch(username,domain) {
                   1990:     var target;
                   1991:     for (var i=0; i<document.studentform.usernamelink.length; i++) {
                   1992:         if (document.studentform.usernamelink[i].checked) {
                   1993:             target = document.studentform.usernamelink[i].value;
                   1994:         }
                   1995:     }
                   1996:     if (target == 'modify') {
1.50      raeburn  1997:         if (document.studentform.userwin.checked == true) {
                   1998:             var url = '/adm/createuser?srchterm='+username+'&srchdomain='+domain+'&phase=get_user_info&action=singleuser&srchin=dom&srchby=uname&srchtype=exact&popup=1';
                   1999:             var options = 'height=600,width=800,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no';
                   2000:             modifywin = window.open(url,'',options,1);
                   2001:             modifywin.focus();
                   2002:             return;
                   2003:         } else {
                   2004:             document.studentform.srchterm.value=username;
                   2005:             document.studentform.srchdomain.value=domain;
                   2006:             document.studentform.phase.value='get_user_info';
                   2007:             document.studentform.action.value = 'singleuser';
                   2008:             document.studentform.submit();
                   2009:         }
1.10      raeburn  2010:     }
1.48      raeburn  2011:     if (target == 'aboutme') {
1.50      raeburn  2012:         if (document.studentform.userwin.checked == true) {
                   2013:             var url = '/adm/'+domain+'/'+username+'/aboutme?popup=1';
                   2014:             var options = 'height=600,width=800,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no';
                   2015:             aboutmewin = window.open(url,'',options,1);
                   2016:             aboutmewin.focus();
                   2017:             return;
                   2018:         } else {
                   2019:             document.location.href = '/adm/'+domain+'/'+username+'/aboutme';
                   2020:         }
1.48      raeburn  2021:     }
1.10      raeburn  2022: }
                   2023: </script>
1.11      raeburn  2024: $date_sec_selector
1.1       raeburn  2025: <input type="hidden" name="state" value="$env{'form.state'}" />
                   2026: END
                   2027:     }
                   2028:     $r->print(<<END);
                   2029: <input type="hidden" name="sortby" value="$sortby" />
                   2030: END
                   2031: 
                   2032:     my %lt=&Apache::lonlocal::texthash(
                   2033:                        'username'   => "username",
                   2034:                        'domain'     => "domain",
                   2035:                        'id'         => 'ID',
                   2036:                        'fullname'   => "name",
                   2037:                        'section'    => "section",
                   2038:                        'groups'     => "active groups",
                   2039:                        'start'      => "start date",
                   2040:                        'end'        => "end date",
                   2041:                        'status'     => "status",
1.2       raeburn  2042:                        'role'       => "role",
1.1       raeburn  2043:                        'type'       => "enroll type/action",
                   2044:                        'email'      => "email address",
                   2045:                        'clicker'    => "clicker id",
                   2046:                        'photo'      => "photo",
1.2       raeburn  2047:                        'extent'     => "extent",
1.41      raeburn  2048:                        'go'         => "go",
1.11      raeburn  2049:                        'pr'         => "Proceed",
                   2050:                        'ca'         => "check all",
                   2051:                        'ua'         => "uncheck all",
                   2052:                        'ac'         => "Action to take for selected users",
1.10      raeburn  2053:                        'link'       => "Behavior of username links",
                   2054:                        'aboutme'    => "Display a user's personal page",
1.50      raeburn  2055:                        'owin'       => "Open in a new window",
1.10      raeburn  2056:                        'modify'     => "Modify a user's information",
1.1       raeburn  2057:                       );
1.2       raeburn  2058:     if ($context eq 'domain' && $env{'form.roletype'} eq 'course') {
                   2059:         $lt{'extent'} = &mt('Course(s): description, section(s), status');
1.13      raeburn  2060:     } elsif ($context eq 'author') {
1.2       raeburn  2061:         $lt{'extent'} = &mt('Author'); 
                   2062:     }
1.1       raeburn  2063:     my @cols = ('username','domain','id','fullname');
                   2064:     if ($context eq 'course') {
                   2065:         push(@cols,'section');
                   2066:     }
1.2       raeburn  2067:     if (!($context eq 'domain' && $env{'form.roletype'} eq 'course')) { 
                   2068:         push(@cols,('start','end'));
                   2069:     }
1.3       raeburn  2070:     if ($env{'form.showrole'} eq 'Any' || $env{'form.showrole'} eq 'cr') {
1.2       raeburn  2071:         push(@cols,'role');
                   2072:     }
1.13      raeburn  2073:     if ($context eq 'domain' && ($env{'form.roletype'} eq 'author' ||
1.2       raeburn  2074:                                 $env{'form.roletype'} eq 'course')) {
                   2075:         push (@cols,'extent');
                   2076:     }
                   2077:     if (($statusmode eq 'Any') && 
                   2078:         (!($context eq 'domain' && $env{'form.roletype'} eq 'course'))) {
1.1       raeburn  2079:         push(@cols,'status');
                   2080:     }
                   2081:     if ($context eq 'course') {
                   2082:         push(@cols,'groups');
                   2083:     }
                   2084:     push(@cols,'email');
                   2085: 
1.4       raeburn  2086:     my $rolefilter = $env{'form.showrole'};
1.5       raeburn  2087:     if ($env{'form.showrole'} eq 'cr') {
                   2088:         $rolefilter = &mt('custom');  
                   2089:     } elsif ($env{'form.showrole'} ne 'Any') {
1.2       raeburn  2090:         $rolefilter = &Apache::lonnet::plaintext($env{'form.showrole'});
                   2091:     }
1.16      raeburn  2092:     my $results_description;
                   2093:     if ($mode ne 'autoenroll') {
                   2094:         $results_description = &results_header_row($rolefilter,$statusmode,
1.24      raeburn  2095:                                                    $context,$permission,$mode);
1.16      raeburn  2096:         $r->print('<b>'.$results_description.'</b><br />');
                   2097:     }
1.26      raeburn  2098:     my ($output,$actionselect,%canchange,%canchangesec);
1.16      raeburn  2099:     if ($mode eq 'html' || $mode eq 'view' || $mode eq 'autoenroll') {
                   2100:         if ($mode ne 'autoenroll') {
                   2101:             if ($permission->{'cusr'}) {
                   2102:                 $actionselect = &select_actions($context,$setting,$statusmode);
                   2103:             }
                   2104:             $r->print(<<END);
1.10      raeburn  2105: <input type="hidden" name="srchby"  value="uname" />
                   2106: <input type="hidden" name="srchin"   value="dom" />
                   2107: <input type="hidden" name="srchtype" value="exact" />
                   2108: <input type="hidden" name="srchterm" value="" />
1.11      raeburn  2109: <input type="hidden" name="srchdomain" value="" /> 
1.1       raeburn  2110: END
1.16      raeburn  2111:             $output = '<p>';
1.50      raeburn  2112:             my @linkdests = ('aboutme');
1.16      raeburn  2113:             if ($permission->{'cusr'}) {
1.48      raeburn  2114:                 unshift (@linkdests,'modify');
                   2115:             }
                   2116:             $output .= '<span class="LC_nobreak">'.$lt{'link'}.':&nbsp;';
                   2117:             my $usernamelink = $env{'form.usernamelink'};
                   2118:             if ($usernamelink eq '') {
                   2119:                 $usernamelink = 'aboutme';
                   2120:             }
                   2121:             foreach my $item (@linkdests) {
                   2122:                 my $checkedstr = '';
                   2123:                 if ($item eq $usernamelink) {
                   2124:                     $checkedstr = ' checked="checked" ';
1.16      raeburn  2125:                 }
1.48      raeburn  2126:                 $output .= '<label><input type="radio" name="usernamelink" value="'.$item.'"'.$checkedstr.'>&nbsp;'.$lt{$item}.'</label>&nbsp;&nbsp;';
1.16      raeburn  2127:             }
1.50      raeburn  2128:             my $checkwin;
                   2129:             if ($env{'form.userwin'}) { 
                   2130:                 $checkwin = 'checked = "checked"'; 
                   2131:             }
                   2132:             $output .= '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" name="userwin" value="1" $checkwin />'.$lt{'owin'}.'</span><br />';
1.16      raeburn  2133:             if ($actionselect) {
1.41      raeburn  2134:                 $output .= <<"END";
                   2135: $lt{'ac'}:&nbsp;$actionselect <input type="button" value="$lt{'go'}" onclick="javascript:opendatebrowser(this.form,'studentform','go')" /></p>
1.11      raeburn  2136: <p><input type="button" value="$lt{'ca'}" onclick="javascript:checkAll(document.studentform.actionlist)" /> &nbsp;
1.41      raeburn  2137: <input type="button" value="$lt{'ua'}" onclick="javascript:uncheckAll(document.studentform.actionlist)" /><br /><br /><input type="button" value="$lt{'pr'}" onclick="javascript:verify_action(document.studentform.actionlist)" />
1.11      raeburn  2138: END
1.26      raeburn  2139:                 my @allroles;
                   2140:                 if ($env{'form.showrole'} eq 'Any') {
                   2141:                     my $custom = 1;
                   2142:                     if ($context eq 'domain') {
                   2143:                         @allroles = &roles_by_context($setting,$custom);
                   2144:                     } else {
                   2145:                         @allroles = &roles_by_context($context,$custom);
                   2146:                     }
                   2147:                 } else {
                   2148:                     @allroles = ($env{'form.showrole'});
                   2149:                 }
                   2150:                 foreach my $role (@allroles) {
                   2151:                     if ($context eq 'domain') {
                   2152:                         if ($setting eq 'domain') {
                   2153:                             if (&Apache::lonnet::allowed('c'.$role,
                   2154:                                     $env{'request.role.domain'})) {
                   2155:                                 $canchange{$role} = 1;
                   2156:                             }
1.31      raeburn  2157:                         } elsif ($setting eq 'author') {
                   2158:                             if (&Apache::lonnet::allowed('c'.$role,
                   2159:                                     $env{'request.role.domain'})) {
                   2160:                                 $canchange{$role} = 1;
                   2161:                             }
1.26      raeburn  2162:                         }
                   2163:                     } elsif ($context eq 'author') {
                   2164:                         if (&Apache::lonnet::allowed('c'.$role,
                   2165:                             $env{'user.domain'}.'/'.$env{'user.name'})) {
                   2166:                             $canchange{$role} = 1;
                   2167:                         }
                   2168:                     } elsif ($context eq 'course') {
                   2169:                         if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'})) {
                   2170:                             $canchange{$role} = 1;
                   2171:                         } elsif ($env{'request.course.sec'} ne '') {
                   2172:                             if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
                   2173:                                 $canchangesec{$role} = $env{'request.course.sec'};
                   2174:                             }
                   2175:                         }
                   2176:                     }
                   2177:                 }
1.16      raeburn  2178:             }
1.4       raeburn  2179:         }
                   2180:         $output .= "\n<p>\n".
1.1       raeburn  2181:                   &Apache::loncommon::start_data_table().
1.4       raeburn  2182:                   &Apache::loncommon::start_data_table_header_row();
1.1       raeburn  2183:         if ($mode eq 'autoenroll') {
1.4       raeburn  2184:             $output .= "
1.1       raeburn  2185:  <th><a href=\"javascript:document.studentform.sortby.value='type';document.studentform.submit();\">$lt{'type'}</a></th>
1.4       raeburn  2186:             ";
1.1       raeburn  2187:         } else {
1.11      raeburn  2188:             $output .= "\n".'<th>'.&mt('Count').'</th>'."\n";
                   2189:             if ($actionselect) {
                   2190:                 $output .= '<th>'.&mt('Select').'</th>'."\n";
                   2191:             }
1.1       raeburn  2192:         }
                   2193:         foreach my $item (@cols) {
1.4       raeburn  2194:             $output .= "<th><a href=\"javascript:document.studentform.sortby.value='$item';document.studentform.submit();\">$lt{$item}</a></th>\n";
1.1       raeburn  2195:         }
1.2       raeburn  2196:         my %role_types = &role_type_names();
1.16      raeburn  2197:         if ($context eq 'course' && $mode ne 'autoenroll') {
1.4       raeburn  2198:             if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') {
                   2199:                 # Clicker display on or off?
                   2200:                 my %clicker_options = &Apache::lonlocal::texthash(
                   2201:                                                             'on' => 'Show',
                   2202:                                                             'off' => 'Hide',
                   2203:                                                            );
                   2204:                 my $clickerchg = 'on';
                   2205:                 if ($displayclickers eq 'on') {
                   2206:                     $clickerchg = 'off';
                   2207:                 }
                   2208:                 $output .= '    <th>'."\n".'     '.
                   2209:                     '<a href="javascript:document.studentform.displayclickers.value='.
1.1       raeburn  2210:                       "'".$clickerchg."'".';document.studentform.submit();">'.
                   2211:                       $clicker_options{$clickerchg}.'</a>&nbsp;'.$lt{'clicker'}."\n".
1.4       raeburn  2212:                       '    </th>'."\n";
1.1       raeburn  2213: 
1.4       raeburn  2214:                 # Photo display on or off?
                   2215:                 if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) {
                   2216:                     my %photo_options = &Apache::lonlocal::texthash(
                   2217:                                                             'on' => 'Show',
                   2218:                                                             'off' => 'Hide',
                   2219:                                                                 );
                   2220:                     my $photochg = 'on';
                   2221:                     if ($displayphotos eq 'on') {
                   2222:                         $photochg = 'off';
                   2223:                     }
                   2224:                     $output .= '    <th>'."\n".'     '.
                   2225:                 '<a href="javascript:document.studentform.displayphotos.value='.
1.1       raeburn  2226:                       "'".$photochg."'".';document.studentform.submit();">'.
                   2227:                       $photo_options{$photochg}.'</a>&nbsp;'.$lt{'photo'}."\n".
1.4       raeburn  2228:                       '    </th>'."\n";
                   2229:                 }
1.1       raeburn  2230:             }
1.4       raeburn  2231:         }
1.16      raeburn  2232:         $output .= &Apache::loncommon::end_data_table_header_row();
1.1       raeburn  2233: # Done with the HTML header line
                   2234:     } elsif ($mode eq 'csv') {
                   2235:         #
                   2236:         # Open a file
                   2237:         $CSVfilename = '/prtspool/'.
1.2       raeburn  2238:                        $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
                   2239:                        time.'_'.rand(1000000000).'.csv';
1.1       raeburn  2240:         unless ($CSVfile = Apache::File->new('>/home/httpd'.$CSVfilename)) {
                   2241:             $r->log_error("Couldn't open $CSVfilename for output $!");
                   2242:             $r->print("Problems occured in writing the csv file.  ".
                   2243:                       "This error has been logged.  ".
                   2244:                       "Please alert your LON-CAPA administrator.");
                   2245:             $CSVfile = undef;
                   2246:         }
                   2247:         #
                   2248:         # Write headers and data to file
1.2       raeburn  2249:         print $CSVfile '"'.$results_description.'"'."\n"; 
1.1       raeburn  2250:         print $CSVfile '"'.join('","',map {
                   2251:             &Apache::loncommon::csv_translate($lt{$_})
                   2252:             } (@cols)).'"'."\n";
                   2253:     } elsif ($mode eq 'excel') {
                   2254:         # Create the excel spreadsheet
                   2255:         ($excel_workbook,$excel_filename,$format) =
                   2256:             &Apache::loncommon::create_workbook($r);
                   2257:         return if (! defined($excel_workbook));
                   2258:         $excel_sheet = $excel_workbook->addworksheet('userlist');
1.2       raeburn  2259:         $excel_sheet->write($row++,0,$results_description,$format->{'h2'});
1.1       raeburn  2260:         #
                   2261:         my @colnames = map {$lt{$_}} (@cols);
                   2262:         $excel_sheet->write($row++,0,\@colnames,$format->{'bold'});
                   2263:     }
                   2264: 
                   2265: # Done with header lines in all formats
                   2266:     my %index;
                   2267:     my $i;
1.2       raeburn  2268:     foreach my $idx (@$keylist) {
                   2269:         $index{$idx} = $i++;
                   2270:     }
1.4       raeburn  2271:     my $usercount = 0;
1.33      raeburn  2272:     my ($secfilter,$grpfilter);
                   2273:     if ($context eq 'course') {
                   2274:         $secfilter = $env{'form.secfilter'};
                   2275:         $grpfilter = $env{'form.grpfilter'};
                   2276:         if ($secfilter eq '') {
                   2277:             $secfilter = 'all';
                   2278:         }
                   2279:         if ($grpfilter eq '') {
                   2280:             $grpfilter = 'all';
                   2281:         }
                   2282:     }
1.2       raeburn  2283:     # Get groups, role, permanent e-mail so we can sort on them if
                   2284:     # necessary.
                   2285:     foreach my $user (keys(%{$userlist})) {
1.43      raeburn  2286:         if ($user eq '' ) {
                   2287:             delete($userlist->{$user});
                   2288:             next;
                   2289:         }
1.11      raeburn  2290:         if ($context eq 'domain' &&  $user eq $env{'request.role.domain'}.'-domainconfig:'.$env{'request.role.domain'}) {
                   2291:             delete($userlist->{$user});
                   2292:             next;
                   2293:         }
1.2       raeburn  2294:         my ($uname,$udom,$role,$groups,$email);
1.5       raeburn  2295:         if (($statusmode ne 'Any') && 
                   2296:                  ($userlist->{$user}->[$index{'status'}] ne $statusmode)) {
                   2297:             delete($userlist->{$user});
                   2298:             next;
                   2299:         }
1.2       raeburn  2300:         if ($context eq 'domain') {
                   2301:             if ($env{'form.roletype'} eq 'domain') {
                   2302:                 ($role,$uname,$udom) = split(/:/,$user);
1.11      raeburn  2303:                 if (($uname eq $env{'request.role.domain'}.'-domainconfig') &&
                   2304:                     ($udom eq $env{'request.role.domain'})) {
                   2305:                     delete($userlist->{$user});
                   2306:                     next;
                   2307:                 }
1.13      raeburn  2308:             } elsif ($env{'form.roletype'} eq 'author') {
1.2       raeburn  2309:                 ($uname,$udom,$role) = split(/:/,$user,-1);
                   2310:             } elsif ($env{'form.roletype'} eq 'course') {
                   2311:                 ($uname,$udom,$role) = split(/:/,$user);
                   2312:             }
                   2313:         } else {
                   2314:             ($uname,$udom,$role) = split(/:/,$user,-1);
                   2315:             if (($context eq 'course') && $role eq '') {
                   2316:                 $role = 'st';
                   2317:             }
                   2318:         }
                   2319:         $userlist->{$user}->[$index{'role'}] = $role;
                   2320:         if (($env{'form.showrole'} ne 'Any') && (!($env{'form.showrole'}  eq 'cr' && $role =~ /^cr\//)) && ($role ne $env{'form.showrole'})) {
                   2321:             delete($userlist->{$user});
                   2322:             next;
                   2323:         }
1.33      raeburn  2324:         if ($context eq 'course') {
                   2325:             my @ac_groups;
                   2326:             if (ref($classgroups) eq 'HASH') {
                   2327:                 $groups = $classgroups->{$user};
                   2328:             }
                   2329:             if (ref($groups->{'active'}) eq 'HASH') {
                   2330:                 @ac_groups = keys(%{$groups->{'active'}});
                   2331:                 $userlist->{$user}->[$index{'groups'}] = join(', ',@ac_groups);
                   2332:             }
                   2333:             if ($mode ne 'autoenroll') {
                   2334:                 my $section = $userlist->{$user}->[$index{'section'}];
1.43      raeburn  2335:                 if (($env{'request.course.sec'} ne '') && 
                   2336:                     ($section ne $env{'request.course.sec'})) {
                   2337:                     if ($role eq 'st') {
                   2338:                         delete($userlist->{$user});
                   2339:                         next;
                   2340:                     }
                   2341:                 }
1.33      raeburn  2342:                 if ($secfilter eq 'none') {
                   2343:                     if ($section ne '') {
                   2344:                         delete($userlist->{$user});
                   2345:                         next;
                   2346:                     }
                   2347:                 } elsif ($secfilter ne 'all') {
                   2348:                     if ($section ne $secfilter) {
                   2349:                         delete($userlist->{$user});
                   2350:                         next;
                   2351:                     }
                   2352:                 }
                   2353:                 if ($grpfilter eq 'none') {
                   2354:                     if (@ac_groups > 0) {
                   2355:                         delete($userlist->{$user});
                   2356:                         next;
                   2357:                     }
                   2358:                 } elsif ($grpfilter ne 'all') {
                   2359:                     if (!grep(/^\Q$grpfilter\E$/,@ac_groups)) {
                   2360:                         delete($userlist->{$user});
                   2361:                         next;
                   2362:                     }
                   2363:                 }
1.44      raeburn  2364:                 if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) {
                   2365:                     if (($displayphotos eq 'on') && ($role eq 'st')) {
                   2366:                         $userlist->{$user}->[$index{'photo'}] =
1.47      raeburn  2367:                             &Apache::lonnet::retrievestudentphoto($udom,$uname,'jpg');
                   2368:                         $userlist->{$user}->[$index{'thumbnail'}] =
1.44      raeburn  2369:                             &Apache::lonnet::retrievestudentphoto($udom,$uname,
                   2370:                                                                 'gif','thumbnail');
                   2371:                     }
                   2372:                 }
1.33      raeburn  2373:             }
1.2       raeburn  2374:         }
                   2375:         my %emails   = &Apache::loncommon::getemails($uname,$udom);
                   2376:         if ($emails{'permanentemail'} =~ /\S/) {
                   2377:             $userlist->{$user}->[$index{'email'}] = $emails{'permanentemail'};
                   2378:         }
1.4       raeburn  2379:         $usercount ++;
                   2380:     }
                   2381:     my $autocount = 0;
                   2382:     my $manualcount = 0;
                   2383:     my $lockcount = 0;
                   2384:     my $unlockcount = 0;
                   2385:     if ($usercount) {
                   2386:         $r->print($output);
                   2387:     } else {
                   2388:         if ($mode eq 'autoenroll') {
                   2389:             return ($usercount,$autocount,$manualcount,$lockcount,$unlockcount);
                   2390:         } else {
                   2391:             return;
                   2392:         }
1.1       raeburn  2393:     }
1.2       raeburn  2394:     #
                   2395:     # Sort the users
1.1       raeburn  2396:     my $index  = $index{$sortby};
                   2397:     my $second = $index{'username'};
                   2398:     my $third  = $index{'domain'};
1.2       raeburn  2399:     my @sorted_users = sort {
                   2400:         lc($userlist->{$a}->[$index])  cmp lc($userlist->{$b}->[$index])
1.1       raeburn  2401:             ||
1.2       raeburn  2402:         lc($userlist->{$a}->[$second]) cmp lc($userlist->{$b}->[$second])            ||
                   2403:         lc($userlist->{$a}->[$third]) cmp lc($userlist->{$b}->[$third])
                   2404:         } (keys(%$userlist));
1.4       raeburn  2405:     my $rowcount = 0;
1.2       raeburn  2406:     foreach my $user (@sorted_users) {
1.4       raeburn  2407:         my %in;
1.2       raeburn  2408:         my $sdata = $userlist->{$user};
1.4       raeburn  2409:         $rowcount ++; 
1.2       raeburn  2410:         foreach my $item (@{$keylist}) {
                   2411:             $in{$item} = $sdata->[$index{$item}];
                   2412:         }
1.11      raeburn  2413:         my $role = $in{'role'};
1.2       raeburn  2414:         $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}]); 
                   2415:         if (! defined($in{'start'}) || $in{'start'} == 0) {
                   2416:             $in{'start'} = &mt('none');
                   2417:         } else {
                   2418:             $in{'start'} = &Apache::lonlocal::locallocaltime($in{'start'});
1.1       raeburn  2419:         }
1.2       raeburn  2420:         if (! defined($in{'end'}) || $in{'end'} == 0) {
                   2421:             $in{'end'} = &mt('none');
1.1       raeburn  2422:         } else {
1.2       raeburn  2423:             $in{'end'} = &Apache::lonlocal::locallocaltime($in{'end'});
1.1       raeburn  2424:         }
1.2       raeburn  2425:         if ($mode eq 'view' || $mode eq 'html' || $mode eq 'autoenroll') {
                   2426:             $r->print(&Apache::loncommon::start_data_table_row());
1.11      raeburn  2427:             my $checkval;
1.16      raeburn  2428:             if ($mode eq 'autoenroll') {
                   2429:                 my $cellentry;
                   2430:                 if ($in{'type'} eq 'auto') {
                   2431:                     $cellentry = '<b>'.&mt('auto').'</b>&nbsp;<label><input type="checkbox" name="chgauto" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;Change</label>';
                   2432:                     $autocount ++;
                   2433:                 } else {
                   2434:                     $cellentry = '<table border="0" cellspacing="0"><tr><td rowspan="2"><b>'.&mt('manual').'</b></td><td><nobr><label><input type="checkbox" name="chgmanual" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;Change</label></nobr></td></tr><tr><td><nobr>';
                   2435:                     $manualcount ++;
                   2436:                     if ($in{'lockedtype'}) {
                   2437:                         $cellentry .= '<label><input type="checkbox" name="unlockchg" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Unlock').'</label>';
                   2438:                         $unlockcount ++;
                   2439:                     } else {
                   2440:                         $cellentry .= '<label><input type="checkbox" name="lockchg" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Lock').'</label>';
                   2441:                         $lockcount ++;
1.11      raeburn  2442:                     }
1.16      raeburn  2443:                     $cellentry .= '</nobr></td></tr></table>';
                   2444:                 }
                   2445:                 $r->print("<td>$cellentry</td>\n");
                   2446:             } else {
                   2447:                 $r->print("<td>$rowcount</td>\n");
                   2448:                 if ($actionselect) {
1.26      raeburn  2449:                     my $showcheckbox;
                   2450:                     if ($role =~ /^cr\//) {
                   2451:                         $showcheckbox = $canchange{'cr'};
                   2452:                     } else {
                   2453:                         $showcheckbox = $canchange{$role};
                   2454:                     }
                   2455:                     if (!$showcheckbox) {
                   2456:                         if ($context eq 'course') {
                   2457:                             if ($canchangesec{$role} ne '') {
                   2458:                                 if ($canchangesec{$role} eq $in{'section'}) {
                   2459:                                     $showcheckbox = 1;
                   2460:                                 }
                   2461:                             }
1.16      raeburn  2462:                         }
1.26      raeburn  2463:                     }
                   2464:                     if ($showcheckbox) {
                   2465:                         $checkval = $user; 
                   2466:                         if ($context eq 'course') {
                   2467:                             if ($role eq 'st') {
                   2468:                                 $checkval .= ':st';
                   2469:                             }
                   2470:                             $checkval .= ':'.$in{'section'};
                   2471:                             if ($role eq 'st') {
                   2472:                                 $checkval .= ':'.$in{'type'}.':'.
                   2473:                                              $in{'lockedtype'};
                   2474:                             }
1.16      raeburn  2475:                         }
1.26      raeburn  2476:                         $r->print('<td><input type="checkbox" name="'.
                   2477:                                   'actionlist" value="'.$checkval.'"></td>');
                   2478:                     } else {
                   2479:                         $r->print('<td>&nbsp;</td>');
1.16      raeburn  2480:                     }
1.11      raeburn  2481:                 }
                   2482:             }
1.2       raeburn  2483:             foreach my $item (@cols) {
1.10      raeburn  2484:                 if ($item eq 'username') {
1.48      raeburn  2485:                     $r->print('<td>'.&print_username_link($mode,\%in).'</td>');
1.16      raeburn  2486:                 } elsif (($item eq 'start' || $item eq 'end') && ($actionselect)) {
1.11      raeburn  2487:                     $r->print('<td>'.$in{$item}.'<input type="hidden" name="'.$checkval.'_'.$item.'" value="'.$sdata->[$index{$item}].'" /></td>'."\n");
1.10      raeburn  2488:                 } else {
                   2489:                     $r->print('<td>'.$in{$item}.'</td>'."\n");
                   2490:                 }
1.2       raeburn  2491:             }
1.16      raeburn  2492:             if (($context eq 'course') && ($mode ne 'autoenroll')) {
1.4       raeburn  2493:                 if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') {
                   2494:                     if ($displayclickers eq 'on') {
                   2495:                         my $clickers =
1.2       raeburn  2496:                    (&Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers'))[1];
1.4       raeburn  2497:                         if ($clickers!~/\w/) { $clickers='-'; }
                   2498:                         $r->print('<td>'.$clickers.'</td>');
1.2       raeburn  2499:                     } else {
                   2500:                         $r->print('    <td>&nbsp;</td>  ');
                   2501:                     }
1.4       raeburn  2502:                     if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) {
1.44      raeburn  2503:                         if ($displayphotos eq 'on' && $role eq 'st' && $in{'photo'} ne '') {
1.47      raeburn  2504:                             $r->print('    <td align="right"><a href="javascript:photowindow('."'".$in{'photo'}."'".')"><img src="'.$in{'thumbnail'}.'" border="1"></a></td>');
1.4       raeburn  2505:                         } else {
                   2506:                             $r->print('    <td>&nbsp;</td>  ');
                   2507:                         }
                   2508:                     }
1.2       raeburn  2509:                 }
                   2510:             }
                   2511:             $r->print(&Apache::loncommon::end_data_table_row());
                   2512:         } elsif ($mode eq 'csv') {
                   2513:             next if (! defined($CSVfile));
                   2514:             # no need to bother with $linkto
                   2515:             if (! defined($in{'start'}) || $in{'start'} == 0) {
                   2516:                 $in{'start'} = &mt('none');
                   2517:             } else {
                   2518:                 $in{'start'} = &Apache::lonlocal::locallocaltime($in{'start'});
                   2519:             }
                   2520:             if (! defined($in{'end'}) || $in{'end'} == 0) {
                   2521:                 $in{'end'} = &mt('none');
                   2522:             } else {
                   2523:                 $in{'end'} = &Apache::lonlocal::locallocaltime($in{'end'});
                   2524:             }
                   2525:             my @line = ();
                   2526:             foreach my $item (@cols) {
                   2527:                 push @line,&Apache::loncommon::csv_translate($in{$item});
                   2528:             }
                   2529:             print $CSVfile '"'.join('","',@line).'"'."\n";
                   2530:         } elsif ($mode eq 'excel') {
                   2531:             my $col = 0;
                   2532:             foreach my $item (@cols) {
                   2533:                 if ($item eq 'start' || $item eq 'end') {
                   2534:                     if (defined($item) && $item != 0) {
                   2535:                         $excel_sheet->write($row,$col++,
                   2536:                             &Apache::lonstathelpers::calc_serial($in{item}),
                   2537:                                     $format->{'date'});
                   2538:                     } else {
                   2539:                         $excel_sheet->write($row,$col++,'none');
                   2540:                     }
                   2541:                 } else {
                   2542:                     $excel_sheet->write($row,$col++,$in{$item});
                   2543:                 }
                   2544:             }
                   2545:             $row++;
1.1       raeburn  2546:         }
                   2547:     }
1.2       raeburn  2548:     if ($mode eq 'view' || $mode eq 'html' || $mode eq 'autoenroll') {
                   2549:             $r->print(&Apache::loncommon::end_data_table().'<br />');
                   2550:     } elsif ($mode eq 'excel') {
                   2551:         $excel_workbook->close();
                   2552:         $r->print('<p><a href="'.$excel_filename.'">'.
                   2553:                   &mt('Your Excel spreadsheet').'</a> '.&mt('is ready for download').'.</p>'."\n");
                   2554:     } elsif ($mode eq 'csv') {
                   2555:         close($CSVfile);
                   2556:         $r->print('<a href="'.$CSVfilename.'">'.
                   2557:                   &mt('Your CSV file').'</a> is ready for download.'.
                   2558:                   "\n");
                   2559:         $r->rflush();
                   2560:     }
                   2561:     if ($mode eq 'autoenroll') {
                   2562:         return ($usercount,$autocount,$manualcount,$lockcount,$unlockcount);
1.4       raeburn  2563:     } else {
                   2564:         return ($usercount);
1.2       raeburn  2565:     }
1.1       raeburn  2566: }
                   2567: 
1.10      raeburn  2568: sub print_username_link {
1.48      raeburn  2569:     my ($mode,$in) = @_;
1.10      raeburn  2570:     my $output;
1.16      raeburn  2571:     if ($mode eq 'autoenroll') {
                   2572:         $output = $in->{'username'};
1.10      raeburn  2573:     } else {
                   2574:         $output = '<a href="javascript:username_display_launch('.
                   2575:                   "'$in->{'username'}','$in->{'domain'}'".')" />'.
                   2576:                   $in->{'username'}.'</a>';
                   2577:     }
                   2578:     return $output;
                   2579: }
                   2580: 
1.2       raeburn  2581: sub role_type_names {
                   2582:     my %lt = &Apache::lonlocal::texthash (
1.13      raeburn  2583:                          'domain' => 'Domain Roles',
                   2584:                          'author' => 'Co-Author Roles',
                   2585:                          'course' => 'Course Roles',
1.2       raeburn  2586:              );
                   2587:     return %lt;
                   2588: }
                   2589: 
1.11      raeburn  2590: sub select_actions {
                   2591:     my ($context,$setting,$statusmode) = @_;
                   2592:     my %lt = &Apache::lonlocal::texthash(
                   2593:                 revoke   => "Revoke user roles",
                   2594:                 delete   => "Delete user roles",
                   2595:                 reenable => "Re-enable expired user roles",
                   2596:                 activate => "Make future user roles active now",
                   2597:                 chgdates  => "Change starting/ending dates",
                   2598:                 chgsec   => "Change section associated with user roles",
                   2599:     );
                   2600:     my ($output,$options,%choices);
1.23      raeburn  2601:     # FIXME Disable actions for now for roletype=course in domain context
                   2602:     if ($context eq 'domain' && $setting eq 'course') {
                   2603:         return;
                   2604:     }
1.26      raeburn  2605:     if ($context eq 'course') {
                   2606:         if ($env{'form.showrole'} ne 'Any') {
                   2607:              if (!&Apache::lonnet::allowed('c'.$env{'form.showrole'},
                   2608:                                            $env{'request.course.id'})) {
                   2609:                  if ($env{'request.course.sec'} eq '') {
                   2610:                      return;
                   2611:                  } else {
                   2612:                      if (!&Apache::lonnet::allowed('c'.$env{'form.showrole'},$env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
                   2613:                          return;
                   2614:                      }
                   2615:                  }
                   2616:             }
                   2617:         }
                   2618:     }
1.11      raeburn  2619:     if ($statusmode eq 'Any') {
                   2620:         $options .= '
                   2621: <option value="chgdates">'.$lt{'chgdates'}.'</option>';
                   2622:         $choices{'dates'} = 1;
                   2623:     } else {
                   2624:         if ($statusmode eq 'Future') {
                   2625:             $options .= '
                   2626: <option value="activate">'.$lt{'activate'}.'</option>';
                   2627:             $choices{'dates'} = 1;
                   2628:         } elsif ($statusmode eq 'Expired') {
                   2629:             $options .= '
                   2630: <option value="reenable">'.$lt{'reenable'}.'</option>';
                   2631:             $choices{'dates'} = 1;
                   2632:         }
1.13      raeburn  2633:         if ($statusmode eq 'Active' || $statusmode eq 'Future') {
                   2634:             $options .= '
                   2635: <option value="chgdates">'.$lt{'chgdates'}.'</option>
                   2636: <option value="revoke">'.$lt{'revoke'}.'</option>';
                   2637:             $choices{'dates'} = 1;
                   2638:         }
1.11      raeburn  2639:     }
                   2640:     if ($context eq 'domain') {
                   2641:         $options .= '
                   2642: <option value="delete">'.$lt{'delete'}.'</option>';
                   2643:     }
                   2644:     if (($context eq 'course') || ($context eq 'domain' && $setting eq 'course')) {
1.26      raeburn  2645:         if (($statusmode ne 'Expired') && ($env{'request.course.sec'} eq '')) {
1.11      raeburn  2646:             $options .= '
                   2647: <option value="chgsec">'.$lt{'chgsec'}.'</option>';
                   2648:             $choices{'sections'} = 1;
                   2649:         }
                   2650:     }
                   2651:     if ($options) {
1.41      raeburn  2652:         $output = '<select name="bulkaction" onchange="javascript:opendatebrowser(this.form,'."'studentform','change'".')" />'."\n".
1.11      raeburn  2653:                   '<option value="" selected="selected">'.
                   2654:                   &mt('Please select').'</option>'."\n".$options."\n".'</select>';
                   2655:         if ($choices{'dates'}) {
                   2656:             $output .= 
                   2657:                 '<input type="hidden" name="startdate_month" value="" />'."\n".
                   2658:                 '<input type="hidden" name="startdate_day" value="" />'."\n".
                   2659:                 '<input type="hidden" name="startdate_year" value="" />'."\n".
                   2660:                 '<input type="hidden" name="startdate_hour" value="" />'."\n".
                   2661:                 '<input type="hidden" name="startdate_minute" value="" />'."\n".
                   2662:                 '<input type="hidden" name="startdate_second" value="" />'."\n".
                   2663:                 '<input type="hidden" name="enddate_month" value="" />'."\n".
                   2664:                 '<input type="hidden" name="enddate_day" value="" />'."\n".
                   2665:                 '<input type="hidden" name="enddate_year" value="" />'."\n".
                   2666:                 '<input type="hidden" name="enddate_hour" value="" />'."\n".
                   2667:                 '<input type="hidden" name="enddate_minute" value="" />'."\n".
                   2668:                 '<input type="hidden" name="enddate_second" value="" />'."\n";
                   2669:             if ($context eq 'course') {
                   2670:                 $output .= '<input type="hidden" name="makedatesdefault" value="" />'."\n";
                   2671:             }
                   2672:         }
                   2673:         if ($choices{'sections'}) {
                   2674:             $output .= '<input type="hidden" name="retainsec" value= "" />'."\n".
                   2675:                        '<input type="hidden" name="newsecs" value= "" />'."\n";
                   2676:         }
                   2677:     }
                   2678:     return $output;
                   2679: }
                   2680: 
                   2681: sub date_section_javascript {
                   2682:     my ($context,$setting) = @_;
1.49      raeburn  2683:     my $title = 'Date_And_Section_Selector';
1.41      raeburn  2684:     my %nopopup = &Apache::lonlocal::texthash (
                   2685:         revoke => "Check the boxes for any users for whom roles are to be revoked, and click 'Proceed'",
                   2686:         delete => "Check the boxes for any users for whom roles are to be deleted, and click 'Proceed'",
                   2687:         none   => "Choose an action to take for selected users",
                   2688:     );  
1.11      raeburn  2689:     my $output = '
1.49      raeburn  2690: <script type="text/javascript">'."\n";
1.11      raeburn  2691:     $output .= <<"ENDONE";
1.41      raeburn  2692:     function opendatebrowser(callingform,formname,calledby) {
1.11      raeburn  2693:         var bulkaction = callingform.bulkaction.options[callingform.bulkaction.selectedIndex].value;
                   2694:         if (bulkaction == 'revoke' || bulkaction == 'delete' || bulkaction == '') {
1.41      raeburn  2695:             if (calledby == 'go') {
                   2696:                 if (bulkaction == 'revoke') {
                   2697:                     alert("$nopopup{'revoke'}");
                   2698:                 }
                   2699:                 if (bulkaction == 'delete') {
                   2700:                     alert("$nopopup{'delete'}"); 
                   2701:                 }
                   2702:                 if (bulkaction == '') {
                   2703:                     alert("$nopopup{'none'}");
                   2704:                 }
                   2705:             }
1.11      raeburn  2706:             return;
                   2707:         }
                   2708:         var url = '/adm/createuser?';
                   2709:         var type = '';
                   2710:         var showrole = callingform.showrole.options[callingform.showrole.selectedIndex].value;
                   2711: ENDONE
                   2712:     if ($context eq 'domain') {
                   2713:         $output .= '
                   2714:         type = callingform.roletype.options[callingform.roletype.selectedIndex].value;
                   2715: ';
                   2716:     }
                   2717:     my $width= '700';
                   2718:     my $height = '400';
                   2719:     $output .= <<"ENDTWO";
                   2720:         url += 'action=dateselect&callingform=' + formname + 
                   2721:                '&roletype='+type+'&showrole='+showrole +'&bulkaction='+bulkaction;
                   2722:         var title = '$title';
                   2723:         var options = 'scrollbars=1,resizable=1,menubar=0';
                   2724:         options += ',width=$width,height=$height';
                   2725:         stdeditbrowser = open(url,title,options,'1');
                   2726:         stdeditbrowser.focus();
                   2727:     }
                   2728: </script>
                   2729: ENDTWO
                   2730:     return $output;
                   2731: }
                   2732: 
                   2733: sub date_section_selector {
1.21      raeburn  2734:     my ($context,$permission) = @_;
1.11      raeburn  2735:     my $callingform = $env{'form.callingform'};
                   2736:     my $formname = 'dateselect';  
                   2737:     my $groupslist = &get_groupslist();
                   2738:     my $sec_js = &setsections_javascript($formname,$groupslist);
                   2739:     my $output = <<"END";
                   2740: <script type="text/javascript">
                   2741: 
                   2742: $sec_js
                   2743: 
                   2744: function saveselections(formname) {
                   2745: 
                   2746: END
                   2747:     if ($env{'form.bulkaction'} eq 'chgsec') {
                   2748:         $output .= <<"END";
1.40      raeburn  2749:         if (formname.retainsec.length > 1) {  
                   2750:             for (var i=0; i<formname.retainsec.length; i++) {
                   2751:                 if (formname.retainsec[i].checked == true) {
                   2752:                     opener.document.$callingform.retainsec.value = formname.retainsec[i].value;
                   2753:                 }
                   2754:             }
                   2755:         } else {
                   2756:             opener.document.$callingform.retainsec.value = formname.retainsec.value;
                   2757:         }
1.11      raeburn  2758:         setSections(formname);
                   2759:         if (seccheck == 'ok') {
                   2760:             opener.document.$callingform.newsecs.value = formname.sections.value;
                   2761:             window.close();
                   2762:         }
                   2763:         return;
                   2764: END
                   2765:     } else {
                   2766:         if ($context eq 'course') {
                   2767:             if (($env{'form.bulkaction'} eq 'reenable') || 
                   2768:                 ($env{'form.bulkaction'} eq 'activate') || 
                   2769:                 ($env{'form.bulkaction'} eq 'chgdates')) {
1.26      raeburn  2770:                 if ($env{'request.course.sec'} eq '') {
                   2771:                     $output .= <<"END";
1.11      raeburn  2772:  
                   2773:         if (formname.makedatesdefault.checked == true) {
                   2774:             opener.document.$callingform.makedatesdefault.value = 1;
                   2775:         }
                   2776:         else {
                   2777:             opener.document.$callingform.makedatesdefault.value = 0;
                   2778:         }
                   2779: 
                   2780: END
1.26      raeburn  2781:                 }
1.11      raeburn  2782:             }
                   2783:         }
                   2784:         $output .= <<"END";
                   2785:     opener.document.$callingform.startdate_month.value =  formname.startdate_month.options[formname.startdate_month.selectedIndex].value;
                   2786:     opener.document.$callingform.startdate_day.value =  formname.startdate_day.value;
                   2787:     opener.document.$callingform.startdate_year.value = formname.startdate_year.value;
                   2788:     opener.document.$callingform.startdate_hour.value =  formname.startdate_hour.options[formname.startdate_hour.selectedIndex].value;
                   2789:     opener.document.$callingform.startdate_minute.value =  formname.startdate_minute.value;
                   2790:     opener.document.$callingform.startdate_second.value = formname.startdate_second.value;
                   2791:     opener.document.$callingform.enddate_month.value =  formname.enddate_month.options[formname.enddate_month.selectedIndex].value;
                   2792:     opener.document.$callingform.enddate_day.value =  formname.enddate_day.value;
                   2793:     opener.document.$callingform.enddate_year.value = formname.enddate_year.value;
                   2794:     opener.document.$callingform.enddate_hour.value =  formname.enddate_hour.options[formname.enddate_hour.selectedIndex].value;
                   2795:     opener.document.$callingform.enddate_minute.value =  formname.enddate_minute.value;
                   2796:     opener.document.$callingform.enddate_second.value = formname.enddate_second.value;
                   2797:     window.close();
                   2798: END
                   2799:     }
                   2800:     $output .= '
                   2801: }
                   2802: </script>
                   2803: ';
                   2804:     my %lt = &Apache::lonlocal::texthash (
                   2805:                  chac => 'Access dates to apply for selected users',
                   2806:                  chse => 'Changes in section affiliation to apply to selected users',
                   2807:                  fors => 'For student roles changing the section, will result in a section switch as students may only be in one section of a course at a time.',
                   2808:                  forn => 'For a role in a course that is not a student role, a user may have roles in more than one section of a course at a time.',
                   2809:                  reta => "Retain each user's current section affiliations?", 
                   2810:                  dnap => '(Does not apply to student roles).', 
                   2811:             );
                   2812:     my ($date_items,$headertext);
                   2813:     if ($env{'form.bulkaction'} eq 'chgsec') {
                   2814:         $headertext = $lt{'chse'};
                   2815:     } else {
                   2816:         $headertext = $lt{'chac'};
                   2817:         my $starttime;
                   2818:         if (($env{'form.bulkaction'} eq 'activate') || 
                   2819:             ($env{'form.bulkaction'} eq 'reenable')) {
                   2820:             $starttime = time;
                   2821:         }
                   2822:         $date_items = &date_setting_table($starttime,undef,$context,
1.21      raeburn  2823:                                           $env{'form.bulkaction'},$formname,
                   2824:                                           $permission);
1.11      raeburn  2825:     }
                   2826:     $output .= '<h3>'.$headertext.'</h3>'.
                   2827:                '<form name="'.$formname.'" method="post">'."\n".
                   2828:                 $date_items;
                   2829:     if ($context eq 'course' && $env{'form.bulkaction'} eq 'chgsec') {
1.17      raeburn  2830:         my ($cnum,$cdom) = &get_course_identity();
1.11      raeburn  2831:         my $info;
                   2832:         if ($env{'form.showrole'} eq 'st') {
                   2833:             $output .= '<p>'.$lt{'fors'}.'</p>'; 
1.26      raeburn  2834:         } elsif ($env{'form.showrole'} eq 'Any') {
1.11      raeburn  2835:             $output .= '<p>'.$lt{'fors'}.'</p>'.
                   2836:                        '<p>'.$lt{'forn'}.'&nbsp;';
                   2837:             $info = $lt{'reta'};
                   2838:         } else {
                   2839:             $output .= '<p>'.$lt{'forn'}.'&nbsp;';
                   2840:             $info = $lt{'reta'};
                   2841:         }
                   2842:         if ($info) {
                   2843:             $info .= '<span class="LC_nobreak">'.
                   2844:                      '<label><input type="radio" name="retainsec" value="1" '.
                   2845:                      'checked="checked" />'.&mt('Yes').'</label>&nbsp;&nbsp;'.
                   2846:                      '<label><input type="radio" name="retainsec" value="0" />'.
                   2847:                      &mt('No').'</label></span>';
                   2848:             if ($env{'form.showrole'} eq 'Any') {
                   2849:                 $info .= '<br />'.$lt{'dnap'};
                   2850:             }
                   2851:             $info .= '</p>';
                   2852:         } else {
                   2853:             $info = '<input type="hidden" name="retainsec" value="0" />'; 
                   2854:         }
1.21      raeburn  2855:         my $rowtitle = &mt('New section to assign');
                   2856:         my $secbox = &section_picker($cdom,$cnum,$env{'form.showrole'},$rowtitle,$permission,$context);
1.11      raeburn  2857:         $output .= $info.$secbox;
                   2858:     }
                   2859:     $output .= '<p>'.
                   2860: &mt('Use "Save" to update the main window with your selections.').'<br /><br />'.
                   2861: '<input type="button" name="dateselection" value="'.&mt('Save').'" onclick="javascript:saveselections(this.form)" /></p>'."\n".
                   2862: '</form>';
                   2863:     return $output;
                   2864: }
                   2865: 
1.17      raeburn  2866: sub section_picker {
                   2867:     my ($cdom,$cnum,$role,$rowtitle,$permission,$context,$mode) = @_;
                   2868:     my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum);
                   2869:     my $sections_select .= &course_sections(\%sections_count,$role);
                   2870:     my $secbox = '<p>'.&Apache::lonhtmlcommon::start_pick_box()."\n";
                   2871:     if ($mode eq 'upload') {
                   2872:         my ($options,$cb_script,$coursepick) =
                   2873:             &default_role_selector($context,1);
                   2874:         $secbox .= &Apache::lonhtmlcommon::row_title('role','LC_oddrow_value').
                   2875:                    $options. &Apache::lonhtmlcommon::row_closure(1)."\n";
                   2876:     }
                   2877:     $secbox .= &Apache::lonhtmlcommon::row_title($rowtitle,'LC_oddrow_value')."\n";
                   2878:     if ($env{'request.course.sec'} eq '') {
                   2879:         $secbox .= '<table class="LC_createuser"><tr class="LC_section_row">'."\n".
                   2880:                    '<td align="center">'.&mt('Existing sections')."\n".
                   2881:                    '<br />'.$sections_select.'</td><td align="center">'.
                   2882:                    &mt('New section').'<br />'."\n".
                   2883:                    '<input type="text" name="newsec" size="15" />'."\n".
                   2884:                    '<input type="hidden" name="sections" value="" />'."\n".
                   2885:                    '</td></tr></table>'."\n";
                   2886:     } else {
                   2887:        $secbox .= '<input type="hidden" name="sections" value="'.
                   2888:                    $env{'request.course.sec'}.'" />'.
                   2889:                    $env{'request.course.sec'};
                   2890:     }
                   2891:     $secbox .= &Apache::lonhtmlcommon::row_closure(1)."\n".
                   2892:                &Apache::lonhtmlcommon::end_pick_box().'</p>';
                   2893:     return $secbox;
                   2894: }
                   2895: 
1.2       raeburn  2896: sub results_header_row {
1.24      raeburn  2897:     my ($rolefilter,$statusmode,$context,$permission,$mode) = @_;
1.5       raeburn  2898:     my ($description,$showfilter);
                   2899:     if ($rolefilter ne 'Any') {
                   2900:         $showfilter = $rolefilter;
                   2901:     }
1.2       raeburn  2902:     if ($context eq 'course') {
1.24      raeburn  2903:         if ($mode eq 'csv' || $mode eq 'excel') {
                   2904:             $description = &mt('Course - ').$env{'course.'.$env{'request.course.id'}.'.description'}.': ';
                   2905:         }
1.2       raeburn  2906:         if ($statusmode eq 'Expired') {
1.5       raeburn  2907:             $description .= &mt('Users in course with expired [_1] roles',$showfilter);
1.11      raeburn  2908:         } elsif ($statusmode eq 'Future') {
1.5       raeburn  2909:             $description .= &mt('Users in course with future [_1] roles',$showfilter);
1.2       raeburn  2910:         } elsif ($statusmode eq 'Active') {
1.5       raeburn  2911:             $description .= &mt('Users in course with active [_1] roles',$showfilter);
1.2       raeburn  2912:         } else {
                   2913:             if ($rolefilter eq 'Any') {
                   2914:                 $description .= &mt('All users in course');
                   2915:             } else {
                   2916:                 $description .= &mt('All users in course with [_1] roles',$rolefilter);
                   2917:             }
                   2918:         }
1.33      raeburn  2919:         my $constraint;
1.26      raeburn  2920:         my $viewablesec = &viewable_section($permission);
                   2921:         if ($viewablesec ne '') {
1.15      raeburn  2922:             if ($env{'form.showrole'} eq 'st') {
1.33      raeburn  2923:                 $constraint = &mt('only users in section "[_1]"',$viewablesec);
1.26      raeburn  2924:             } elsif ($env{'form.showrole'} ne 'cc') {
1.33      raeburn  2925:                 $constraint = &mt('only users affiliated with no section or section "[_1]"',$viewablesec);
                   2926:             }
                   2927:             if (($env{'form.grpfilter'} ne 'all') && ($env{'form.grpfilter'} ne '')) {
                   2928:                 if ($env{'form.grpfilter'} eq 'none') {
                   2929:                     $constraint .= &mt(' and not in any group');
                   2930:                 } else {
                   2931:                     $constraint .= &mt(' and members of group: "[_1]"',$env{'form.grpfilter'});
                   2932:                 }
                   2933:             }
                   2934:         } else {
                   2935:             if (($env{'form.secfilter'} ne 'all') && ($env{'form.secfilter'} ne '')) {
                   2936:                 if ($env{'form.secfilter'} eq 'none') {
                   2937:                     $constraint = &mt('only users affiliated with no section');
                   2938:                 } else {
                   2939:                     $constraint = &mt('only users affiliated with section "[_1]"',$env{'form.secfilter'});
                   2940:                 }
                   2941:             }
                   2942:             if (($env{'form.grpfilter'} ne 'all') && ($env{'form.grpfilter'} ne '')) {
                   2943:                 if ($env{'form.grpfilter'} eq 'none') {
                   2944:                     if ($constraint eq '') {
                   2945:                         $constraint = &mt('only users not in any group');
                   2946:                     } else {
                   2947:                         $constraint .= &mt(' and also not in any group'); 
                   2948:                     }
                   2949:                 } else {
                   2950:                     if ($constraint eq '') {
                   2951:                         $constraint = &mt('only members of group: "[_1]"',$env{'form.grpfilter'});
                   2952:                     } else {
                   2953:                         $constraint .= &mt(' and also members of group: "[_1]"'.$env{'form.grpfilter'});
                   2954:                     }
                   2955:                 }
1.15      raeburn  2956:             }
                   2957:         }
1.33      raeburn  2958:         if ($constraint ne '') {
                   2959:             $description .= ' ('.$constraint.')';
                   2960:         } 
1.13      raeburn  2961:     } elsif ($context eq 'author') {
1.14      raeburn  2962:         $description = 
                   2963:             &mt('Author space for <span class="LC_cusr_emph">[_1]</span>',
                   2964:         &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'})).':&nbsp;&nbsp;';
1.2       raeburn  2965:         if ($statusmode eq 'Expired') {
1.5       raeburn  2966:             $description .= &mt('Co-authors with expired [_1] roles',$showfilter);
1.2       raeburn  2967:         } elsif ($statusmode eq 'Future') {
1.5       raeburn  2968:             $description .= &mt('Co-authors with future [_1] roles',$showfilter);
1.2       raeburn  2969:         } elsif ($statusmode eq 'Active') {
1.5       raeburn  2970:             $description .= &mt('Co-authors with active [_1] roles',$showfilter);
1.2       raeburn  2971:         } else {
                   2972:             if ($rolefilter eq 'Any') {
1.5       raeburn  2973:                 $description .= &mt('All co-authors');
1.2       raeburn  2974:             } else {
                   2975:                 $description .= &mt('All co-authors with [_1] roles',$rolefilter);
                   2976:             }
                   2977:         }
                   2978:     } elsif ($context eq 'domain') {
                   2979:         my $domdesc = &Apache::lonnet::domain($env{'request.role.domain'},'description');
                   2980:         $description = &mt('Domain - ').$domdesc.': ';
                   2981:         if ($env{'form.roletype'} eq 'domain') {
                   2982:             if ($statusmode eq 'Expired') {
1.5       raeburn  2983:                 $description .= &mt('Users in domain with expired [_1] roles',$showfilter);
1.2       raeburn  2984:             } elsif ($statusmode eq 'Future') {
1.5       raeburn  2985:                 $description .= &mt('Users in domain with future [_1] roles',$showfilter);
1.2       raeburn  2986:             } elsif ($statusmode eq 'Active') {
1.5       raeburn  2987:                 $description .= &mt('Users in domain with active [_1] roles',$showfilter);
1.2       raeburn  2988:             } else {
                   2989:                 if ($rolefilter eq 'Any') {
1.5       raeburn  2990:                     $description .= &mt('All users in domain');
1.2       raeburn  2991:                 } else {
                   2992:                     $description .= &mt('All users in domain with [_1] roles',$rolefilter);
                   2993:                 }
                   2994:             }
1.13      raeburn  2995:         } elsif ($env{'form.roletype'} eq 'author') {
1.2       raeburn  2996:             if ($statusmode eq 'Expired') {
1.5       raeburn  2997:                 $description .= &mt('Co-authors in domain with expired [_1] roles',$showfilter);
1.2       raeburn  2998:             } elsif ($statusmode eq 'Future') {
1.5       raeburn  2999:                 $description .= &mt('Co-authors in domain with future [_1] roles',$showfilter);
1.2       raeburn  3000:             } elsif ($statusmode eq 'Active') {
1.5       raeburn  3001:                $description .= &mt('Co-authors in domain with active [_1] roles',$showfilter);
1.2       raeburn  3002:             } else {
                   3003:                 if ($rolefilter eq 'Any') {
1.5       raeburn  3004:                     $description .= &mt('All users with co-author roles in domain',$showfilter);
1.2       raeburn  3005:                 } else {
                   3006:                     $description .= &mt('All co-authors in domain  with [_1] roles',$rolefilter);
                   3007:                 }
                   3008:             }
                   3009:         } elsif ($env{'form.roletype'} eq 'course') {
                   3010:             my $coursefilter = $env{'form.coursepick'};
                   3011:             if ($coursefilter eq 'category') {
                   3012:                 my $instcode = &instcode_from_coursefilter();
                   3013:                 if ($instcode eq '.') {
                   3014:                     $description .= &mt('All courses in domain').' - ';
                   3015:                 } else {
                   3016:                     $description .= &mt('Courses in domain with institutional code: [_1]',$instcode).' - ';
                   3017:                 }
                   3018:             } elsif ($coursefilter eq 'selected') {
                   3019:                 $description .= &mt('Selected courses in domain').' - ';
                   3020:             } elsif ($coursefilter eq 'all') {
                   3021:                 $description .= &mt('All courses in domain').' - ';
                   3022:             }
                   3023:             if ($statusmode eq 'Expired') {
1.5       raeburn  3024:                 $description .= &mt('users with expired [_1] roles',$showfilter);
1.2       raeburn  3025:             } elsif ($statusmode eq 'Future') {
1.5       raeburn  3026:                 $description .= &mt('users with future [_1] roles',$showfilter);
1.2       raeburn  3027:             } elsif ($statusmode eq 'Active') {
1.5       raeburn  3028:                 $description .= &mt('users with active [_1] roles',$showfilter);
1.2       raeburn  3029:             } else {
                   3030:                 if ($rolefilter eq 'Any') {
                   3031:                     $description .= &mt('all users');
                   3032:                 } else {
                   3033:                     $description .= &mt('users with [_1] roles',$rolefilter);
                   3034:                 }
                   3035:             }
                   3036:         }
                   3037:     }
                   3038:     return $description;
                   3039: }
1.22      raeburn  3040: 
                   3041: sub viewable_section {
                   3042:     my ($permission) = @_;
                   3043:     my $viewablesec;
                   3044:     if (ref($permission) eq 'HASH') {
                   3045:         if (exists($permission->{'view_section'})) {
                   3046:             $viewablesec = $permission->{'view_section'};
                   3047:         } elsif (exists($permission->{'cusr_section'})) {
                   3048:             $viewablesec = $permission->{'cusr_section'};
                   3049:         }
                   3050:     }
                   3051:     return $viewablesec;
                   3052: }
                   3053: 
1.2       raeburn  3054:     
1.1       raeburn  3055: #################################################
                   3056: #################################################
                   3057: sub show_drop_list {
1.30      raeburn  3058:     my ($r,$classlist,$nosort,$permission) = @_;
1.29      raeburn  3059:     my $cid = $env{'request.course.id'};
1.17      raeburn  3060:     my ($cnum,$cdom) = &get_course_identity($cid);
1.1       raeburn  3061:     if (! exists($env{'form.sortby'})) {
                   3062:         &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                   3063:                                                 ['sortby']);
                   3064:     }
                   3065:     my $sortby = $env{'form.sortby'};
                   3066:     if ($sortby !~ /^(username|domain|section|groups|fullname|id|start|end)$/) {
                   3067:         $sortby = 'username';
                   3068:     }
                   3069:     my $action = "drop";
1.17      raeburn  3070:     my $check_uncheck_js = &Apache::loncommon::check_uncheck_jscript();
1.1       raeburn  3071:     $r->print(<<END);
                   3072: <input type="hidden" name="sortby" value="$sortby" />
                   3073: <input type="hidden" name="action" value="$action" />
                   3074: <input type="hidden" name="state"  value="done" />
1.17      raeburn  3075: <script type="text/javascript" language="Javascript">
                   3076: $check_uncheck_js
1.1       raeburn  3077: </script>
                   3078: <p>
                   3079: <input type="hidden" name="phase" value="four">
                   3080: END
1.30      raeburn  3081:     my ($indexhash,$keylist) = &make_keylist_array();
                   3082:     my $studentcount = 0;
                   3083:     if (ref($classlist) eq 'HASH') {
                   3084:         foreach my $student (keys(%{$classlist})) {
                   3085:             my $sdata = $classlist->{$student}; 
                   3086:             my $status = $sdata->[$indexhash->{'status'}];
                   3087:             my $section = $sdata->[$indexhash->{'section'}];
                   3088:             if ($status ne 'Active') {
                   3089:                 delete($classlist->{$student});
                   3090:                 next;
                   3091:             }
                   3092:             if ($env{'request.course.sec'} ne '') {
                   3093:                 if ($section ne $env{'request.course.sec'}) {
                   3094:                     delete($classlist->{$student});
                   3095:                     next;
                   3096:                 }
                   3097:             }
                   3098:             $studentcount ++;
                   3099:         }
                   3100:     }
                   3101:     if (!$studentcount) {
                   3102:         $r->print(&mt('There are no students to drop.'));
                   3103:         return;
                   3104:     }
                   3105:     my ($classgroups) = &Apache::loncoursedata::get_group_memberships(
                   3106:                                               $classlist,$keylist,$cdom,$cnum);
                   3107:     my %lt=&Apache::lonlocal::texthash('usrn'   => "username",
                   3108:                                        'dom'    => "domain",
                   3109:                                        'sn'     => "student name",
                   3110:                                        'sec'    => "section",
                   3111:                                        'start'  => "start date",
                   3112:                                        'end'    => "end date",
                   3113:                                        'groups' => "active groups",
                   3114:                                       );
1.1       raeburn  3115:     if ($nosort) {
1.17      raeburn  3116:         $r->print(&Apache::loncommon::start_data_table().
                   3117:                   &Apache::loncommon::start_data_table_header_row());
1.1       raeburn  3118:         $r->print(<<END);
                   3119:     <th>&nbsp;</th>
                   3120:     <th>$lt{'usrn'}</th>
                   3121:     <th>$lt{'dom'}</th>
                   3122:     <th>ID</th>
                   3123:     <th>$lt{'sn'}</th>
                   3124:     <th>$lt{'sec'}</th>
                   3125:     <th>$lt{'start'}</th>
                   3126:     <th>$lt{'end'}</th>
                   3127:     <th>$lt{'groups'}</th>
                   3128: END
1.17      raeburn  3129:         $r->print(&Apache::loncommon::end_data_table_header_row());
1.1       raeburn  3130:     } else  {
1.17      raeburn  3131:         $r->print(&Apache::loncommon::start_data_table().
                   3132:                   &Apache::loncommon::start_data_table_header_row());
1.1       raeburn  3133:         $r->print(<<END);
1.17      raeburn  3134:     <th>&nbsp;</th>
1.1       raeburn  3135:     <th>
1.17      raeburn  3136:        <a href="/adm/createuser?action=$action&sortby=username">$lt{'usrn'}</a>
1.1       raeburn  3137:     </th><th>
1.17      raeburn  3138:        <a href="/adm/createuser?action=$action&sortby=domain">$lt{'dom'}</a>
1.1       raeburn  3139:     </th><th>
1.17      raeburn  3140:        <a href="/adm/createuser?action=$action&sortby=id">ID</a>
1.1       raeburn  3141:     </th><th>
1.17      raeburn  3142:        <a href="/adm/createuser?action=$action&sortby=fullname">$lt{'sn'}</a>
1.1       raeburn  3143:     </th><th>
1.17      raeburn  3144:        <a href="/adm/createuser?action=$action&sortby=section">$lt{'sec'}</a>
1.1       raeburn  3145:     </th><th>
1.17      raeburn  3146:        <a href="/adm/createuser?action=$action&sortby=start">$lt{'start'}</a>
1.1       raeburn  3147:     </th><th>
1.17      raeburn  3148:        <a href="/adm/createuser?action=$action&sortby=end">$lt{'end'}</a>
1.1       raeburn  3149:     </th><th>
1.17      raeburn  3150:        <a href="/adm/createuser?action=$action&sortby=groups">$lt{'groups'}</a>
1.1       raeburn  3151:     </th>
                   3152: END
1.17      raeburn  3153:         $r->print(&Apache::loncommon::end_data_table_header_row());
1.1       raeburn  3154:     }
                   3155:     #
                   3156:     # Sort the students
1.30      raeburn  3157:     my $index  = $indexhash->{$sortby};
                   3158:     my $second = $indexhash->{'username'};
                   3159:     my $third  = $indexhash->{'domain'};
1.1       raeburn  3160:     my @Sorted_Students = sort {
                   3161:         lc($classlist->{$a}->[$index])  cmp lc($classlist->{$b}->[$index])
                   3162:             ||
                   3163:         lc($classlist->{$a}->[$second]) cmp lc($classlist->{$b}->[$second])
                   3164:             ||
                   3165:         lc($classlist->{$a}->[$third]) cmp lc($classlist->{$b}->[$third])
1.30      raeburn  3166:         } (keys(%{$classlist}));
1.1       raeburn  3167:     foreach my $student (@Sorted_Students) {
                   3168:         my $error;
                   3169:         my $sdata = $classlist->{$student};
1.30      raeburn  3170:         my $username = $sdata->[$indexhash->{'username'}];
                   3171:         my $domain   = $sdata->[$indexhash->{'domain'}];
                   3172:         my $section  = $sdata->[$indexhash->{'section'}];
                   3173:         my $name     = $sdata->[$indexhash->{'fullname'}];
                   3174:         my $id       = $sdata->[$indexhash->{'id'}];
                   3175:         my $start    = $sdata->[$indexhash->{'start'}];
                   3176:         my $end      = $sdata->[$indexhash->{'end'}];
1.1       raeburn  3177:         my $groups = $classgroups->{$student};
                   3178:         my $active_groups;
                   3179:         if (ref($groups->{active}) eq 'HASH') {
                   3180:             $active_groups = join(', ',keys(%{$groups->{'active'}}));
                   3181:         }
                   3182:         if (! defined($start) || $start == 0) {
                   3183:             $start = &mt('none');
                   3184:         } else {
                   3185:             $start = &Apache::lonlocal::locallocaltime($start);
                   3186:         }
                   3187:         if (! defined($end) || $end == 0) {
                   3188:             $end = &mt('none');
                   3189:         } else {
                   3190:             $end = &Apache::lonlocal::locallocaltime($end);
                   3191:         }
1.17      raeburn  3192:         my $studentkey = $student.':'.$section;
1.30      raeburn  3193:         my $startitem = '<input type="hidden" name="'.$studentkey.'_start" value="'.$sdata->[$indexhash->{'start'}].'" />';
1.1       raeburn  3194:         #
                   3195:         $r->print(&Apache::loncommon::start_data_table_row());
                   3196:         $r->print(<<"END");
1.29      raeburn  3197:     <td><input type="checkbox" name="droplist" value="$studentkey"></td>
1.1       raeburn  3198:     <td>$username</td>
                   3199:     <td>$domain</td>
                   3200:     <td>$id</td>
                   3201:     <td>$name</td>
                   3202:     <td>$section</td>
1.29      raeburn  3203:     <td>$start $startitem</td>
1.1       raeburn  3204:     <td>$end</td>
                   3205:     <td>$active_groups</td>
                   3206: END
                   3207:         $r->print(&Apache::loncommon::end_data_table_row());
                   3208:     }
                   3209:     $r->print(&Apache::loncommon::end_data_table().'<br />');
                   3210:     %lt=&Apache::lonlocal::texthash(
1.29      raeburn  3211:                        'dp'   => "Drop Students",
1.1       raeburn  3212:                        'ca'   => "check all",
                   3213:                        'ua'   => "uncheck all",
                   3214:                                        );
                   3215:     $r->print(<<"END");
                   3216: </p><p>
                   3217: <input type="button" value="$lt{'ca'}" onclick="javascript:checkAll(document.studentform.droplist)"> &nbsp;
                   3218: <input type="button" value="$lt{'ua'}" onclick="javascript:uncheckAll(document.studentform.droplist)">
                   3219: <p><input type=submit value="$lt{'dp'}"></p>
                   3220: END
                   3221:     return;
                   3222: }
                   3223: 
                   3224: #
                   3225: # Print out the initial form to get the file containing a list of users
                   3226: #
                   3227: sub print_first_users_upload_form {
                   3228:     my ($r,$context) = @_;
                   3229:     my $str;
                   3230:     $str  = '<input type="hidden" name="phase" value="two">';
                   3231:     $str .= '<input type="hidden" name="action" value="upload" />';
                   3232:     $str .= '<input type="hidden"   name="state"  value="got_file" />';
1.2       raeburn  3233:     $str .= "<h3>".&mt('Upload a file containing information about users')."</h3>\n";
1.1       raeburn  3234:     $str .= &Apache::loncommon::upfile_select_html();
                   3235:     $str .= "<p>\n";
                   3236:     $str .= '<input type="submit" name="fileupload" value="'.
1.2       raeburn  3237:         &mt('Upload file of users').'">'."\n";
1.1       raeburn  3238:     $str .= '<label><input type="checkbox" name="noFirstLine" /> '.
                   3239:         &mt('Ignore First Line')."</label></p>\n";
                   3240:     $str .= &Apache::loncommon::help_open_topic("Course_Create_Class_List",
                   3241:                          &mt("How do I create a users list from a spreadsheet")).
                   3242:                              "<br />\n";
                   3243:     $str .= &Apache::loncommon::help_open_topic("Course_Convert_To_CSV",
                   3244:                            &mt("How do I create a CSV file from a spreadsheet")).
                   3245:                                "<br />\n";
                   3246:     $str .= &Apache::loncommon::end_page();
                   3247:     $r->print($str);
                   3248:     return;
                   3249: }
                   3250: 
                   3251: # ================================================= Drop/Add from uploaded file
                   3252: sub upfile_drop_add {
1.21      raeburn  3253:     my ($r,$context,$permission) = @_;
1.1       raeburn  3254:     &Apache::loncommon::load_tmp_file($r);
                   3255:     my @userdata=&Apache::loncommon::upfile_record_sep();
                   3256:     if($env{'form.noFirstLine'}){shift(@userdata);}
                   3257:     my @keyfields = split(/\,/,$env{'form.keyfields'});
                   3258:     my %fields=();
                   3259:     for (my $i=0; $i<=$env{'form.nfields'}; $i++) {
                   3260:         if ($env{'form.upfile_associate'} eq 'reverse') {
                   3261:             if ($env{'form.f'.$i} ne 'none') {
                   3262:                 $fields{$keyfields[$i]}=$env{'form.f'.$i};
                   3263:             }
                   3264:         } else {
                   3265:             $fields{$env{'form.f'.$i}}=$keyfields[$i];
                   3266:         }
                   3267:     }
1.29      raeburn  3268:     if ($env{'form.fullup'} ne 'yes') {
                   3269:         $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n".
                   3270:                   '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />');
                   3271:     }
1.1       raeburn  3272:     #
                   3273:     # Store the field choices away
                   3274:     foreach my $field (qw/username names
                   3275:                        fname mname lname gen id sec ipwd email role/) {
                   3276:         $env{'form.'.$field.'_choice'}=$fields{$field};
                   3277:     }
                   3278:     &Apache::loncommon::store_course_settings('enrollment_upload',
                   3279:                                               { 'username_choice' => 'scalar',
                   3280:                                                 'names_choice' => 'scalar',
                   3281:                                                 'fname_choice' => 'scalar',
                   3282:                                                 'mname_choice' => 'scalar',
                   3283:                                                 'lname_choice' => 'scalar',
                   3284:                                                 'gen_choice' => 'scalar',
                   3285:                                                 'id_choice' => 'scalar',
                   3286:                                                 'sec_choice' => 'scalar',
                   3287:                                                 'ipwd_choice' => 'scalar',
                   3288:                                                 'email_choice' => 'scalar',
                   3289:                                                 'role_choice'  => 'scalar' });
                   3290:     #
                   3291:     my ($startdate,$enddate) = &get_dates_from_form();
                   3292:     if ($env{'form.makedatesdefault'}) {
1.27      raeburn  3293:         $r->print(&make_dates_default($startdate,$enddate,$context));
1.1       raeburn  3294:     }
                   3295:     # Determine domain and desired host (home server)
                   3296:     my $domain=$env{'request.role.domain'};
                   3297:     my $desiredhost = $env{'form.lcserver'};
                   3298:     if (lc($desiredhost) eq 'default') {
                   3299:         $desiredhost = undef;
                   3300:     } else {
                   3301:         my %home_servers = &Apache::lonnet::get_servers($domain,'library');
                   3302:         if (! exists($home_servers{$desiredhost})) {
                   3303:             $r->print('<span class="LC_error">'.&mt('Error').
                   3304:                       &mt('Invalid home server specified').'</span>');
                   3305:             $r->print(&Apache::loncommon::end_page());
                   3306:             return;
                   3307:         }
                   3308:     }
                   3309:     # Determine authentication mechanism
                   3310:     my $changeauth;
                   3311:     if ($context eq 'domain') {
                   3312:         $changeauth = $env{'form.changeauth'};
                   3313:     }
                   3314:     my $amode  = '';
                   3315:     my $genpwd = '';
                   3316:     if ($env{'form.login'} eq 'krb') {
                   3317:         $amode='krb';
                   3318:         $amode.=$env{'form.krbver'};
                   3319:         $genpwd=$env{'form.krbarg'};
                   3320:     } elsif ($env{'form.login'} eq 'int') {
                   3321:         $amode='internal';
                   3322:         if ((defined($env{'form.intarg'})) && ($env{'form.intarg'})) {
                   3323:             $genpwd=$env{'form.intarg'};
                   3324:         }
                   3325:     } elsif ($env{'form.login'} eq 'loc') {
                   3326:         $amode='localauth';
                   3327:         if ((defined($env{'form.locarg'})) && ($env{'form.locarg'})) {
                   3328:             $genpwd=$env{'form.locarg'};
                   3329:         }
                   3330:     }
                   3331:     if ($amode =~ /^krb/) {
                   3332:         if (! defined($genpwd) || $genpwd eq '') {
                   3333:             $r->print('<span class="Error">'.
                   3334:                       &mt('Unable to enroll users').' '.
                   3335:                       &mt('No Kerberos domain was specified.').'</span></p>');
                   3336:             $amode = ''; # This causes the loop below to be skipped
                   3337:         }
                   3338:     }
                   3339:     my ($cid,$defaultsec,$defaultrole,$setting);
                   3340:     if ($context eq 'domain') {
                   3341:         $setting = $env{'form.roleaction'};
                   3342:         if ($setting eq 'domain') {
                   3343:             $defaultrole = $env{'form.defaultrole'};
                   3344:         } elsif ($setting eq 'course') {
                   3345:             $defaultrole = $env{'form.courserole'};
1.27      raeburn  3346:             $defaultsec = $env{'form.sections'};
1.1       raeburn  3347:         }  
1.13      raeburn  3348:     } elsif ($context eq 'author') {
1.1       raeburn  3349:         $defaultrole = $env{'form.defaultrole'};
1.27      raeburn  3350:     } elsif ($context eq 'course') {
                   3351:         $defaultrole = $env{'form.defaultrole'};
                   3352:         $defaultsec = $env{'form.sections'};
1.1       raeburn  3353:     }
1.27      raeburn  3354:     if ($env{'request.course.id'} ne '') {
                   3355:         $cid = $env{'request.course.id'};
                   3356:     } elsif ($setting eq 'course') {
                   3357:         if (&Apache::lonnet::is_course($env{'form.dcdomain'},$env{'form.dccourse'})) {
                   3358:             $cid = $env{'form.dcdomain'}.'_'.$env{'form.dccourse'};
1.1       raeburn  3359:         }
                   3360:     }
1.27      raeburn  3361:     # Check to see if user information can be changed
                   3362:     my @userinfo = ('firstname','middlename','lastname','generation',
                   3363:                     'permanentemail','id');
                   3364:     my %canmodify;
                   3365:     if (&Apache::lonnet::allowed('mau',$domain)) {
                   3366:         foreach my $field (@userinfo) {
                   3367:             $canmodify{$field} = 1;
                   3368:         }
                   3369:     }
                   3370:     my (%userlist,%modifiable_fields,@poss_roles);
                   3371:     my $secidx = &Apache::loncoursedata::CL_SECTION();
                   3372:     my @courseroles = &roles_by_context('course',1);
                   3373:     if (!&Apache::lonnet::allowed('mau',$domain)) {
                   3374:         if ($context eq 'course' || $context eq 'author') {
                   3375:             @poss_roles =  &curr_role_permissions($context);
                   3376:             my @statuses = ('active','future');
                   3377:             my ($indexhash,$keylist) = &make_keylist_array();
                   3378:             my %info;
                   3379:             foreach my $role (@poss_roles) {
                   3380:                 %{$modifiable_fields{$role}} = &can_modify_userinfo($context,$domain,
                   3381:                                                         \@userinfo,[$role]);
                   3382:             }
                   3383:             if ($context eq 'course') {
                   3384:                 my ($cnum,$cdom) = &get_course_identity();
                   3385:                 my $roster = &Apache::loncoursedata::get_classlist();
                   3386:                 %userlist = %{$roster};
                   3387:                 my %advrolehash = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,
                   3388:                                                          \@statuses,\@poss_roles);
                   3389:                 &gather_userinfo($context,'view',\%userlist,$indexhash,\%info,
                   3390:                                 \%advrolehash,$permission);
                   3391:             } elsif ($context eq 'author') {
                   3392:                 my %cstr_roles = &Apache::lonnet::get_my_roles(undef,undef,undef,
                   3393:                                                   \@statuses,\@poss_roles);
                   3394:                 &gather_userinfo($context,'view',\%userlist,$indexhash,\%info,
                   3395:                              \%cstr_roles,$permission);
                   3396: 
                   3397:             }
                   3398:         }
1.1       raeburn  3399:     }
                   3400:     if ( $domain eq &LONCAPA::clean_domain($domain)
                   3401:         && ($amode ne '')) {
                   3402:         #######################################
                   3403:         ##         Add/Modify Users          ##
                   3404:         #######################################
                   3405:         if ($context eq 'course') {
                   3406:             $r->print('<h3>'.&mt('Enrolling Users')."</h3>\n<p>\n");
1.13      raeburn  3407:         } elsif ($context eq 'author') {
1.1       raeburn  3408:             $r->print('<h3>'.&mt('Updating Co-authors')."</h3>\n<p>\n");
                   3409:         } else {
                   3410:             $r->print('<h3>'.&mt('Adding/Modifying Users')."</h3>\n<p>\n");
                   3411:         }
                   3412:         my %counts = (
                   3413:                        user => 0,
                   3414:                        auth => 0,
                   3415:                        role => 0,
                   3416:                      );
                   3417:         my $flushc=0;
                   3418:         my %student=();
1.42      raeburn  3419:         my (%curr_groups,@sections,@cleansec,$defaultwarn,$groupwarn);
1.1       raeburn  3420:         my %userchg;
1.27      raeburn  3421:         if ($context eq 'course' || $setting eq 'course') {
                   3422:             if ($context eq 'course') {
                   3423:                 # Get information about course groups
                   3424:                 %curr_groups = &Apache::longroup::coursegroups();
                   3425:             } elsif ($setting eq 'course') {
                   3426:                 if ($cid) {
                   3427:                     %curr_groups =
                   3428:                         &Apache::longroup::coursegroups($env{'form.dcdomain'},
                   3429:                                                         $env{'form.dccourse'});
                   3430:                 }
                   3431:             }
                   3432:             # determine section number
                   3433:             if ($defaultsec =~ /,/) {
                   3434:                 push(@sections,split(/,/,$defaultsec));
                   3435:             } else {
                   3436:                 push(@sections,$defaultsec);
                   3437:             }
                   3438:             # remove non alphanumeric values from section
                   3439:             foreach my $item (@sections) {
                   3440:                 $item =~ s/\W//g;
                   3441:                 if ($item eq "none" || $item eq 'all') {
                   3442:                     $defaultwarn = &mt('Default section name [_1] could not be used as it is a reserved word.',$item);
                   3443:                 } elsif ($item ne ''  && exists($curr_groups{$item})) {
                   3444:                     $groupwarn = &mt('Default section name "[_1]" is the name of a course group. Section names and group names must be distinct.',$item);
                   3445:                 } elsif ($item ne '') {
                   3446:                     push(@cleansec,$item);
                   3447:                 }
                   3448:             }
                   3449:             if ($defaultwarn) {
                   3450:                 $r->print($defaultwarn.'<br />');
                   3451:             }
                   3452:             if ($groupwarn) {
                   3453:                 $r->print($groupwarn.'<br />');
                   3454:             }
1.1       raeburn  3455:         }
1.5       raeburn  3456:         my (%curr_rules,%got_rules,%alerts);
1.27      raeburn  3457:         my %customroles = &my_custom_roles();
1.42      raeburn  3458:         my @permitted_roles = &roles_on_upload($context,$setting,%customroles); 
1.1       raeburn  3459:         # Get new users list
1.27      raeburn  3460:         foreach my $line (@userdata) {
1.42      raeburn  3461:             my @secs;
1.27      raeburn  3462:             my %entries=&Apache::loncommon::record_sep($line);
1.1       raeburn  3463:             # Determine user name
                   3464:             unless (($entries{$fields{'username'}} eq '') ||
                   3465:                     (!defined($entries{$fields{'username'}}))) {
                   3466:                 my ($fname, $mname, $lname,$gen) = ('','','','');
                   3467:                 if (defined($fields{'names'})) {
                   3468:                     ($lname,$fname,$mname)=($entries{$fields{'names'}}=~
                   3469:                                             /([^\,]+)\,\s*(\w+)\s*(.*)$/);
                   3470:                 } else {
                   3471:                     if (defined($fields{'fname'})) {
                   3472:                         $fname=$entries{$fields{'fname'}};
                   3473:                     }
                   3474:                     if (defined($fields{'mname'})) {
                   3475:                         $mname=$entries{$fields{'mname'}};
                   3476:                     }
                   3477:                     if (defined($fields{'lname'})) {
                   3478:                         $lname=$entries{$fields{'lname'}};
                   3479:                     }
                   3480:                     if (defined($fields{'gen'})) {
                   3481:                         $gen=$entries{$fields{'gen'}};
                   3482:                     }
                   3483:                 }
                   3484:                 if ($entries{$fields{'username'}}
                   3485:                     ne &LONCAPA::clean_username($entries{$fields{'username'}})) {
                   3486:                     $r->print('<br />'.
                   3487:       &mt('<b>[_1]</b>: Unacceptable username for user [_2] [_3] [_4] [_5]',
                   3488:           $entries{$fields{'username'}},$fname,$mname,$lname,$gen).
                   3489:                               '</b>');
1.27      raeburn  3490:                     next;
1.1       raeburn  3491:                 } else {
1.5       raeburn  3492:                     my $username = $entries{$fields{'username'}};
1.27      raeburn  3493:                     if (defined($fields{'sec'})) {
                   3494:                         if (defined($entries{$fields{'sec'}})) {
1.42      raeburn  3495:                             $entries{$fields{'sec'}} =~ s/\W//g;
1.27      raeburn  3496:                             my $item = $entries{$fields{'sec'}};
                   3497:                             if ($item eq "none" || $item eq 'all') {
                   3498:                                 $r->print('<br />'.&mt('<b>[_1]</b>: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a reserved word.',$username,$fname,$mname,$lname,$gen,$item));
                   3499:                                 next;
                   3500:                             } elsif (exists($curr_groups{$item})) {
                   3501:                                 $r->print('<br />'.&mt('<b>[_1]</b>: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a course group.',$username,$fname,$mname,$lname,$gen,$item).' '.&mt('Section names and group names must be distinct.'));
                   3502:                                 next;
                   3503:                             } else {
                   3504:                                 push(@secs,$item);
                   3505:                             }
                   3506:                         }
                   3507:                     }
                   3508:                     if ($env{'request.course.sec'} ne '') {
                   3509:                         @secs = ($env{'request.course.sec'});
                   3510:                         if (ref($userlist{$username.':'.$domain}) eq 'ARRAY') {
                   3511:                             my $currsec = $userlist{$username.':'.$domain}[$secidx];
                   3512:                             if ($currsec ne $env{'request.course.sec'}) {
                   3513:                                 $r->print('<br />'.&mt('<b>[_1]</b>: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".',$username,$fname,$mname,$lname,$gen,$secs[0]).'<br />');
                   3514:                                 if ($currsec eq '') {
                   3515:                                     $r->print(&mt('This user already has an active/future student role in the course, unaffiliated to any section.'));
                   3516: 
                   3517:                                 } else {
                   3518:                                     $r->print(&mt('This user already has an active/future role in section "[_1]" of the course.',$currsec));
                   3519:                                 }
                   3520:                                 $r->print('<br />'.&mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',$secs[0]).'<br />');
                   3521:                                 next;
1.1       raeburn  3522:                             }
                   3523:                         }
1.27      raeburn  3524:                     } elsif ($context eq 'course' || $setting eq 'course') {
                   3525:                         if (@secs == 0) {
                   3526:                             @secs = @cleansec;
1.1       raeburn  3527:                         }
                   3528:                     }
                   3529:                     # determine id number
                   3530:                     my $id='';
                   3531:                     if (defined($fields{'id'})) {
                   3532:                         if (defined($entries{$fields{'id'}})) {
                   3533:                             $id=$entries{$fields{'id'}};
                   3534:                         }
                   3535:                         $id=~tr/A-Z/a-z/;
                   3536:                     }
                   3537:                     # determine email address
                   3538:                     my $email='';
                   3539:                     if (defined($fields{'email'})) {
                   3540:                         if (defined($entries{$fields{'email'}})) {
                   3541:                             $email=$entries{$fields{'email'}};
                   3542:                             unless ($email=~/^[^\@]+\@[^\@]+$/) { $email=''; }                        }
                   3543:                     }
                   3544:                     # determine user password
                   3545:                     my $password = $genpwd;
                   3546:                     if (defined($fields{'ipwd'})) {
                   3547:                         if ($entries{$fields{'ipwd'}}) {
                   3548:                             $password=$entries{$fields{'ipwd'}};
                   3549:                         }
                   3550:                     }
                   3551:                     # determine user role
                   3552:                     my $role = '';
                   3553:                     if (defined($fields{'role'})) {
                   3554:                         if ($entries{$fields{'role'}}) {
1.42      raeburn  3555:                             $entries{$fields{'role'}}  =~ s/(\s+$|^\s+)//g;
                   3556:                             if ($entries{$fields{'role'}} ne '') {
                   3557:                                 if (grep(/^\Q$entries{$fields{'role'}}\E$/,@permitted_roles)) {
                   3558:                                     $role = $entries{$fields{'role'}};
1.27      raeburn  3559:                                 }
                   3560:                             }
                   3561:                             if ($role eq '') {
                   3562:                                 my $rolestr = join(', ',@permitted_roles);
1.1       raeburn  3563:                                 $r->print('<br />'.
                   3564:       &mt('<b>[_1]</b>: You do not have permission to add the requested role [_2] for the user.',$entries{$fields{'username'}},$entries{$fields{'role'}}).'<br />'.&mt('Allowable role(s) is/are: [_1].',$rolestr)."\n");
                   3565:                                 next;
                   3566:                             }
                   3567:                         }
                   3568:                     }
                   3569:                     if ($role eq '') {
                   3570:                         $role = $defaultrole;
                   3571:                     }
                   3572:                     # Clean up whitespace
                   3573:                     foreach (\$domain,\$username,\$id,\$fname,\$mname,
1.27      raeburn  3574:                              \$lname,\$gen) {
1.1       raeburn  3575:                         $$_ =~ s/(\s+$|^\s+)//g;
                   3576:                     }
1.5       raeburn  3577:                     # check against rules
                   3578:                     my $checkid = 0;
                   3579:                     my $newuser = 0;
                   3580:                     my (%rulematch,%inst_results,%idinst_results);
                   3581:                     my $uhome=&Apache::lonnet::homeserver($username,$domain);
                   3582:                     if ($uhome eq 'no_host') {
                   3583:                         $checkid = 1;
                   3584:                         $newuser = 1;
                   3585:                         my $checkhash;
                   3586:                         my $checks = { 'username' => 1 };
                   3587:                         $checkhash->{$username.':'.$domain} = { 'newuser' => 1, };
                   3588:                         &Apache::loncommon::user_rule_check($checkhash,$checks,
                   3589:                             \%alerts,\%rulematch,\%inst_results,\%curr_rules,
                   3590:                             \%got_rules);
                   3591:                         if (ref($alerts{'username'}) eq 'HASH') {
                   3592:                             if (ref($alerts{'username'}{$domain}) eq 'HASH') {
                   3593:                                 next if ($alerts{'username'}{$domain}{$username});
                   3594:                             }
                   3595:                         }
1.13      raeburn  3596:                     } else {
1.27      raeburn  3597:                         if ($context eq 'course' || $context eq 'author') {
                   3598:                             if ($role eq '') {
                   3599:                                 my @checkroles;
                   3600:                                 foreach my $role (@poss_roles) {
                   3601:                                     my $endkey;
                   3602:                                     if ($role ne 'st') {
                   3603:                                         $endkey = ':'.$role;
                   3604:                                     }
                   3605:                                     if (exists($userlist{$username.':'.$domain.$endkey})) {
                   3606:                                         if (!grep(/^\Q$role\E$/,@checkroles)) {
                   3607:                                             push(@checkroles,$role);
                   3608:                                         }
                   3609:                                     }
                   3610:                                 }
                   3611:                                 if (@checkroles > 0) {
                   3612:                                     %canmodify = &can_modify_userinfo($context,$domain,\@userinfo,\@checkroles);
                   3613:                                 }
                   3614:                             } elsif (ref($modifiable_fields{$role}) eq 'HASH') {
                   3615:                                 %canmodify = %{$modifiable_fields{$role}};
                   3616:                             }
                   3617:                         }
                   3618:                         my @newinfo = (\$fname,\$mname,\$lname,\$gen,\$email,\$id);
                   3619:                         for (my $i=0; $i<@userinfo; $i++) {
                   3620:                             if (${$newinfo[$i]} ne '') {
                   3621:                                 if (!$canmodify{$userinfo[$i]}) {
                   3622:                                     ${$newinfo[$i]} = '';
                   3623:                                 }
                   3624:                             }
                   3625:                         }
1.5       raeburn  3626:                     }
                   3627:                     if ($id ne '') {
                   3628:                         if (!$newuser) {
                   3629:                             my %idhash = &Apache::lonnet::idrget($domain,($username));
                   3630:                             if ($idhash{$username} ne $id) {
                   3631:                                 $checkid = 1;
                   3632:                             }
                   3633:                         }
                   3634:                         if ($checkid) {
                   3635:                             my $checkhash;
                   3636:                             my $checks = { 'id' => 1 };
                   3637:                             $checkhash->{$username.':'.$domain} = { 'newuser' => $newuser,
                   3638:                                                                     'id'  => $id };
                   3639:                             &Apache::loncommon::user_rule_check($checkhash,$checks,
                   3640:                                 \%alerts,\%rulematch,\%idinst_results,\%curr_rules,
                   3641:                                 \%got_rules);
                   3642:                             if (ref($alerts{'id'}) eq 'HASH') {
                   3643:                                 if (ref($alerts{'id'}{$domain}) eq 'HASH') {
                   3644:                                     next if ($alerts{'id'}{$domain}{$id});
                   3645:                                 }
                   3646:                             }
                   3647:                         }
                   3648:                     }
1.1       raeburn  3649:                     if ($password || $env{'form.login'} eq 'loc') {
1.27      raeburn  3650:                         my $multiple = 0;
                   3651:                         my ($userresult,$authresult,$roleresult,$idresult);
                   3652:                         my (%userres,%authres,%roleres,%idres);
1.42      raeburn  3653:                         my $singlesec = '';
1.1       raeburn  3654:                         if ($role eq 'st') {
1.27      raeburn  3655:                             my $sec;
1.42      raeburn  3656:                             if (@secs > 0) {
                   3657:                                 $sec = $secs[0];
1.27      raeburn  3658:                             }
1.42      raeburn  3659:                             &modifystudent($domain,$username,$cid,$sec,
                   3660:                                            $desiredhost);
                   3661:                             $roleresult =
                   3662:                                 &Apache::lonnet::modifystudent
                   3663:                                     ($domain,$username,$id,$amode,$password,
                   3664:                                      $fname,$mname,$lname,$gen,$sec,$enddate,
                   3665:                                      $startdate,$env{'form.forceid'},
                   3666:                                      $desiredhost,$email,'manual','',$cid);
                   3667:                             $userresult = $roleresult;
1.1       raeburn  3668:                         } else {
1.42      raeburn  3669:                             if ($role ne '') { 
                   3670:                                 if ($context eq 'course' || $setting eq 'course') {
                   3671:                                     if ($customroles{$role}) {
                   3672:                                         $role = 'cr_'.$env{'user.domain'}.'_'.
                   3673:                                                 $env{'user.name'}.'_'.$role;
                   3674:                                     }
                   3675:                                     if ($role ne 'cc') { 
                   3676:                                         if (@secs > 1) {
                   3677:                                             $multiple = 1;
                   3678:                                             foreach my $sec (@secs) {
                   3679:                                                 ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) =
                   3680:                                                 &modifyuserrole($context,$setting,
                   3681:                                                     $changeauth,$cid,$domain,$username,
                   3682:                                                     $id,$amode,$password,$fname,
                   3683:                                                     $mname,$lname,$gen,$sec,
                   3684:                                                     $env{'form.forceid'},$desiredhost,
                   3685:                                                     $email,$role,$enddate,
                   3686:                                                     $startdate,$checkid);
                   3687:                                             }
                   3688:                                         } elsif (@secs > 0) {
                   3689:                                             $singlesec = $secs[0];
                   3690:                                         }
1.27      raeburn  3691:                                     }
                   3692:                                 }
                   3693:                             }
                   3694:                             if (!$multiple) {
1.28      raeburn  3695:                                 ($userresult,$authresult,$roleresult,$idresult) = 
1.27      raeburn  3696:                                     &modifyuserrole($context,$setting,
1.42      raeburn  3697:                                                     $changeauth,$cid,$domain,$username, 
                   3698:                                                     $id,$amode,$password,$fname,
                   3699:                                                     $mname,$lname,$gen,$singlesec,
                   3700:                                                     $env{'form.forceid'},$desiredhost,
                   3701:                                                     $email,$role,$enddate,$startdate,$checkid);
1.27      raeburn  3702:                             }
                   3703:                         }
                   3704:                         if ($multiple) {
                   3705:                             foreach my $sec (sort(keys(%userres))) {
1.42      raeburn  3706:                                 $flushc =
1.27      raeburn  3707:                                 &user_change_result($r,$userres{$sec},$authres{$sec},
                   3708:                                                     $roleres{$sec},$idres{$sec},\%counts,$flushc,
                   3709:                                                     $username,\%userchg);
                   3710: 
                   3711:                             }
                   3712:                         } else {
                   3713:                             $flushc = 
                   3714:                                 &user_change_result($r,$userresult,$authresult,
1.28      raeburn  3715:                                                     $roleresult,$idresult,\%counts,$flushc,
1.29      raeburn  3716:                                                     $username,\%userchg);
1.1       raeburn  3717:                         }
                   3718:                     } else {
                   3719:                         if ($context eq 'course') {
                   3720:                             $r->print('<br />'. 
                   3721:       &mt('<b>[_1]</b>: Unable to enroll.  No password specified.',$username)
                   3722:                                      );
1.13      raeburn  3723:                         } elsif ($context eq 'author') {
1.1       raeburn  3724:                             $r->print('<br />'.
                   3725:       &mt('<b>[_1]</b>: Unable to add co-author.  No password specified.',$username)
                   3726:                                      );
                   3727:                         } else {
                   3728:                             $r->print('<br />'.
                   3729:       &mt('<b>[_1]</b>: Unable to add user.  No password specified.',$username)
                   3730:                                      );
                   3731:                         }
                   3732:                     }
                   3733:                 }
                   3734:             }
                   3735:         } # end of foreach (@userdata)
                   3736:         # Flush the course logs so reverse user roles immediately updated
1.5       raeburn  3737:         &Apache::lonnet::flushcourselogs();
1.29      raeburn  3738:         $r->print("</p>\n<p>\n".&mt('Processed [quant,_1,user].',$counts{'user'}).
1.1       raeburn  3739:                   "</p>\n");
                   3740:         if ($counts{'role'} > 0) {
                   3741:             $r->print("<p>\n".
1.29      raeburn  3742:                       &mt('Roles added for [quant,_1,user].',$counts{'role'}).' '.&mt('If a user is currently logged-in to LON-CAPA, any new roles which are active will be available when the user next logs in.')."</p>\n");
                   3743:         } else {
                   3744:             $r->print('<p>'.&mt('No roles added').'</p>');
1.1       raeburn  3745:         }
                   3746:         if ($counts{'auth'} > 0) {
                   3747:             $r->print("<p>\n".
                   3748:                       &mt('Authentication changed for [_1] existing users.',
                   3749:                           $counts{'auth'})."</p>\n");
                   3750:         }
1.13      raeburn  3751:         $r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules));
1.1       raeburn  3752:         #####################################
1.29      raeburn  3753:         # Display list of students to drop  #
1.1       raeburn  3754:         #####################################
                   3755:         if ($env{'form.fullup'} eq 'yes') {
1.29      raeburn  3756:             $r->print('<h3>'.&mt('Students to Drop')."</h3>\n");
1.1       raeburn  3757:             #  Get current classlist
1.30      raeburn  3758:             my $classlist = &Apache::loncoursedata::get_classlist();
1.1       raeburn  3759:             if (! defined($classlist)) {
1.29      raeburn  3760:                 $r->print('<form name="studentform" method="post" action="/adm/createuser" />'.
                   3761:                           '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />'.
                   3762:                           &mt('There are no students with current/future access to the course.').
                   3763:                           '</form>'."\n");
1.1       raeburn  3764:             } else {
                   3765:                 # Remove the students we just added from the list of students.
1.30      raeburn  3766:                 foreach my $line (@userdata) {
                   3767:                     my %entries=&Apache::loncommon::record_sep($line);
1.1       raeburn  3768:                     unless (($entries{$fields{'username'}} eq '') ||
                   3769:                             (!defined($entries{$fields{'username'}}))) {
                   3770:                         delete($classlist->{$entries{$fields{'username'}}.
                   3771:                                                 ':'.$domain});
                   3772:                     }
                   3773:                 }
                   3774:                 # Print out list of dropped students.
1.30      raeburn  3775:                 &show_drop_list($r,$classlist,'nosort',$permission);
1.1       raeburn  3776:             }
                   3777:         }
                   3778:     } # end of unless
1.29      raeburn  3779:     if ($env{'form.fullup'} ne 'yes') {
                   3780:         $r->print('</form>');
                   3781:     }
1.1       raeburn  3782: }
                   3783: 
1.13      raeburn  3784: sub print_namespacing_alerts {
                   3785:     my ($domain,$alerts,$curr_rules) = @_;
                   3786:     my $output;
                   3787:     if (ref($alerts) eq 'HASH') {
                   3788:         if (keys(%{$alerts}) > 0) {
                   3789:             if (ref($alerts->{'username'}) eq 'HASH') {
                   3790:                 foreach my $dom (sort(keys(%{$alerts->{'username'}}))) {
                   3791:                     my $count;
                   3792:                     if (ref($alerts->{'username'}{$dom}) eq 'HASH') {
                   3793:                         $count = keys(%{$alerts->{'username'}{$dom}});
                   3794:                     }
                   3795:                     my $domdesc = &Apache::lonnet::domain($domain,'description');
                   3796:                     if (ref($curr_rules->{$dom}) eq 'HASH') {
                   3797:                         $output .= &Apache::loncommon::instrule_disallow_msg(
                   3798:                                         'username',$domdesc,$count,'upload');
                   3799:                     }
                   3800:                     $output .= &Apache::loncommon::user_rule_formats($dom,
                   3801:                                    $domdesc,$curr_rules->{$dom}{'username'},
                   3802:                                    'username');
                   3803:                 }
                   3804:             }
                   3805:             if (ref($alerts->{'id'}) eq 'HASH') {
                   3806:                 foreach my $dom (sort(keys(%{$alerts->{'id'}}))) {
                   3807:                     my $count;
                   3808:                     if (ref($alerts->{'id'}{$dom}) eq 'HASH') {
                   3809:                         $count = keys(%{$alerts->{'id'}{$dom}});
                   3810:                     }
                   3811:                     my $domdesc = &Apache::lonnet::domain($domain,'description');
                   3812:                     if (ref($curr_rules->{$dom}) eq 'HASH') {
                   3813:                         $output .= &Apache::loncommon::instrule_disallow_msg(
                   3814:                                               'id',$domdesc,$count,'upload');
                   3815:                     }
                   3816:                     $output .= &Apache::loncommon::user_rule_formats($dom,
                   3817:                                     $domdesc,$curr_rules->{$dom}{'id'},'id');
                   3818:                 }
                   3819:             }
                   3820:         }
                   3821:     }
                   3822: }
                   3823: 
1.1       raeburn  3824: sub user_change_result {
1.29      raeburn  3825:     my ($r,$userresult,$authresult,$roleresult,$idresult,$counts,$flushc,
                   3826:         $username,$userchg) = @_;
1.1       raeburn  3827:     my $okresult = 0;
                   3828:     if ($userresult ne 'ok') {
                   3829:         if ($userresult =~ /^error:(.+)$/) {
                   3830:             my $error = $1;
                   3831:             $r->print('<br />'.
                   3832:                   &mt('<b>[_1]</b>:  Unable to add/modify: [_2]',$username,$error));
                   3833:         }
                   3834:     } else {
                   3835:         $counts->{'user'} ++;
                   3836:         $okresult = 1;
                   3837:     }
                   3838:     if ($authresult ne 'ok') {
                   3839:         if ($authresult =~ /^error:(.+)$/) {
                   3840:             my $error = $1;
                   3841:             $r->print('<br />'.
                   3842:                   &mt('<b>[_1]</b>:  Unable to modify authentication: [_2]',$username,$error));
                   3843:         } 
                   3844:     } else {
                   3845:         $counts->{'auth'} ++;
                   3846:         $okresult = 1;
                   3847:     }
                   3848:     if ($roleresult ne 'ok') {
                   3849:         if ($roleresult =~ /^error:(.+)$/) {
                   3850:             my $error = $1;
                   3851:             $r->print('<br />'.
                   3852:                   &mt('<b>[_1]</b>:  Unable to add role: [_2]',$username,$error));
                   3853:         }
                   3854:     } else {
                   3855:         $counts->{'role'} ++;
                   3856:         $okresult = 1;
                   3857:     }
                   3858:     if ($okresult) {
                   3859:         $flushc++;
                   3860:         $userchg->{$username}=1;
                   3861:         $r->print('. ');
                   3862:         if ($flushc>15) {
                   3863:             $r->rflush;
                   3864:             $flushc=0;
                   3865:         }
                   3866:     }
1.29      raeburn  3867:     if ($idresult) {
                   3868:         $r->print($idresult);
                   3869:     }
1.1       raeburn  3870:     return $flushc;
                   3871: }
                   3872: 
                   3873: # ========================================================= Menu Phase Two Drop
1.17      raeburn  3874: sub print_drop_menu {
                   3875:     my ($r,$context,$permission) = @_;
                   3876:     $r->print('<h3>'.&mt("Drop Students").'</h3>'."\n".
                   3877:               '<form name="studentform" method="post">'."\n");
1.30      raeburn  3878:     my $classlist = &Apache::loncoursedata::get_classlist();
1.1       raeburn  3879:     if (! defined($classlist)) {
                   3880:         $r->print(&mt('There are no students currently enrolled.')."\n");
1.30      raeburn  3881:     } else {
                   3882:         &show_drop_list($r,$classlist,'nosort',$permission);
1.1       raeburn  3883:     }
1.17      raeburn  3884:     $r->print('</form>'. &Apache::loncommon::end_page());
1.1       raeburn  3885:     return;
                   3886: }
                   3887: 
                   3888: # ================================================================== Phase four
                   3889: 
1.11      raeburn  3890: sub update_user_list {
                   3891:     my ($r,$context,$setting,$choice) = @_;
                   3892:     my $now = time;
1.1       raeburn  3893:     my $count=0;
1.11      raeburn  3894:     my @changelist;
1.29      raeburn  3895:     if ($choice eq 'drop') {
                   3896:         @changelist = &Apache::loncommon::get_env_multiple('form.droplist');
                   3897:     } else {
1.11      raeburn  3898:         @changelist = &Apache::loncommon::get_env_multiple('form.actionlist');
                   3899:     }
                   3900:     my %result_text = ( ok    => { 'revoke'   => 'Revoked',
                   3901:                                    'delete'   => 'Deleted',
                   3902:                                    'reenable' => 'Re-enabled',
1.17      raeburn  3903:                                    'activate' => 'Activated',
                   3904:                                    'chgdates' => 'Changed Access Dates for',
                   3905:                                    'chgsec'   => 'Changed section for',
                   3906:                                    'drop'     => 'Dropped',
1.11      raeburn  3907:                                  },
                   3908:                         error => {'revoke'    => 'revoking',
                   3909:                                   'delete'    => 'deleting',
                   3910:                                   'reenable'  => 're-enabling',
                   3911:                                   'activate'  => 'activating',
1.17      raeburn  3912:                                   'chgdates'  => 'changing access dates for',
                   3913:                                   'chgsec'    => 'changing section for',
                   3914:                                   'drop'      => 'dropping',
1.11      raeburn  3915:                                  },
                   3916:                       );
                   3917:     my ($startdate,$enddate);
                   3918:     if ($choice eq 'chgdates' || $choice eq 'reenable' || $choice eq 'activate') {
                   3919:         ($startdate,$enddate) = &get_dates_from_form();
                   3920:     }
                   3921:     foreach my $item (@changelist) {
                   3922:         my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype,@sections,
                   3923:             $scopestem);
1.17      raeburn  3924:         if ($choice eq 'drop') {
                   3925:             ($uname,$udom,$sec) = split(/:/,$item,-1);
                   3926:             $role = 'st';
                   3927:             $cid = $env{'request.course.id'};
                   3928:             $scopestem = '/'.$cid;
                   3929:             $scopestem =~s/\_/\//g;
                   3930:             if ($sec eq '') {
                   3931:                 $scope = $scopestem;
                   3932:             } else {
                   3933:                 $scope = $scopestem.'/'.$sec;
                   3934:             }
                   3935:         } elsif ($context eq 'course') {
1.11      raeburn  3936:             ($uname,$udom,$role,$sec,$type,$locktype) = split(/\:/,$item,-1);
                   3937:             $cid = $env{'request.course.id'};
                   3938:             $scopestem = '/'.$cid;
                   3939:             $scopestem =~s/\_/\//g;
                   3940:             if ($sec eq '') {
                   3941:                 $scope = $scopestem;
                   3942:             } else {
                   3943:                 $scope = $scopestem.'/'.$sec;
                   3944:             }
1.13      raeburn  3945:         } elsif ($context eq 'author') {
1.11      raeburn  3946:             ($uname,$udom,$role) = split(/\:/,$item,-1);
                   3947:             $scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'};
                   3948:         } elsif ($context eq 'domain') {
                   3949:             if ($setting eq 'domain') {
                   3950:                 ($role,$uname,$udom) = split(/\:/,$item,-1);
                   3951:                 $scope = '/'.$env{'request.role.domain'}.'/';
1.13      raeburn  3952:             } elsif ($setting eq 'author') { 
1.11      raeburn  3953:                 ($uname,$udom,$role,$scope) = split(/\:/,$item);
                   3954:             } elsif ($setting eq 'course') {
                   3955:                 ($uname,$udom,$role,$cid,$sec,$type,$locktype) = 
                   3956:                     split(/\:/,$item);
                   3957:                 $scope = '/'.$cid;
                   3958:                 $scope =~s/\_/\//g;
                   3959:                 if ($sec ne '') {
                   3960:                     $scope .= '/'.$sec;
                   3961:                 }
                   3962:             }
                   3963:         }
                   3964:         my $plrole = &Apache::lonnet::plaintext($role);
                   3965:         my $start = $env{'form.'.$item.'_start'};
                   3966:         my $end = $env{'form.'.$item.'_end'};
1.17      raeburn  3967:         if ($choice eq 'drop') {
                   3968:             # drop students
                   3969:             $end = $now;
                   3970:             $type = 'manual';
                   3971:             $result =
                   3972:                 &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid);
                   3973:         } elsif ($choice eq 'revoke') {
                   3974:             # revoke or delete user role
1.11      raeburn  3975:             $end = $now; 
                   3976:             if ($role eq 'st') {
                   3977:                 $result = 
                   3978:                     &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid);
                   3979:             } else {
                   3980:                 $result = 
                   3981:                     &Apache::lonnet::revokerole($udom,$uname,$scope,$role);
                   3982:             }
                   3983:         } elsif ($choice eq 'delete') {
                   3984:             if ($role eq 'st') {
1.29      raeburn  3985:                 &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid);
                   3986:             }
                   3987:             $result =
                   3988:                 &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$now,
                   3989:                                             $start,1);
1.11      raeburn  3990:         } else {
                   3991:             #reenable, activate, change access dates or change section
                   3992:             if ($choice ne 'chgsec') {
                   3993:                 $start = $startdate; 
                   3994:                 $end = $enddate;
                   3995:             }
                   3996:             if ($choice eq 'reenable') {
                   3997:                 if ($role eq 'st') {
                   3998:                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid);
                   3999:                 } else {
                   4000:                     $result = 
                   4001:                         &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                   4002:                                                     $now);
                   4003:                 }
                   4004:             } elsif ($choice eq 'activate') {
                   4005:                 if ($role eq 'st') {
                   4006:                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid);
                   4007:                 } else {
                   4008:                     $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                   4009:                                             $now);
                   4010:                 }
                   4011:             } elsif ($choice eq 'chgdates') {
                   4012:                 if ($role eq 'st') {
                   4013:                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid);
                   4014:                 } else {
                   4015:                     $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                   4016:                                                 $start);
                   4017:                 }
                   4018:             } elsif ($choice eq 'chgsec') {
                   4019:                 my (@newsecs,$revresult,$nochg,@retained);
                   4020:                 if ($role ne 'cc') {
                   4021:                     @newsecs = split(/,/,$env{'form.newsecs'});
                   4022:                 }
                   4023:                 # remove existing section if not to be retained.   
                   4024:                 if (!$env{'form.retainsec'}) {
                   4025:                     if ($sec eq '') {
                   4026:                         if (@newsecs == 0) {
                   4027:                             $result = &mt('No change in section assignment (none)');
                   4028:                             $nochg = 1;
1.40      raeburn  4029:                         } else {
                   4030:                             $revresult =
                   4031:                                 &Apache::lonnet::revokerole($udom,$uname,
                   4032:                                                             $scope,$role);
                   4033:                         } 
1.11      raeburn  4034:                     } else {
1.28      raeburn  4035:                         if (@newsecs > 0) {
                   4036:                             if (grep(/^\Q$sec\E$/,@newsecs)) {
                   4037:                                 push(@retained,$sec);
                   4038:                             } else {
                   4039:                                 $revresult =
                   4040:                                     &Apache::lonnet::revokerole($udom,$uname,
                   4041:                                                                 $scope,$role);
                   4042:                             }
                   4043:                         } else {
1.11      raeburn  4044:                             $revresult =
1.28      raeburn  4045:                                 &Apache::lonnet::revokerole($udom,$uname,
                   4046:                                                             $scope,$role);
1.11      raeburn  4047:                         }
                   4048:                     }
                   4049:                 } else {
1.28      raeburn  4050:                     if ($sec eq '') {
                   4051:                         $nochg = 1;
                   4052:                     } else { 
                   4053:                         push(@retained,$sec);
                   4054:                     }
1.11      raeburn  4055:                 }
                   4056:                 # add new sections
                   4057:                 if (@newsecs == 0) {
                   4058:                     if (!$nochg) {
1.28      raeburn  4059:                         if ($role eq 'st') {
                   4060:                             $result = 
                   4061:                                 &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid);
                   4062:                         } else {
                   4063:                             my $newscope = $scopestem;
                   4064:                             $result = &Apache::lonnet::assignrole($udom,$uname,$newscope,$role,$end,$start);
1.11      raeburn  4065:                         }
                   4066:                     }
                   4067:                 } else {
                   4068:                     foreach my $newsec (@newsecs) { 
                   4069:                         if (!grep(/^\Q$newsec\E$/,@retained)) {
                   4070:                             if ($role eq 'st') {
                   4071:                                 $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid);
                   4072:                             } else {
                   4073:                                 my $newscope = $scopestem;
                   4074:                                 if ($newsec ne '') {
                   4075:                                    $newscope .= '/'.$newsec;
                   4076:                                 }
                   4077:                                 $result = &Apache::lonnet::assignrole($udom,$uname,
                   4078:                                                         $newscope,$role,$end,$start);
                   4079:                             }
                   4080:                         }
                   4081:                     }
                   4082:                 }
                   4083:             }
                   4084:         }
1.17      raeburn  4085:         my $extent = $scope;
                   4086:         if ($choice eq 'drop' || $context eq 'course') {
                   4087:             my ($cnum,$cdom,$cdesc) = &get_course_identity($cid);
                   4088:             if ($cdesc) {
                   4089:                 $extent = $cdesc;
                   4090:             }
                   4091:         }
1.1       raeburn  4092:         if ($result eq 'ok' || $result eq 'ok:') {
1.11      raeburn  4093:             $r->print(&mt("$result_text{'ok'}{$choice} role of '[_1]' in [_2] for [_3]",
1.17      raeburn  4094:                           $plrole,$extent,$uname.':'.$udom).'<br />');
1.1       raeburn  4095:             $count++;
                   4096:         } else {
                   4097:             $r->print(
1.29      raeburn  4098:                 &mt("Error $result_text{'error'}{$choice} [_1] in [_2] for [_3]: [_4].",
1.17      raeburn  4099:                     $plrole,$extent,$uname.':'.$udom,$result).'<br />');
1.11      raeburn  4100:         }
                   4101:     }
1.32      raeburn  4102:     $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n");
1.33      raeburn  4103:     if ($choice eq 'drop') {
                   4104:         $r->print('<input type="hidden" name="action" value="listusers" />'."\n".
                   4105:                   '<input type="hidden" name="Status" value="Active" />'."\n".
                   4106:                   '<input type="hidden" name="showrole" value="st" />'."\n");
                   4107:     } else {
                   4108:         foreach my $item ('action','sortby','roletype','showrole','Status','secfilter','grpfilter') {
                   4109:             if ($env{'form.'.$item} ne '') {
                   4110:                 $r->print('<input type="hidden" name="'.$item.'" value="'.$env{'form.'.$item}.
                   4111:                           '" />'."\n");
                   4112:             }
1.32      raeburn  4113:         }
                   4114:     }
1.29      raeburn  4115:     $r->print('<p><b>'.&mt("$result_text{'ok'}{$choice} role(s) for [quant,_1,user,users,no users].",$count).'</b></p>');
1.11      raeburn  4116:     if ($count > 0) {
1.17      raeburn  4117:         if ($choice eq 'revoke' || $choice eq 'drop') {
1.11      raeburn  4118:             $r->print('<p>'.&mt('Re-enabling will re-activate data for the role.</p>'));
                   4119:         }
                   4120:         # Flush the course logs so reverse user roles immediately updated
                   4121:         &Apache::lonnet::flushcourselogs();
                   4122:     }
                   4123:     if ($env{'form.makedatesdefault'}) {
                   4124:         if ($choice eq 'chgdates' || $choice eq 'reenable' || $choice eq 'activate') {
1.29      raeburn  4125:             $r->print(&make_dates_default($startdate,$enddate,$context));
1.1       raeburn  4126:         }
                   4127:     }
1.33      raeburn  4128:     my $linktext = &mt('Display User Lists');
                   4129:     if ($choice eq 'drop') {
                   4130:         $linktext = &mt('Display current class roster');
                   4131:     }
                   4132:     $r->print('<a href="javascript:document.studentform.submit()">'.$linktext.'</a></form>'."\n");
1.1       raeburn  4133: }
                   4134: 
1.8       raeburn  4135: sub classlist_drop {
1.29      raeburn  4136:     my ($scope,$uname,$udom,$now) = @_;
1.8       raeburn  4137:     my ($cdom,$cnum) = ($scope=~m{^/($match_domain)/($match_courseid)});
1.29      raeburn  4138:     if (&Apache::lonnet::is_course($cdom,$cnum)) {
                   4139:         my $user = $uname.':'.$udom;
1.8       raeburn  4140:         if (!&active_student_roles($cnum,$cdom,$uname,$udom)) {
                   4141:             my $result =
                   4142:                 &Apache::lonnet::cput('classlist',
1.29      raeburn  4143:                                       { $user => $now },$cdom,$cnum);
1.8       raeburn  4144:             return &mt('Drop from classlist: [_1]',
                   4145:                        '<b>'.$result.'</b>').'<br />';
                   4146:         }
                   4147:     }
                   4148: }
                   4149: 
                   4150: sub active_student_roles {
                   4151:     my ($cnum,$cdom,$uname,$udom) = @_;
                   4152:     my %roles =
                   4153:         &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
                   4154:                                       ['future','active'],['st']);
                   4155:     return exists($roles{"$cnum:$cdom:st"});
                   4156: }
                   4157: 
1.1       raeburn  4158: sub section_check_js {
1.8       raeburn  4159:     my $groupslist= &get_groupslist();
1.1       raeburn  4160:     return <<"END";
                   4161: function validate(caller) {
1.9       raeburn  4162:     var groups = new Array($groupslist);
1.1       raeburn  4163:     var secname = caller.value;
                   4164:     if ((secname == 'all') || (secname == 'none')) {
                   4165:         alert("'"+secname+"' may not be used as the name for a section, as it is a reserved word.\\nPlease choose a different section name.");
                   4166:         return 'error';
                   4167:     }
                   4168:     if (secname != '') {
                   4169:         for (var k=0; k<groups.length; k++) {
                   4170:             if (secname == groups[k]) {
                   4171:                 alert("'"+secname+"' may not be used as the name for a section, as it is the name of a course group.\\nSection names and group names must be distinct. Please choose a different section name.");
                   4172:                 return 'error';
                   4173:             }
                   4174:         }
                   4175:     }
                   4176:     return 'ok';
                   4177: }
                   4178: END
                   4179: }
                   4180: 
                   4181: sub set_login {
                   4182:     my ($dom,$authformkrb,$authformint,$authformloc) = @_;
                   4183:     my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
                   4184:     my $response;
                   4185:     my ($authnum,%can_assign) =
                   4186:         &Apache::loncommon::get_assignable_auth($dom);
                   4187:     if ($authnum) {
                   4188:         $response = &Apache::loncommon::start_data_table();
                   4189:         if (($can_assign{'krb4'}) || ($can_assign{'krb5'})) {
                   4190:             $response .= &Apache::loncommon::start_data_table_row().
                   4191:                          '<td>'.$authformkrb.'</td>'.
                   4192:                          &Apache::loncommon::end_data_table_row()."\n";
                   4193:         }
                   4194:         if ($can_assign{'int'}) {
                   4195:             $response .= &Apache::loncommon::start_data_table_row().
                   4196:                          '<td>'.$authformint.'</td>'.
                   4197:                          &Apache::loncommon::end_data_table_row()."\n"
                   4198:         }
                   4199:         if ($can_assign{'loc'}) {
                   4200:             $response .= &Apache::loncommon::start_data_table_row().
                   4201:                          '<td>'.$authformloc.'</td>'.
                   4202:                          &Apache::loncommon::end_data_table_row()."\n";
                   4203:         }
                   4204:         $response .= &Apache::loncommon::end_data_table();
                   4205:     }
                   4206:     return $response;
                   4207: }
                   4208: 
1.8       raeburn  4209: sub course_sections {
1.51    ! raeburn  4210:     my ($sections_count,$role,$current_sec) = @_;
1.8       raeburn  4211:     my $output = '';
                   4212:     my @sections = (sort {$a <=> $b} keys %{$sections_count});
1.29      raeburn  4213:     my $numsec = scalar(@sections);
1.51    ! raeburn  4214:     my $is_selected = ' selected="selected" ';
1.29      raeburn  4215:     if ($numsec <= 1) {
1.8       raeburn  4216:         $output = '<select name="currsec_'.$role.'" >'."\n".
1.51    ! raeburn  4217:                   '  <option value="">'.&mt('Select').'</option>'."\n";
        !          4218:         if ($current_sec eq 'none') {
        !          4219:             $output .=       
        !          4220:                   '  <option value=""'.$is_selected.'>'.&mt('No section').'</option>'."\n";
        !          4221:         } else {
        !          4222:             $output .=
1.29      raeburn  4223:                   '  <option value="">'.&mt('No section').'</option>'."\n";
1.51    ! raeburn  4224:         }
1.29      raeburn  4225:         if ($numsec == 1) {
1.51    ! raeburn  4226:             if ($current_sec eq $sections[0]) {
        !          4227:                 $output .=
        !          4228:                   '  <option value="'.$sections[0].'"'.$is_selected.'>'.$sections[0].'</option>'."\n";
        !          4229:             } else {
        !          4230:                 $output .=  
1.8       raeburn  4231:                   '  <option value="'.$sections[0].'" >'.$sections[0].'</option>'."\n";
1.51    ! raeburn  4232:             }
1.29      raeburn  4233:         }
1.8       raeburn  4234:     } else {
                   4235:         $output = '<select name="currsec_'.$role.'" ';
                   4236:         my $multiple = 4;
                   4237:         if (scalar(@sections) < 4) { $multiple = scalar(@sections); }
1.29      raeburn  4238:         if ($role eq 'st') {
                   4239:             $output .= '>'."\n".
1.51    ! raeburn  4240:                        '  <option value="">'.&mt('Select').'</option>'."\n";
        !          4241:             if ($current_sec eq 'none') {
        !          4242:                 $output .= 
        !          4243:                        '  <option value=""'.$is_selected.'>'.&mt('No section')."</option>\n";
        !          4244:             } else {
        !          4245:                 $output .=
1.29      raeburn  4246:                        '  <option value="">'.&mt('No section')."</option>\n";
1.51    ! raeburn  4247:             }
1.29      raeburn  4248:         } else {
                   4249:             $output .= 'multiple="multiple" size="'.$multiple.'">'."\n";
                   4250:         }
1.8       raeburn  4251:         foreach my $sec (@sections) {
1.51    ! raeburn  4252:             if ($current_sec eq $sec) {
        !          4253:                 $output .= '<option value="'.$sec.'"'.$is_selected.'>'.$sec."</option>\n";
        !          4254:             } else {
        !          4255:                 $output .= '<option value="'.$sec.'">'.$sec."</option>\n";
        !          4256:             }
1.8       raeburn  4257:         }
                   4258:     }
                   4259:     $output .= '</select>';
                   4260:     return $output;
                   4261: }
                   4262: 
                   4263: sub get_groupslist {
                   4264:     my $groupslist;
                   4265:     my %curr_groups = &Apache::longroup::coursegroups();
                   4266:     if (%curr_groups) {
                   4267:         $groupslist = join('","',sort(keys(%curr_groups)));
                   4268:         $groupslist = '"'.$groupslist.'"';
                   4269:     }
1.11      raeburn  4270:     return $groupslist; 
1.8       raeburn  4271: }
                   4272: 
                   4273: sub setsections_javascript {
1.37      raeburn  4274:     my ($formname,$groupslist,$mode,$checkauth) = @_;
1.28      raeburn  4275:     my ($checkincluded,$finish,$rolecode,$setsection_js);
                   4276:     if ($mode eq 'upload') {
                   4277:         $checkincluded = 'formname.name == "'.$formname.'"';
                   4278:         $finish = "return 'ok';";
                   4279:         $rolecode = "var role = formname.defaultrole.options[formname.defaultrole.selectedIndex].value;\n";
                   4280:     } elsif ($formname eq 'cu') {
1.8       raeburn  4281:         $checkincluded = 'formname.elements[i-1].checked == true';
1.37      raeburn  4282:         if ($checkauth) {
                   4283:             $finish = "var authcheck = auth_check();\n".
                   4284:                       "   if (authcheck == 'ok') {\n".
                   4285:                       "       formname.submit();\n".
                   4286:                       "   }\n";
                   4287:         } else {
                   4288:             $finish = 'formname.submit()';
                   4289:         }
1.28      raeburn  4290:         $rolecode = "var match = str.split('_');
                   4291:                 var role = match[3];\n";
                   4292:     } elsif ($formname eq 'enrollstudent') {
                   4293:         $checkincluded = 'formname.name == "'.$formname.'"';
1.37      raeburn  4294:         if ($checkauth) {
                   4295:             $finish = "var authcheck = auth_check();\n".
                   4296:                       "   if (authcheck == 'ok') {\n".
                   4297:                       "       formname.submit();\n".
                   4298:                       "   }\n";
                   4299:         } else {
                   4300:             $finish = 'formname.submit()';
                   4301:         }
1.28      raeburn  4302:         $rolecode = "var match = str.split('_');
                   4303:                 var role = match[1];\n";
1.8       raeburn  4304:     } else {
1.28      raeburn  4305:         $checkincluded = 'formname.name == "'.$formname.'"'; 
1.8       raeburn  4306:         $finish = "seccheck = 'ok';";
1.28      raeburn  4307:         $rolecode = "var match = str.split('_');
                   4308:                 var role = match[1];\n";
1.11      raeburn  4309:         $setsection_js = "var seccheck = 'alert';"; 
1.8       raeburn  4310:     }
                   4311:     my %alerts = &Apache::lonlocal::texthash(
                   4312:                     secd => 'Section designations do not apply to Course Coordinator roles.',
                   4313:                     accr => 'A course coordinator role will be added with access to all sections.',
                   4314:                     inea => 'In each course, each user may only have one student role at a time.',
                   4315:                     youh => 'You had selected ',
                   4316:                     secs => 'sections.',
                   4317:                     plmo => 'Please modify your selections so they include no more than one section.',
                   4318:                     mayn => 'may not be used as the name for a section, as it is a reserved word.',
                   4319:                     plch => 'Please choose a different section name.',
                   4320:                     mnot => 'may not be used as a section name, as it is the name of a course group.',
                   4321:                     secn => 'Section names and group names must be distinct. Please choose a different section name.',
1.11      raeburn  4322:                  );                
1.8       raeburn  4323:     $setsection_js .= <<"ENDSECCODE";
                   4324: 
                   4325: function setSections(formname) {
                   4326:     var re1 = /^currsec_/;
                   4327:     var groups = new Array($groupslist);
                   4328:     for (var i=0;i<formname.elements.length;i++) {
                   4329:         var str = formname.elements[i].name;
                   4330:         var checkcurr = str.match(re1);
                   4331:         if (checkcurr != null) {
                   4332:             if ($checkincluded) {
1.28      raeburn  4333:                 $rolecode
1.8       raeburn  4334:                 if (role == 'cc') {
                   4335:                     alert("$alerts{'secd'}\\n$alerts{'accr'}");
                   4336:                 }
                   4337:                 else {
                   4338:                     var sections = '';
                   4339:                     var numsec = 0;
                   4340:                     var sections;
                   4341:                     for (var j=0; j<formname.elements[i].length; j++) {
                   4342:                         if (formname.elements[i].options[j].selected == true ) {
                   4343:                             if (formname.elements[i].options[j].value != "") {
                   4344:                                 if (numsec == 0) {
                   4345:                                     if (formname.elements[i].options[j].value != "") {
                   4346:                                         sections = formname.elements[i].options[j].value;
                   4347:                                         numsec ++;
                   4348:                                     }
                   4349:                                 }
                   4350:                                 else {
                   4351:                                     sections = sections + "," +  formname.elements[i].options[j].value
                   4352:                                     numsec ++;
                   4353:                                 }
                   4354:                             }
                   4355:                         }
                   4356:                     }
                   4357:                     if (numsec > 0) {
                   4358:                         if (formname.elements[i+1].value != "" && formname.elements[i+1].value != null) {
                   4359:                             sections = sections + "," +  formname.elements[i+1].value;
                   4360:                         }
                   4361:                     }
                   4362:                     else {
                   4363:                         sections = formname.elements[i+1].value;
                   4364:                     }
                   4365:                     var newsecs = formname.elements[i+1].value;
                   4366:                     var numsplit;
                   4367:                     if (newsecs != null && newsecs != "") {
                   4368:                         numsplit = newsecs.split(/,/g);
                   4369:                         numsec = numsec + numsplit.length;
                   4370:                     }
                   4371: 
                   4372:                     if ((role == 'st') && (numsec > 1)) {
                   4373:                         alert("$alerts{'inea'} $alerts{'youh'} "+numsec+" $alerts{'secs'}\\n$alerts{'plmo'}")
                   4374:                         return;
                   4375:                     }
                   4376:                     else {
                   4377:                         if (numsplit != null) {
                   4378:                             for (var j=0; j<numsplit.length; j++) {
                   4379:                                 if ((numsplit[j] == 'all') ||
                   4380:                                     (numsplit[j] == 'none')) {
                   4381:                                     alert("'"+numsplit[j]+"' $alerts{'mayn'}\\n$alerts{'plch'}");
                   4382:                                     return;
                   4383:                                 }
                   4384:                                 for (var k=0; k<groups.length; k++) {
                   4385:                                     if (numsplit[j] == groups[k]) {
                   4386:                                         alert("'"+numsplit[j]+"' $alerts{'mnot'}\\n$alerts{'secn'}");
                   4387:                                         return;
                   4388:                                     }
                   4389:                                 }
                   4390:                             }
                   4391:                         }
                   4392:                         formname.elements[i+2].value = sections;
                   4393:                     }
                   4394:                 }
                   4395:             }
                   4396:         }
                   4397:     }
                   4398:     $finish
                   4399: }
                   4400: ENDSECCODE
1.11      raeburn  4401:     return $setsection_js; 
1.8       raeburn  4402: }
                   4403: 
1.15      raeburn  4404: sub can_create_user {
                   4405:     my ($dom,$context,$usertype) = @_;
                   4406:     my %domconf = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
                   4407:     my $cancreate = 1;
1.28      raeburn  4408:     if (&Apache::lonnet::allowed('mau',$dom)) {
                   4409:         return $cancreate;
                   4410:     }
1.15      raeburn  4411:     if (ref($domconf{'usercreation'}) eq 'HASH') {
                   4412:         if (ref($domconf{'usercreation'}{'cancreate'}) eq 'HASH') {
                   4413:             if ($context eq 'course' || $context eq 'author') {
                   4414:                 my $creation = $domconf{'usercreation'}{'cancreate'}{$context};
                   4415:                 if ($creation eq 'none') {
                   4416:                     $cancreate = 0;
                   4417:                 } elsif ($creation ne 'any') {
                   4418:                     if (defined($usertype)) {
                   4419:                         if ($creation ne $usertype) {
                   4420:                             $cancreate = 0;
                   4421:                         }
                   4422:                     }
                   4423:                 }
                   4424:             }
                   4425:         }
                   4426:     }
                   4427:     return $cancreate;
                   4428: }
                   4429: 
1.20      raeburn  4430: sub can_modify_userinfo {
                   4431:     my ($context,$dom,$fields,$userroles) = @_;
                   4432:     my %domconfig =
                   4433:        &Apache::lonnet::get_dom('configuration',['usermodification'],
                   4434:                                 $dom);
                   4435:     my %canmodify;
                   4436:     if (ref($fields) eq 'ARRAY') {
                   4437:         foreach my $field (@{$fields}) {
                   4438:             $canmodify{$field}  = 0;
                   4439:             if (&Apache::lonnet::allowed('mau',$dom)) {
                   4440:                 $canmodify{$field} = 1;
                   4441:             } else {
                   4442:                 if (ref($domconfig{'usermodification'}) eq 'HASH') {
                   4443:                     if (ref($domconfig{'usermodification'}{$context}) eq 'HASH') {
                   4444:                         if (ref($userroles) eq 'ARRAY') {
                   4445:                             foreach my $role (@{$userroles}) {
                   4446:                                 my $testrole;
                   4447:                                 if ($role =~ /^cr\//) {
                   4448:                                     $testrole = 'cr';
                   4449:                                 } else {
                   4450:                                     $testrole = $role;
                   4451:                                 }
                   4452:                                 if (ref($domconfig{'usermodification'}{$context}{$testrole}) eq 'HASH') {
                   4453:                                     if ($domconfig{'usermodification'}{$context}{$testrole}{$field}) {
                   4454:                                         $canmodify{$field} = 1;
                   4455:                                         last;
                   4456:                                     }
                   4457:                                 }
                   4458:                             }
                   4459:                         } else {
                   4460:                             foreach my $key (keys(%{$domconfig{'usermodification'}{$context}})) {
                   4461:                                 if (ref($domconfig{'usermodification'}{$context}{$key}) eq 'HASH') {
                   4462:                                     if ($domconfig{'usermodification'}{$context}{$key}{$field}) {
                   4463:                                         $canmodify{$field} = 1;
                   4464:                                         last;
                   4465:                                     }
                   4466:                                 }
                   4467:                             }
                   4468:                         }
                   4469:                     }
                   4470:                 } elsif ($context eq 'course') {
                   4471:                     if (ref($userroles) eq 'ARRAY') {
                   4472:                         if (grep(/^st$/,@{$userroles})) {
                   4473:                             $canmodify{$field} = 1;
                   4474:                         }
                   4475:                     } else {
                   4476:                         $canmodify{$field} = 1;
                   4477:                     }
                   4478:                 }
                   4479:             }
                   4480:         }
                   4481:     }
                   4482:     return %canmodify;
                   4483: }
                   4484: 
1.18      raeburn  4485: sub check_usertype {
                   4486:     my ($dom,$uname,$rules) = @_;
                   4487:     my $usertype;
                   4488:     if (ref($rules) eq 'HASH') {
                   4489:         my @user_rules = keys(%{$rules});
                   4490:         if (@user_rules > 0) {
                   4491:             my %rule_check = &Apache::lonnet::inst_rulecheck($dom,$uname,undef,'username',\@user_rules);
                   4492:             if (keys(%rule_check) > 0) {
                   4493:                 $usertype = 'unofficial';
                   4494:                 foreach my $item (keys(%rule_check)) {
                   4495:                     if ($rule_check{$item}) {
                   4496:                         $usertype = 'official';
                   4497:                         last;
                   4498:                     }
                   4499:                 }
                   4500:             }
                   4501:         }
                   4502:     }
                   4503:     return $usertype;
                   4504: }
                   4505: 
1.17      raeburn  4506: sub roles_by_context {
                   4507:     my ($context,$custom) = @_;
                   4508:     my @allroles;
                   4509:     if ($context eq 'course') {
                   4510:         @allroles = ('st','ad','ta','ep','in','cc');
                   4511:         if ($custom) {
                   4512:             push(@allroles,'cr');
                   4513:         }
                   4514:     } elsif ($context eq 'author') {
                   4515:         @allroles = ('ca','aa');
                   4516:     } elsif ($context eq 'domain') {
                   4517:         @allroles = ('li','dg','sc','au','dc');
                   4518:     }
                   4519:     return @allroles;
                   4520: }
                   4521: 
1.16      raeburn  4522: sub get_permission {
1.17      raeburn  4523:     my ($context,$roles) = @_;
1.16      raeburn  4524:     my %permission;
                   4525:     if ($context eq 'course') {
1.17      raeburn  4526:         my $custom = 1;
                   4527:         my @allroles = &roles_by_context($context,$custom);
                   4528:         foreach my $role (@allroles) {
                   4529:             if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'})) {
                   4530:                 $permission{'cusr'} = 1;
                   4531:                 last;
                   4532:             }
1.16      raeburn  4533:         }
                   4534:         if (&Apache::lonnet::allowed('ccr',$env{'request.course.id'})) {
                   4535:             $permission{'custom'} = 1;
                   4536:         }
                   4537:         if (&Apache::lonnet::allowed('vcl',$env{'request.course.id'})) {
                   4538:             $permission{'view'} = 1;
                   4539:         }
                   4540:         if (!$permission{'view'}) {
                   4541:             my $scope = $env{'request.course.id'}.'/'.$env{'request.course.sec'};
                   4542:             $permission{'view'} =  &Apache::lonnet::allowed('vcl',$scope);
                   4543:             if ($permission{'view'}) {
                   4544:                 $permission{'view_section'} = $env{'request.course.sec'};
                   4545:             }
                   4546:         }
1.17      raeburn  4547:         if (!$permission{'cusr'}) {
                   4548:             if ($env{'request.course.sec'} ne '') {
                   4549:                 my $scope = $env{'request.course.id'}.'/'.$env{'request.course.sec'};
                   4550:                 $permission{'cusr'} = (&Apache::lonnet::allowed('cst',$scope));
                   4551:                 if ($permission{'cusr'}) {
                   4552:                     $permission{'cusr_section'} = $env{'request.course.sec'};
                   4553:                 }
                   4554:             }
                   4555:         }
1.16      raeburn  4556:         if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   4557:             $permission{'grp_manage'} = 1;
                   4558:         }
                   4559:     } elsif ($context eq 'author') {
                   4560:         $permission{'cusr'} = &authorpriv($env{'user.name'},$env{'request.role.domain'});
                   4561:         $permission{'view'} = $permission{'cusr'};
                   4562:     } else {
1.17      raeburn  4563:         my @allroles = &roles_by_context($context);
                   4564:         foreach my $role (@allroles) {
1.28      raeburn  4565:             if (&Apache::lonnet::allowed('c'.$role,$env{'request.role.domain'})) {
                   4566:                 $permission{'cusr'} = 1;
1.17      raeburn  4567:                 last;
                   4568:             }
                   4569:         }
                   4570:         if (!$permission{'cusr'}) {
                   4571:             if (&Apache::lonnet::allowed('mau',$env{'request.role.domain'})) {
                   4572:                 $permission{'cusr'} = 1;
                   4573:             }
1.16      raeburn  4574:         }
                   4575:         if (&Apache::lonnet::allowed('ccr',$env{'request.role.domain'})) {
                   4576:             $permission{'custom'} = 1;
                   4577:         }
                   4578:         $permission{'view'} = $permission{'cusr'};
                   4579:     }
                   4580:     my $allowed = 0;
                   4581:     foreach my $perm (values(%permission)) {
                   4582:         if ($perm) { $allowed=1; last; }
                   4583:     }
                   4584:     return (\%permission,$allowed);
                   4585: }
                   4586: 
                   4587: # ==================================================== Figure out author access
                   4588: 
                   4589: sub authorpriv {
                   4590:     my ($auname,$audom)=@_;
                   4591:     unless ((&Apache::lonnet::allowed('cca',$audom.'/'.$auname))
                   4592:          || (&Apache::lonnet::allowed('caa',$audom.'/'.$auname))) { return ''; }    return 1;
                   4593: }
                   4594: 
1.27      raeburn  4595: sub roles_on_upload {
1.42      raeburn  4596:     my ($context,$setting,%customroles) = @_;
1.27      raeburn  4597:     my (@possible_roles,@permitted_roles);
1.42      raeburn  4598:     @possible_roles = &curr_role_permissions($context,$setting,1);
1.27      raeburn  4599:     foreach my $role (@possible_roles) {
                   4600:         if ($role eq 'cr') {
                   4601:             push(@permitted_roles,keys(%customroles));
                   4602:         } else {
                   4603:             push(@permitted_roles,$role);
                   4604:         }
                   4605:     }
1.42      raeburn  4606:     return @permitted_roles;
1.27      raeburn  4607: }
                   4608: 
1.17      raeburn  4609: sub get_course_identity {
                   4610:     my ($cid) = @_;
                   4611:     my ($cnum,$cdom,$cdesc);
                   4612:     if ($cid eq '') {
                   4613:         $cid = $env{'request.course.id'}
                   4614:     }
                   4615:     if ($cid ne '') {
                   4616:         $cnum = $env{'course.'.$cid.'.num'};
                   4617:         $cdom = $env{'course.'.$cid.'.domain'};
                   4618:         $cdesc = $env{'course.'.$cid.'.description'};
                   4619:         if ($cnum eq '' || $cdom eq '') {
                   4620:             my %coursehash =
                   4621:                 &Apache::lonnet::coursedescription($cid,{'one_time' => 1});
                   4622:             $cdom = $coursehash{'domain'};
                   4623:             $cnum = $coursehash{'num'};
                   4624:             $cdesc = $coursehash{'description'};
                   4625:         }
                   4626:     }
                   4627:     return ($cnum,$cdom,$cdesc);
                   4628: }
                   4629: 
1.19      raeburn  4630: sub dc_setcourse_js {
1.37      raeburn  4631:     my ($formname,$mode,$context) = @_;
                   4632:     my ($dc_setcourse_code,$authen_check);
1.19      raeburn  4633:     my $cctext = &Apache::lonnet::plaintext('cc');
                   4634:     my %alerts = &sectioncheck_alerts();
                   4635:     my $role = 'role';
                   4636:     if ($mode eq 'upload') {
                   4637:         $role = 'courserole';
1.37      raeburn  4638:     } else {
                   4639:         $authen_check = &verify_authen($formname,$context);
1.19      raeburn  4640:     }
                   4641:     $dc_setcourse_code = (<<"SCRIPTTOP");
1.37      raeburn  4642: $authen_check
                   4643: 
1.19      raeburn  4644: function setCourse() {
                   4645:     var course = document.$formname.dccourse.value;
                   4646:     if (course != "") {
                   4647:         if (document.$formname.dcdomain.value != document.$formname.origdom.value) {
                   4648:             alert("$alerts{'curd'}");
                   4649:             return;
                   4650:         }
                   4651:         var userrole = document.$formname.$role.options[document.$formname.$role.selectedIndex].value
                   4652:         var section="";
                   4653:         var numsections = 0;
                   4654:         var newsecs = new Array();
                   4655:         for (var i=0; i<document.$formname.currsec.length; i++) {
                   4656:             if (document.$formname.currsec.options[i].selected == true ) {
                   4657:                 if (document.$formname.currsec.options[i].value != "" && document.$formname.currsec.options[i].value != null) {
                   4658:                     if (numsections == 0) {
                   4659:                         section = document.$formname.currsec.options[i].value
                   4660:                         numsections = 1;
                   4661:                     }
                   4662:                     else {
                   4663:                         section = section + "," +  document.$formname.currsec.options[i].value
                   4664:                         numsections ++;
                   4665:                     }
                   4666:                 }
                   4667:             }
                   4668:         }
                   4669:         if (document.$formname.newsec.value != "" && document.$formname.newsec.value != null) {
                   4670:             if (numsections == 0) {
                   4671:                 section = document.$formname.newsec.value
                   4672:             }
                   4673:             else {
                   4674:                 section = section + "," +  document.$formname.newsec.value
                   4675:             }
                   4676:             newsecs = document.$formname.newsec.value.split(/,/g);
                   4677:             numsections = numsections + newsecs.length;
                   4678:         }
                   4679:         if ((userrole == 'st') && (numsections > 1)) {
                   4680:             alert("$alerts{'inea'}. $alerts{'youh'} "+numsections+" $alerts{'sect'}.\\n$alerts{'plsm'}.")
                   4681:             return;
                   4682:         }
                   4683:         for (var j=0; j<newsecs.length; j++) {
                   4684:             if ((newsecs[j] == 'all') || (newsecs[j] == 'none')) {
                   4685:                 alert("'"+newsecs[j]+"' $alerts{'mayn'}.\\n$alerts{'plsc'}.");
                   4686:                 return;
                   4687:             }
                   4688:             if (document.$formname.groups.value != '') {
                   4689:                 var groups = document.$formname.groups.value.split(/,/g);
                   4690:                 for (var k=0; k<groups.length; k++) {
                   4691:                     if (newsecs[j] == groups[k]) {
                   4692:                         alert("'"+newsecs[j]+"' $alerts{'mayt'}.\\n$alerts{'secn'}. $alerts{'plsc'}.");
                   4693:                         return;
                   4694:                     }
                   4695:                 }
                   4696:             }
                   4697:         }
                   4698:         if ((userrole == 'cc') && (numsections > 0)) {
                   4699:             alert("$alerts{'secd'} $cctext $alerts{'role'}.\\n$alerts{'accr'}.");
                   4700:             section = "";
                   4701:         }
                   4702: SCRIPTTOP
                   4703:     if ($mode ne 'upload') {
                   4704:         $dc_setcourse_code .= (<<"ENDSCRIPT");
                   4705:         var coursename = "_$env{'request.role.domain'}"+"_"+course+"_"+userrole
                   4706:         var numcourse = getIndex(document.$formname.dccourse);
                   4707:         if (numcourse == "-1") {
                   4708:             alert("$alerts{'thwa'}");
                   4709:             return;
                   4710:         }
                   4711:         else {
                   4712:             document.$formname.elements[numcourse].name = "act"+coursename;
                   4713:             var numnewsec = getIndex(document.$formname.newsec);
                   4714:             if (numnewsec != "-1") {
                   4715:                 document.$formname.elements[numnewsec].name = "sec"+coursename;
                   4716:                 document.$formname.elements[numnewsec].value = section;
                   4717:             }
                   4718:             var numstart = getIndex(document.$formname.start);
                   4719:             if (numstart != "-1") {
                   4720:                 document.$formname.elements[numstart].name = "start"+coursename;
                   4721:             }
                   4722:             var numend = getIndex(document.$formname.end);
                   4723:             if (numend != "-1") {
                   4724:                 document.$formname.elements[numend].name = "end"+coursename
                   4725:             }
                   4726:         }
                   4727:     }
1.37      raeburn  4728:     var authcheck = auth_check();
                   4729:     if (authcheck == 'ok') {
                   4730:         document.$formname.submit();
                   4731:     }
1.19      raeburn  4732: }
                   4733: ENDSCRIPT
                   4734:     } else {
                   4735:         $dc_setcourse_code .=  "
                   4736:         document.$formname.sections.value = section;
                   4737:     }
                   4738:     return 'ok';
                   4739: }
                   4740: ";
                   4741:     }
                   4742:     $dc_setcourse_code .= (<<"ENDSCRIPT");
                   4743: 
                   4744:     function getIndex(caller) {
                   4745:         for (var i=0;i<document.$formname.elements.length;i++) {
                   4746:             if (document.$formname.elements[i] == caller) {
                   4747:                 return i;
                   4748:             }
                   4749:         }
                   4750:         return -1;
                   4751:     }
                   4752: ENDSCRIPT
1.37      raeburn  4753:     return $dc_setcourse_code;
                   4754: }
                   4755: 
                   4756: sub verify_authen {
                   4757:     my ($formname,$context) = @_;
                   4758:     my %alerts = &authcheck_alerts();
                   4759:     my $finish = "return 'ok';";
                   4760:     if ($context eq 'author') {
                   4761:         $finish = "document.$formname.submit();";
                   4762:     }
                   4763:     my $outcome = <<"ENDSCRIPT";
                   4764: 
                   4765: function auth_check() {
                   4766:     var logintype;
                   4767:     if (document.$formname.login.length) {
                   4768:         if (document.$formname.login.length > 0) {
                   4769:             var loginpicked = 0;
                   4770:             for (var i=0; i<document.$formname.login.length; i++) {
                   4771:                 if (document.$formname.login[i].checked == true) {
                   4772:                     loginpicked = 1;
                   4773:                     logintype = document.$formname.login[i].value;
                   4774:                 }
                   4775:             }
                   4776:             if (loginpicked == 0) {
                   4777:                 alert("$alerts{'authen'}");
                   4778:                 return;
                   4779:             }
                   4780:         }
                   4781:     } else {
                   4782:         logintype = document.$formname.login.value;
                   4783:     }
                   4784:     if (logintype == 'nochange') {
                   4785:         return 'ok';
                   4786:     }
                   4787:     var argpicked = document.$formname.elements[logintype+'arg'].value;
                   4788:     if ((argpicked == null) || (argpicked == '') || (typeof argpicked == 'undefined')) {
                   4789:         var alertmsg = '';
                   4790:         switch (logintype) {
                   4791:             case 'krb':
                   4792:                 alertmsg = '$alerts{'krb'}';
                   4793:                 break;
                   4794:             case 'int':
                   4795:                 alertmsg = '$alerts{'ipass'}';
                   4796:             case 'fsys':
                   4797:                 alertmsg = '$alerts{'ipass'}';
                   4798:                 break;
                   4799:             case 'loc':
                   4800:                 alertmsg = '';
                   4801:                 break;
                   4802:             default:
                   4803:                 alertmsg = '';
                   4804:         }
                   4805:         if (alertmsg != '') {
                   4806:             alert(alertmsg);
                   4807:             return;
                   4808:         }
                   4809:     }
                   4810:     $finish
                   4811: }
                   4812: ENDSCRIPT
1.19      raeburn  4813: }
                   4814: 
                   4815: sub sectioncheck_alerts {
                   4816:     my %alerts = &Apache::lonlocal::texthash(
                   4817:                     curd => 'You must select a course in the current domain',
                   4818:                     inea => 'In each course, each user may only have one student role at a time',
                   4819:                     youh => 'You had selected',
                   4820:                     sect => 'sections',
                   4821:                     plsm => 'Please modify your selections so they include no more than one section',
                   4822:                     mayn => 'may not be used as the name for a section, as it is a reserved word',
                   4823:                     plsc => 'Please choose a different section name',
                   4824:                     mayt => 'may not be used as the name for a section, as it is the name of a course group',
                   4825:                     secn => 'Section names and group names must be distinct',
                   4826:                     secd => 'Section designations do not apply to ',
                   4827:                     role => 'roles',
                   4828:                     accr => 'role will be added with access to all sections',
                   4829:                     thwa => 'There was a problem with your course selection'
                   4830:                  );
                   4831:     return %alerts;
                   4832: }
1.17      raeburn  4833: 
1.37      raeburn  4834: sub authcheck_alerts {
                   4835:     my %alerts = 
                   4836:         &Apache::lonlocal::texthash(
                   4837:                     authen => 'You must choose an authentication type.',
                   4838:                     krb    => 'You need to specify the Kerberos domain.',
                   4839:                     ipass  => 'You need to specify the initial password.',
                   4840:         );
                   4841:     return %alerts;
                   4842: }
                   4843: 
1.1       raeburn  4844: 1;
                   4845: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.