File:  [LON-CAPA] / loncom / interface / lonuserutils.pm
Revision 1.120: download - view: text, annotated - select for diffs
Fri Jul 9 14:40:20 2010 UTC (13 years, 10 months ago) by raeburn
Branches: MAIN
CVS tags: HEAD
- Bug 6333.
  Ensure that form element names for select boxes for institutional codes
  are always named Year, Semester, Department, Number, for consistency with
  names used in javascript to update select box items dynamically.

- Bug 5848.
  Assembly of institutional code from components conforms to order defined in
  localenroll::instcode_defaults().

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

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