Diff for /loncom/auth/lonroles.pm between versions 1.317 and 1.342

version 1.317, 2016/10/19 13:12:58 version 1.342, 2018/12/27 20:10:44
Line 145  use GDBM_File; Line 145  use GDBM_File;
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use HTML::Entities;  use HTML::Entities;
   
   my $registered_cleanup;
   my $rosterupdates;
   
 sub redirect_user {  sub redirect_user {
     my ($r,$title,$url,$msg) = @_;      my ($r,$title,$url,$msg) = @_;
Line 153  sub redirect_user { Line 155  sub redirect_user {
     &Apache::loncommon::no_cache($r);      &Apache::loncommon::no_cache($r);
     $r->send_http_header;      $r->send_http_header;
   
     # Breadcrumbs      my $start_page;
     my $brcrum = [{'href' => $url,      if ($env{'request.lti.login'}) {
                    'text' => 'Switching Role'},];          $start_page = &Apache::loncommon::start_page(undef,undef,
     my $start_page = &Apache::loncommon::start_page('Switching Role',undef,                                                       {'redirect' => [0,$url],}).$msg;
                                                     {'redirect' => [1,$url],      } else {
                                                      'bread_crumbs' => $brcrum,});          # Breadcrumbs
     my $end_page   = &Apache::loncommon::end_page();          my $brcrum = [{'href' => $url,
                          'text' => 'Switching Role'},];
           $start_page = &Apache::loncommon::start_page('Switching Role',undef,
                                                        {'redirect' => [1,$url],
                                                         'bread_crumbs' => $brcrum,}).
                         "\n<p>$msg</p>";
       }
       my $end_page = &Apache::loncommon::end_page();
   
 # Note to style police:   # Note to style police: 
 # This must only replace the spaces, nothing else, or it bombs elsewhere.  # This must only replace the spaces, nothing else, or it bombs elsewhere.
     $url=~s/ /\%20/g;      $url=~s/ /\%20/g;
     $r->print(<<ENDREDIR);      $r->print(<<ENDREDIR);
 $start_page  $start_page
 <p>$msg</p>  
 $end_page  $end_page
 ENDREDIR  ENDREDIR
     return;      return;
Line 204  sub handler { Line 212  sub handler {
     my $r = shift;      my $r = shift;
   
     # Check for critical messages and redirect if present.      # Check for critical messages and redirect if present.
     my ($redirect,$url) = &Apache::loncommon::critical_redirect(300);      my ($redirect,$url) = &Apache::loncommon::critical_redirect(300,'roles');
     if ($redirect) {      if ($redirect) {
         &Apache::loncommon::content_type($r,'text/html');          &Apache::loncommon::content_type($r,'text/html');
         $r->header_out(Location => $url);          $r->header_out(Location => $url);
Line 222  sub handler { Line 230  sub handler {
         $update = $then;          $update = $then;
     }      }
   
       $registered_cleanup=0;
       @{$rosterupdates}=();
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
   
 # -------------------------------------------------- Check if setting hot list   # -------------------------------------------------- Check if setting hot list 
Line 255  sub handler { Line 265  sub handler {
   
     my $envkey;      my $envkey;
     my %dcroles = ();      my %dcroles = ();
     my %dhroles = ();      my %helpdeskroles = ();
     my ($numdc,$numdh,$numadhoc) = &check_for_adhoc(\%dcroles,\%dhroles,$update,$then);      my ($numdc,$numhelpdesk,$numadhoc) = 
           &check_for_adhoc(\%dcroles,\%helpdeskroles,$update,$then);
     my $loncaparev = $r->dir_config('lonVersion');      my $loncaparev = $r->dir_config('lonVersion');
   
 # ================================================================== Roles Init  # ================================================================== Roles Init
     if ($env{'form.selectrole'}) {      if ($env{'form.selectrole'}) {
           if (($env{'request.lti.login'}) && ($env{'request.lti.target'} eq '')) {
               if ($env{'form.ltitarget'} eq 'iframe') {
                   &Apache::lonnet::appenv({'request.lti.target' => 'iframe'});
                   delete($env{'form.ltitarget'});
               }
           }
   
         my $locknum=&Apache::lonnet::get_locks();          my $locknum=&Apache::lonnet::get_locks();
         if ($locknum) { return 409; }          if ($locknum) { return 409; }
Line 268  sub handler { Line 285  sub handler {
         my $custom_adhoc;          my $custom_adhoc;
         if ($env{'form.newrole'}) {          if ($env{'form.newrole'}) {
             $env{'form.'.$env{'form.newrole'}}=1;              $env{'form.'.$env{'form.newrole'}}=1;
 # Check if this is a Domain Helpdesk role trying to enter a course  # Check if this is a Domain Helpdesk or Domain Helpdesk Assistant role trying to enter a course
             if ($env{'form.newrole'} =~ m{^cr/($match_domain)/\1\-domainconfig/\w+\./\1/$match_courseid$}) {              if ($env{'form.newrole'} =~ m{^cr/($match_domain)/\1\-domainconfig/\w+\./\1/$match_courseid$}) {
                 if ($dhroles{$1}) {                  if ($helpdeskroles{$1}) {
                     $custom_adhoc = 1;                      $custom_adhoc = 1;
                 }                  }
             }              }
Line 305  sub handler { Line 322  sub handler {
                                  "request.role.adv"            => $env{'user.adv'},                                   "request.role.adv"            => $env{'user.adv'},
  "request.role.domain"         => $env{'user.domain'}});   "request.role.domain"         => $env{'user.domain'}});
 # Check if Domain Helpdesk role trying to enter a course needs privs to be created  # Check if Domain Helpdesk role trying to enter a course needs privs to be created
         if ($env{'form.newrole'} =~ m{^cr/($match_domain)/\1\-domainconfig/(\w+)\./\1/($match_courseid)$}) {          if ($env{'form.newrole'} =~ m{^cr/($match_domain)/\1\-domainconfig/(\w+)\./\1/($match_courseid)(?:/(\w+)|$)}) {
             my $cdom = $1;              my $cdom = $1;
             my $rolename = $2;              my $rolename = $2;
             my $cnum = $3;              my $cnum = $3;
               my $sec = $4;
             if ($custom_adhoc) {              if ($custom_adhoc) {
                 my %adhocroles = &Apache::lonnet::userenvironment($env{'user.domain'},$env{'user.name'},                  my ($possroles,$description) = &Apache::lonnet::get_my_adhocroles($cdom.'_'.$cnum,1);
                                                                   'adhocroles.'.$cdom);                  if (ref($possroles) eq 'ARRAY') {
                 if (keys(%adhocroles)) {                      if (grep(/^\Q$rolename\E$/,@{$possroles})) { 
                     my @adhoc = split(',',$adhocroles{'adhocroles.'.$cdom});  
                     if (grep(/^\Q$rolename\E$/,@adhoc)) {  
                         if (&Apache::lonnet::check_adhoc_privs($cdom,$cnum,$update,$refresh,$now,                          if (&Apache::lonnet::check_adhoc_privs($cdom,$cnum,$update,$refresh,$now,
                                                                "cr/$cdom/$cdom".'-domainconfig/'.$rolename)) {                                                                 "cr/$cdom/$cdom".'-domainconfig/'.$rolename,undef,$sec)) {
                             &Apache::lonnet::appenv({"environment.internal.$cdom.$cnum.cr/$cdom/$cdom".'-domainconfig/'."$rolename.adhoc" => time});                              &Apache::lonnet::appenv({"environment.internal.$cdom.$cnum.cr/$cdom/$cdom".'-domainconfig/'."$rolename.adhoc" => time});
                         }                          }
                     }                      }
                 }                  }
             }              }
         } elsif ($numdc > 0) {          } elsif (($numdc > 0) || ($numhelpdesk > 0)) {
 # Check if user is a DC trying to enter a course or author space and needs privs to be created  # Check if user is a DC trying to enter a course or author space and needs privs to be created
   # Check if user is a DH or DA trying to enter a course and needs privs to be created
             foreach my $envkey (keys(%env)) {              foreach my $envkey (keys(%env)) {
 # Is this an ad-hoc Coordinator role?  # Is this an ad-hoc Coordinator role?
                 if (my ($ccrole,$domain,$coursenum) =                  if ($numdc) {
     ($envkey =~ m-^form\.(cc|co)\./($match_domain)/($match_courseid)$-)) {                      if (my ($ccrole,$domain,$coursenum) =
                     if ($dcroles{$domain}) {          ($envkey =~ m-^form\.(cc|co)\./($match_domain)/($match_courseid)$-)) {
                         if (&Apache::lonnet::check_adhoc_privs($domain,$coursenum,                          if ($dcroles{$domain}) {
                                                            $update,$refresh,$now,$ccrole)) {                              if (&Apache::lonnet::check_adhoc_privs($domain,$coursenum,
                             &Apache::lonnet::appenv({"environment.internal.$domain.$coursenum.$ccrole.adhoc" => time});                                                                     $update,$refresh,$now,$ccrole)) {
                         }                                  &Apache::lonnet::appenv({"environment.internal.$domain.$coursenum.$ccrole.adhoc" => time});
                     }                              }
                     last;  
                 }  
 # Is this an ad-hoc CA-role?  
                 if (my ($domain,$user) =  
     ($envkey =~ m-^form\.ca\./($match_domain)/($match_username)$-)) {  
                     if (($domain eq $env{'user.domain'}) && ($user eq $env{'user.name'})) {  
                         delete($env{$envkey});  
                         $env{'form.au./'.$domain.'/'} = 1;  
                         my ($server_status,$home) = &check_author_homeserver($user,$domain);  
                         if ($server_status eq 'switchserver') {  
                             my $trolecode = 'au./'.$domain.'/';  
                             my $switchserver = '/adm/switchserver?otherserver='.$home.'&amp;role='.$trolecode;  
                             $r->internal_redirect($switchserver);  
                             return OK;  
                         }                          }
                         last;                          last;
                     }                      }
                     if (my ($castart,$caend) = ($env{'user.role.ca./'.$domain.'/'.$user} =~ /^(\d*)\.(\d*)$/)) {  # Is this an ad-hoc CA-role?
                         if (((($castart) && ($castart < $now)) || !$castart) &&                       if (my ($domain,$user) =
                             ((!$caend) || (($caend) && ($caend > $now)))) {          ($envkey =~ m-^form\.ca\./($match_domain)/($match_username)$-)) {
                           if (($domain eq $env{'user.domain'}) && ($user eq $env{'user.name'})) {
                               delete($env{$envkey});
                               $env{'form.au./'.$domain.'/'} = 1;
                             my ($server_status,$home) = &check_author_homeserver($user,$domain);                              my ($server_status,$home) = &check_author_homeserver($user,$domain);
                             if ($server_status eq 'switchserver') {                              if ($server_status eq 'switchserver') {
                                 my $trolecode = 'ca./'.$domain.'/'.$user;                                  my $trolecode = 'au./'.$domain.'/';
                                 my $switchserver = '/adm/switchserver?otherserver='.$home.'&amp;role='.$trolecode;                                  my $switchserver = '/adm/switchserver?otherserver='.$home.'&amp;role='.$trolecode;
                                 $r->internal_redirect($switchserver);                                  $r->internal_redirect($switchserver);
                                 return OK;                                  return OK;
                             }                              }
                             last;                              last;
                         }                          }
                     }                          if (my ($castart,$caend) = ($env{'user.role.ca./'.$domain.'/'.$user} =~ /^(\d*)\.(\d*)$/)) {
                     # Check if author blocked ca-access                              if (((($castart) && ($castart < $now)) || !$castart) && 
                     my %blocked=&Apache::lonnet::get('environment',['domcoord.author'],$domain,$user);                                  ((!$caend) || (($caend) && ($caend > $now)))) {
                     if ($blocked{'domcoord.author'} eq 'blocked') {                                  my ($server_status,$home) = &check_author_homeserver($user,$domain);
                         delete($env{$envkey});                                  if ($server_status eq 'switchserver') {
                         $env{'user.error.msg'}=':::1:User '.$user.' in domain '.$domain.' blocked domain coordinator access';                                      my $trolecode = 'ca./'.$domain.'/'.$user;
                                       my $switchserver = '/adm/switchserver?otherserver='.$home.'&amp;role='.$trolecode;
                                       $r->internal_redirect($switchserver);
                                       return OK;
                                   }
                                   last;
                               }
                           }
                           # Check if author blocked ca-access
                           my %blocked=&Apache::lonnet::get('environment',['domcoord.author'],$domain,$user);
                           if ($blocked{'domcoord.author'} eq 'blocked') {
                               delete($env{$envkey});
                               $env{'user.error.msg'}=':::1:User '.$user.' in domain '.$domain.' blocked domain coordinator access';
                               last;
                           }
                           if ($dcroles{$domain}) {
                               my ($server_status,$home) = &check_author_homeserver($user,$domain);
                               if (($server_status eq 'ok') || ($server_status eq 'switchserver')) {
                                   &Apache::lonnet::check_adhoc_privs($domain,$user,$update,
                                                                      $refresh,$now,'ca');
                                   if ($server_status eq 'switchserver') {
                                       my $trolecode = 'ca./'.$domain.'/'.$user; 
                                       my $switchserver = '/adm/switchserver?'
                                                         .'otherserver='.$home.'&amp;role='.$trolecode;
                                       $r->internal_redirect($switchserver);
                                       return OK;
                                   }
                               } else {
                                   delete($env{$envkey});
                               }
                           } else {
                               delete($env{$envkey});
                           }
                         last;                          last;
                     }                      }
                     if ($dcroles{$domain}) {                  }
                         my ($server_status,$home) = &check_author_homeserver($user,$domain);                  if ($numhelpdesk) {
                         if (($server_status eq 'ok') || ($server_status eq 'switchserver')) {  # Is this an ad hoc custom role in a course/community?
                             &Apache::lonnet::check_adhoc_privs($domain,$user,$update,                      if (my ($domain,$rolename,$coursenum,$sec) = ($envkey =~ m{^form\.cr/($match_domain)/\1\-domainconfig/(\w+)\./\1/($match_courseid)(?:/(\w+)|$)})) {
                                                                $refresh,$now,'ca');                          if ($helpdeskroles{$domain}) {
                             if ($server_status eq 'switchserver') {                              my ($possroles,$description) = &Apache::lonnet::get_my_adhocroles($domain.'_'.$coursenum,1);
                                 my $trolecode = 'ca./'.$domain.'/'.$user;                               if (ref($possroles) eq 'ARRAY') {
                                 my $switchserver = '/adm/switchserver?'                                  if (grep(/^\Q$rolename\E$/,@{$possroles})) {
                                                   .'otherserver='.$home.'&amp;role='.$trolecode;                                      if (&Apache::lonnet::check_adhoc_privs($domain,$coursenum,$update,$refresh,$now,
                                 $r->internal_redirect($switchserver);                                                                             "cr/$domain/$domain".'-domainconfig/'.$rolename,
                                 return OK;                                                                             undef,$sec)) {
                                           &Apache::lonnet::appenv({"environment.internal.$domain.$coursenum.cr/$domain/$domain".
                                                                    '-domainconfig/'."$rolename.adhoc" => time});
                                       }
                                   } else {
                                       delete($env{$envkey});
                                   }
                               } else {
                                   delete($env{$envkey});
                             }                              }
                         } else {                          } else {
                             delete($env{$envkey});                              delete($env{$envkey});
                         }                          }
                     } else {                          last;
                         delete($env{$envkey});  
                     }                      }
                     last;  
                 }                  }
             }              }
         }          }
   
         foreach $envkey (keys(%env)) {          foreach $envkey (keys(%env)) {
             next if ($envkey!~/^user\.role\./);              next if ($envkey!~/^user\.role\./);
             my ($where,$trolecode,$role,$tstatus,$tend,$tstart);              my ($where,$trolecode,$role,$tstatus,$tend,$tstart);
Line 529  ENDENTERKEY Line 572  ENDENTERKEY
  $env{'user.name'},   $env{'user.name'},
  $env{'user.home'},   $env{'user.home'},
  "Role ".$trolecode);   "Role ".$trolecode);
       
     &Apache::lonnet::appenv(      &Apache::lonnet::appenv(
    {'request.role'        => $trolecode,     {'request.role'        => $trolecode,
     'request.role.domain' => $cdom,      'request.role.domain' => $cdom,
Line 538  ENDENTERKEY Line 581  ENDENTERKEY
                     my $tadv=0;                      my $tadv=0;
   
     if (($cnum) && ($role ne 'ca') && ($role ne 'aa')) {      if (($cnum) && ($role ne 'ca') && ($role ne 'aa')) {
                           if ($role =~ m{^\Qcr/$cdom/$cdom\E\-domainconfig/(\w+)$}) {
                               my $rolename = $1;
                               my %domdef = &Apache::lonnet::get_domain_defaults($cdom);
                               if (ref($domdef{'adhocroles'}) eq 'HASH') {
                                   if (ref($domdef{'adhocroles'}{$rolename}) eq 'HASH') {
                                       &Apache::lonnet::appenv({'request.role.desc' => $domdef{'adhocroles'}{$rolename}{'desc'}});
                                   }
                               }
                           }
                         my $msg;                          my $msg;
  my ($furl,$ferr)=   my ($furl,$ferr)=
     &Apache::lonuserstate::readmap($cdom.'/'.$cnum);      &Apache::lonuserstate::readmap($cdom.'/'.$cnum);
                         unless ($ferr) {                          unless ($ferr) {
                               &Apache::lonnet::appenv({'request.course.timechecked'=>$now});
                             unless (($env{'form.switchrole'}) ||                               unless (($env{'form.switchrole'}) || 
                                     ($env{"environment.internal.$cdom.$cnum.$role.adhoc"})) {                                      ($env{"environment.internal.$cdom.$cnum.$role.adhoc"})) {
                                 &Apache::lonnet::put('nohist_crslastlogin',                                  &Apache::lonnet::put('nohist_crslastlogin',
                                     {$env{'user.name'}.':'.$env{'user.domain'}.                                      {$env{'user.name'}.':'.$env{'user.domain'}.
                                      ':'.$csec.':'.$role => $now},$cdom,$cnum);                                       ':'.$csec.':'.$role => $now},$cdom,$cnum);
                             }                              }
                               if (($env{"environment.internal.$cdom.$cnum.$role.adhoc"}) &&
                                   (&Apache::lonnet::allowed('vxc',$cdom.'_'.$cnum))) {
                                   my $owner = $env{'course.'.$cdom.'_'.$cnum.'.internal.courseowner'};
                                   my @coowners = split(/,/,$env{'course.'.$env{'request.course.id'}.'.internal.co-owners'});
                                   my %auaccess;
                                   foreach my $user ($owner,@coowners) {
                                       my ($cpname,$cpdom) = split(/:/,$user);
                                       my %auroles = &Apache::lonnet::get_my_roles($cpname,$cpdom,'userroles',undef,['au','ca','aa'],[$cdom]);
                                       foreach my $key (keys(%auroles)) {
                                           my ($auname,$audom,$aurole) = split(/:/,$key);
                                           if ($aurole eq 'au') {
                                               $auaccess{$cpname} = 1;
                                           } else {
                                               $auaccess{$auname} = 1;
                                           }
                                       }
                                   }
                                   &Apache::lonnet::appenv({'request.course.adhocsrcaccess' => join(',',sort(keys(%auaccess))) });
                               }
                             my ($feeds,$syllabus_time);                              my ($feeds,$syllabus_time);
                             &Apache::lonrss::advertisefeeds($cnum,$cdom,undef,\$feeds);                              &Apache::lonrss::advertisefeeds($cnum,$cdom,undef,\$feeds);
                             &Apache::lonnet::appenv({'request.course.feeds' => $feeds});                              &Apache::lonnet::appenv({'request.course.feeds' => $feeds});
Line 587  ENDENTERKEY Line 659  ENDENTERKEY
                                                                                        $cdom.'_'.$cnum);                                                                                         $cdom.'_'.$cnum);
                                     }                                      }
                                 }                                  }
                                   if (($env{'request.lti.login'}) &&
                                       ($env{'request.lti.rosterid'} || $env{'request.lti.passbackid'})) {
                                       &process_lti($r,$cdom,$cnum);
                                   }
  $r->internal_redirect($dest);   $r->internal_redirect($dest);
     }      }
     return OK;      return OK;
Line 608  ENDENTERKEY Line 684  ENDENTERKEY
     if (($ferr) && ($tadv)) {      if (($ferr) && ($tadv)) {
  &error_page($r,$ferr,$furl);   &error_page($r,$ferr,$furl);
     } else {      } else {
                                   if (($env{'request.lti.login'}) &&
                                       ($env{'request.lti.rosterid'} || $env{'request.lti.passbackid'})) {
                                       &process_lti($r,$cdom,$cnum);
                                   }
  # Check to see if the user is a CC entering a course    # Check to see if the user is a CC entering a course 
  # for the first time   # for the first time
  if ((($role eq 'cc') || ($role eq 'co'))    if ((($role eq 'cc') || ($role eq 'co')) 
Line 638  ENDENTERKEY Line 718  ENDENTERKEY
                                                     }                                                      }
                                                 }                                                  }
                                             }                                              }
                                               if (($dest =~ m{^\Q/public/$cdom/$cnum/syllabus\E.*(\?|\&)usehttp=1}) ||
                                                   ($dest =~ m{^\Q/adm/wrapper/ext/\E(?!https:)})) {
                                                   if ($ENV{'SERVER_PORT'} == 443) {
                                                       unless (&Apache::lonnet::uses_sts()) {
                                                           my $hostname = $r->hostname();
                                                           if ($hostname ne '') {
                                                               $dest = 'http://'.$hostname.$dest;
                                                           }
                                                       }
                                                   }
                                               }
                                             if ($dest =~ m{^/enc/}) {                                              if ($dest =~ m{^/enc/}) {
                                                 if ($env{'request.role.adv'}) {                                                  if ($env{'request.role.adv'}) {
                                                     $dest = &Apache::lonenc::unencrypted($dest);                                                      $dest = &Apache::lonenc::unencrypted($dest);
Line 670  ENDENTERKEY Line 761  ENDENTERKEY
                                         unless (($dest =~ m{^/enc/}) || ($dest =~ /(\?|\&)symb=.+___\d+___.+/)) {                                          unless (($dest =~ m{^/enc/}) || ($dest =~ /(\?|\&)symb=.+___\d+___.+/)) {
                                             if (($destsymb ne '') && ($destsymb !~ m{^/enc/})) {                                              if (($destsymb ne '') && ($destsymb !~ m{^/enc/})) {
                                                 my $esc_symb = &escape($destsymb);                                                  my $esc_symb = &escape($destsymb);
                                                 $dest .= '?symb='.$esc_symb;                                                  $dest .= (($dest =~/\?/)? '&':'?').'symb='.$esc_symb;
                                             }                                              }
                                         }                                          }
                                         &redirect_user($r, &mt('Entering [_1]',                                          my $title;
                                                        $env{'course.'.$cdom.'_'.$cnum.'.description'}),                                          unless ($env{'request.lti.login'}) {
                                                        $dest, $msg);                                              $title = &mt('Entering [_1]',
                                                            $env{'course.'.$cdom.'_'.$cnum.'.description'});
                                           }
                                           &redirect_user($r,$title,$dest,$msg);
                                         return OK;                                          return OK;
                                     }                                      }
     if (&Apache::lonnet::allowed('whn',      if (&Apache::lonnet::allowed('whn',
Line 713  ENDENTERKEY Line 807  ENDENTERKEY
                                 } elsif ($access eq 'B') {                                  } elsif ($access eq 'B') {
                                     $furl = '/adm/navmaps?showOnlyHomework=1';                                      $furl = '/adm/navmaps?showOnlyHomework=1';
                                 }                                  }
                                 $msg = &mt('Entering [_1] ...',                                  my $title;
    $env{'course.'.$cdom.'_'.$cnum.'.description'});                                  if ($env{'request.lti.login'}) {
  &redirect_user($r, &mt('Entering [_1]',                                      undef($msg);
                                $env{'course.'.$cdom.'_'.$cnum.'.description'}),                                  } else {
                                $furl, $msg);                                      $title = &mt('Entering [_1]',
                                                    $env{'course.'.$cdom.'_'.$cnum.'.description'});
                                       $msg = &mt('Entering [_1] ...',
          $env{'course.'.$cdom.'_'.$cnum.'.description'});
                                   }
    &redirect_user($r,$title,$furl,$msg);
     }      }
     return OK;      return OK;
  }   }
Line 748  ENDENTERKEY Line 847  ENDENTERKEY
                                        $redirect_url);                                         $redirect_url);
                         return OK;                          return OK;
                     }                      }
                       if ($role eq 'da') {
                           my $redirect_url = '/adm/menu/';
                           &redirect_user($r,&mt('Loading Domain Helpdesk Assistant Menu'),
                                          $redirect_url);
                           return OK;
                       }
                     if ($role eq 'sc') {                      if ($role eq 'sc') {
                         my $redirect_url = '/adm/grades?command=scantronupload';                          my $redirect_url = '/adm/grades?command=scantronupload';
                         &redirect_user($r,&mt('Loading Data Upload Page'),                          &redirect_user($r,&mt('Loading Data Upload Page'),
Line 1010  ENDHEADER Line 1115  ENDHEADER
             my $doheaders = &roletable_headers($r,\%roleclass,\%sortrole,              my $doheaders = &roletable_headers($r,\%roleclass,\%sortrole,
                                                $nochoose);                                                 $nochoose);
             &print_rolerows($r,$doheaders,\%roleclass,\%sortrole,\%dcroles,              &print_rolerows($r,$doheaders,\%roleclass,\%sortrole,\%dcroles,
                             \%roletext);                              \%roletext,$update,$then);
             my $tremark='';              my $tremark='';
             my $tbg;              my $tbg;
             if ($env{'request.role'} eq 'cm') {              if ($env{'request.role'} eq 'cm') {
Line 1045  ENDHEADER Line 1150  ENDHEADER
     }      }
 # ----------------------------------------------------------------------- Table  # ----------------------------------------------------------------------- Table
   
     if (($numdc > 0) || (($numdh > 0) && ($numadhoc > 0))) {      if (($numdc > 0) || (($numhelpdesk > 0) && ($numadhoc > 0))) {
         $r->print(&coursepick_jscript());          $r->print(&coursepick_jscript().
         $r->print(&Apache::loncommon::coursebrowser_javascript().                    &Apache::loncommon::coursebrowser_javascript());
                   &Apache::loncommon::authorbrowser_javascript());      }
       if ($numdc > 0) {
           $r->print(&Apache::loncommon::authorbrowser_javascript());
     }      }
   
     unless ((!&Apache::loncommon::show_course()) || ($nochoose) || ($countactive==1)) {      unless ((!&Apache::loncommon::show_course()) || ($nochoose) || ($countactive==1)) {
Line 1078  ENDHEADER Line 1185  ENDHEADER
                                $roletext{'user.role.'.$role}->[1].                                 $roletext{'user.role.'.$role}->[1].
                                &Apache::loncommon::end_data_table_row();                                 &Apache::loncommon::end_data_table_row();
                 }                  }
                 if ($role =~ m{^user\.role\.dc\./($match_domain)/}                   if ($role =~ m{^dc\./($match_domain)/$} 
     && $dcroles{$1}) {      && $dcroles{$1}) {
     $output .= &adhoc_roles_row($1,'recent');      $output .= &adhoc_roles_row($1,'recent');
                 } elsif ($role =~ m{^user\.role\.dh\./($match_domain)/}                  } elsif ($role =~ m{^(dh|da)\./($match_domain)/$}) {
                          && ($env{'environment.adhocroles.'.$1} ne '')) {                      $output .= &adhoc_customroles_row($1,$2,'recent',$update,$then);
                     $output .= &adhoc_customroles_row($1,'recent');  
                 }                  }
     } elsif ($numdc > 0) {      } elsif ($numdc > 0) {
                 unless ($role =~/^error\:/) {                  unless ($role =~/^error\:/) {
Line 1112  ENDHEADER Line 1218  ENDHEADER
             $doheaders ++;              $doheaders ++;
  }   }
     }      }
     &print_rolerows($r,$doheaders,\%roleclass,\%sortrole,\%dcroles,\%roletext);      &print_rolerows($r,$doheaders,\%roleclass,\%sortrole,\%dcroles,\%roletext,$update,$then);
     if ($countactive > 1) {      if ($countactive > 1) {
         my $tremark='';          my $tremark='';
         my $tbg;          my $tbg;
Line 1188  sub gather_roles { Line 1294  sub gather_roles {
     my $advanced = $env{'user.adv'};      my $advanced = $env{'user.adv'};
     my $tryagain = $env{'form.tryagain'};      my $tryagain = $env{'form.tryagain'};
     my @ids = &Apache::lonnet::current_machine_ids();      my @ids = &Apache::lonnet::current_machine_ids();
       my (%willtrust,%trustchecked);
     if (ref($roles_in_env) eq 'HASH') {      if (ref($roles_in_env) eq 'HASH') {
           my %adhocdesc;
         foreach my $envkey (sort(keys(%{$roles_in_env}))) {          foreach my $envkey (sort(keys(%{$roles_in_env}))) {
             my $button = 1;              my $button = 1;
             my $switchserver='';              my $switchserver='';
Line 1240  sub gather_roles { Line 1348  sub gather_roles {
                 my $trole;                  my $trole;
                 if ($role =~ /^cr\//) {                  if ($role =~ /^cr\//) {
                     my ($rdummy,$rdomain,$rauthor,$rrole)=split(/\//,$role);                      my ($rdummy,$rdomain,$rauthor,$rrole)=split(/\//,$role);
                     if ($tremark) { $tremark.='<br />'; }                      unless ($rauthor eq $rdomain.'-domainconfig') {
                     $tremark.=&mt('Custom role defined by [_1].',$rauthor.':'.$rdomain);                          if ($tremark) { $tremark.='<br />'; }
                           $tremark.=&mt('Custom role defined by [_1].',$rauthor.':'.$rdomain);
                       }
                 }                  }
                 $trole=Apache::lonnet::plaintext($role);                  $trole=Apache::lonnet::plaintext($role);
                 my $ttype;                  my $ttype;
Line 1253  sub gather_roles { Line 1363  sub gather_roles {
                 if (($role eq 'ca') || ($role eq 'aa')) {                  if (($role eq 'ca') || ($role eq 'aa')) {
                     my $home = &Apache::lonnet::homeserver($trest,$tdom);                      my $home = &Apache::lonnet::homeserver($trest,$tdom);
                     my $allowed=0;                      my $allowed=0;
                       my $prohibited;
                     foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }                      foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
                     if (!$allowed) {                      if (!$allowed) {
                         $button=0;                          $button=0;
                         $switchserver='otherserver='.$home.'&amp;role='.$trolecode;                          unless ($trustchecked{$tdom}) {
                               if ((&Apache::lonnet::will_trust('othcoau',$env{'user.domain'},$tdom)) &&
                                   (&Apache::lonnet::will_trust('coaurem',$tdom,$env{'user.domain'}))) {
                                   $willtrust{$tdom} = 1;
                                   $trustchecked{$tdom} = 1;
                               }
                           } 
                           if ($willtrust{$tdom}) {
                               $switchserver='otherserver='.$home.'&amp;role='.$trolecode;
                           } else {
                               $prohibited = 1;
                               $tremark .= &mt('Session switch required but prohibited.');
                           }
                     }                      }
                     #next if ($home eq 'no_host');                      #next if ($home eq 'no_host');
                     $home = &Apache::lonnet::hostname($home);                      $home = &Apache::lonnet::hostname($home);
Line 1265  sub gather_roles { Line 1388  sub gather_roles {
                         ': '.$tdom.'<br />'.                          ': '.$tdom.'<br />'.
                         ' '.&mt('Server').':&nbsp;'.$home;                          ' '.&mt('Server').':&nbsp;'.$home;
                     $env{'course.'.$tdom.'_'.$trest.'.description'}='ca';                      $env{'course.'.$tdom.'_'.$trest.'.description'}='ca';
                     $tremark.=&Apache::lonhtmlcommon::authorbombs('/res/'.$tdom.'/'.$trest.'/');                      unless ($prohibited) {
                           $tremark.=&Apache::lonhtmlcommon::authorbombs('/res/'.$tdom.'/'.$trest.'/');
                       }
                     $sortkey=$role."$trest:$tdom";                      $sortkey=$role."$trest:$tdom";
                 } elsif ($role eq 'au') {                  } elsif ($role eq 'au') {
                     # Authors                      # Authors
Line 1288  sub gather_roles { Line 1413  sub gather_roles {
                 } elsif ($trest) {                  } elsif ($trest) {
                     my $tcourseid=$tdom.'_'.$trest;                      my $tcourseid=$tdom.'_'.$trest;
                     $ttype = &Apache::loncommon::course_type($tcourseid);                      $ttype = &Apache::loncommon::course_type($tcourseid);
                     $trole = &Apache::lonnet::plaintext($role,$ttype,$tcourseid);                      if ($role !~ /^cr/) {
                           $trole = &Apache::lonnet::plaintext($role,$ttype,$tcourseid);
                       } elsif ($role =~ m{^\Qcr/$tdom/$tdom\E\-domainconfig/(\w+)$}) {
                           my $rolename = $1;
                           my $desc;
                           if (ref($adhocdesc{$tdom}) eq 'HASH') {
                               $desc = $adhocdesc{$tdom}{$rolename};
                           } else {
                               my %domdef = &Apache::lonnet::get_domain_defaults($tdom);
                               if (ref($domdef{'adhocroles'}) eq 'HASH') {
                                   foreach my $rolename (sort(keys(%{$domdef{'adhocroles'}}))) {
                                       if (ref($domdef{'adhocroles'}{$rolename}) eq 'HASH') {
                                           $adhocdesc{$tdom}{$rolename} = $domdef{'adhocroles'}{$rolename}{'desc'};
                                           $desc = $adhocdesc{$tdom}{$rolename};
                                       }
                                   }
                               }
                           }
                           if ($desc ne '') {
                               $trole = $desc;
                           } else {
                               $trole = &mt('Helpdesk[_1]','&nbsp;'.$rolename);
                           }
                       } else {
                           $trole = (split(/\//,$role,4))[-1];
                       }
                     if ($env{'course.'.$tcourseid.'.description'}) {                      if ($env{'course.'.$tcourseid.'.description'}) {
                         my $home=$env{'course.'.$tcourseid.'.home'};                          my $home=$env{'course.'.$tcourseid.'.home'};
                         $twhere=$env{'course.'.$tcourseid.'.description'};                          $twhere=$env{'course.'.$tcourseid.'.description'};
Line 1462  sub roletypes { Line 1612  sub roletypes {
 }  }
   
 sub print_rolerows {  sub print_rolerows {
     my ($r,$doheaders,$roleclass,$sortrole,$dcroles,$roletext) = @_;      my ($r,$doheaders,$roleclass,$sortrole,$dcroles,$roletext,$update,$then) = @_;
     if ((ref($roleclass) eq 'HASH') && (ref($sortrole) eq 'HASH')) {      if ((ref($roleclass) eq 'HASH') && (ref($sortrole) eq 'HASH')) {
         my @types = &roletypes();          my @types = &roletypes();
         foreach my $type (@types) {          foreach my $type (@types) {
Line 1486  sub print_rolerows { Line 1636  sub print_rolerows {
                                     $output .= &adhoc_roles_row($1,'');                                      $output .= &adhoc_roles_row($1,'');
                                 }                                  }
                             }                              }
                         } elsif (($sortrole->{$which} =~ m{^user\.role\.dh\./($match_domain)/}) &&                          } elsif ($sortrole->{$which} =~ m{^user\.role\.(dh|da)\./($match_domain)/}) {
                                  ($env{'environment.adhocroles.'.$1} ne '')) {                              $output .= &adhoc_customroles_row($1,$2,'',$update,$then);
                             $output .= &adhoc_customroles_row($1,'');  
                         }                          }
                     }                      }
                 }                  }
Line 1520  sub findcourse_advice { Line 1669  sub findcourse_advice {
  <li>'.&mt('You are in a section of course for which automatic enrollment in the corresponding LON-CAPA course is not active.').'</li>   <li>'.&mt('You are in a section of course for which automatic enrollment in the corresponding LON-CAPA course is not active.').'</li>
  <li>'.&mt('The start date for automated enrollment has yet to be reached.').'</li>   <li>'.&mt('The start date for automated enrollment has yet to be reached.').'</li>
  <li>'.&mt('You registered for the course recently and there is a time lag between the time you register, and the time this information becomes available for the update of LON-CAPA course rosters.').'</li>   <li>'.&mt('You registered for the course recently and there is a time lag between the time you register, and the time this information becomes available for the update of LON-CAPA course rosters.').'</li>
    <li>'.&mt('Automated enrollment added you to the course in the time since you last logged in.').' '.&mt('If that is the case you can use the "Check for changes" link in the gray Functions bar to update the list of your available course roles.').'</li>   
  </ul>');   </ul>');
     } else {      } else {
         $r->print(&mt('If you were expecting to see an active role listed for a particular course, that course may not have been created yet.').'<br />');          $r->print(&mt('If you were expecting to see an active role listed for a particular course, that course may not have been created yet.').'<br />');
Line 1658  sub privileges_info { Line 1808  sub privileges_info {
 sub build_roletext {  sub build_roletext {
     my ($trolecode,$tdom,$trest,$tstatus,$tryagain,$advanced,$tremark,$tbg,$trole,$twhere,      my ($trolecode,$tdom,$trest,$tstatus,$tryagain,$advanced,$tremark,$tbg,$trole,$twhere,
         $tpstart,$tpend,$nochoose,$button,$switchserver,$reinit,$switchwarning,$skipcal) = @_;          $tpstart,$tpend,$nochoose,$button,$switchserver,$reinit,$switchwarning,$skipcal) = @_;
     my ($roletext,$roletext_end);      my ($roletext,$roletext_end,$poss_adhoc);
     my $is_dc=($trolecode =~ m/^dc\./);      if ($trolecode =~ m/^d(c|h|a)\./) {
     my $rowspan=($is_dc) ? ''          $poss_adhoc = 1;
       }
       my $rowspan=($poss_adhoc) ? ''
                          : ' rowspan="2" ';                           : ' rowspan="2" ';
   
     unless ($nochoose) {      unless ($nochoose) {
Line 1721  sub build_roletext { Line 1873  sub build_roletext {
               .'<td>'.$twhere.'</td>'                .'<td>'.$twhere.'</td>'
               .'<td>'.$tpstart.'</td>'                .'<td>'.$tpstart.'</td>'
               .'<td>'.$tpend.'</td>';                .'<td>'.$tpend.'</td>';
     if (!$is_dc) {      unless ($poss_adhoc) {
         $roletext_end = '<td colspan="4">'.          $roletext_end = '<td colspan="4">'.
                         $tremark.'&nbsp;'.                          $tremark.'&nbsp;'.
                         '</td>';                          '</td>';
Line 1747  sub check_author_homeserver { Line 1899  sub check_author_homeserver {
 }  }
   
 sub check_for_adhoc {  sub check_for_adhoc {
     my ($dcroles,$dhroles,$update,$then) = @_;      my ($dcroles,$helpdeskroles,$update,$then) = @_;
     my $numdc = 0;      my $numdc = 0;
     my $numdh = 0;      my $numhelpdesk = 0;
     my $numadhoc = 0;      my $numadhoc = 0;
     my $num_custom_adhoc = 0;       my $num_custom_adhoc = 0; 
     if ($env{'user.adv'}) {      if (($env{'user.adv'}) || ($env{'user.rar'})) {
         foreach my $envkey (sort(keys(%env))) {          foreach my $envkey (sort(keys(%env))) {
             if ($envkey=~/^user\.role\.(dc|dh)\.\/($match_domain)\/$/) {              if ($envkey=~/^user\.role\.(dc|dh|da)\.\/($match_domain)\/$/) {
                 my $role = $1;                  my $role = $1;
                 my $roledom = $2;                  my $roledom = $2;
                 my $liverole = 1;                  my $liverole = 1;
                 my ($tstart,$tend)=split(/\./,$env{$envkey});                  my ($tstart,$tend)=split(/\./,$env{$envkey});
                 my $limit = $update;                  my $limit = $update;
                 if ((($role eq 'dc') && ($env{'request.role'} eq 'dc./'.$roledom.'/')) ||                  if ($env{'request.role'} eq "$role./$roledom/") {
                     (($role eq 'dh') && ($env{'request.role'} eq 'dh./'.$roledom.'/'))) {  
                     $limit = $then;                      $limit = $then;
                 }                  }
                 if ($tstart && $tstart>$limit) { $liverole = 0; }                  if ($tstart && $tstart>$limit) { $liverole = 0; }
Line 1771  sub check_for_adhoc { Line 1922  sub check_for_adhoc {
                         $dcroles->{$roledom} = $envkey;                          $dcroles->{$roledom} = $envkey;
                         $numdc++;                          $numdc++;
                     } else {                      } else {
                         $dhroles->{$roledom} = $envkey;                          $helpdeskroles->{$roledom} = $envkey;
                         if ($env{'environment.adhocroles.'.$roledom} ne '') {                          my %domdefaults = &Apache::lonnet::get_domain_defaults($roledom);
                             $numadhoc ++;                          if (ref($domdefaults{'adhocroles'}) eq 'HASH') {
                               if (keys(%{$domdefaults{'adhocroles'}})) {
                                   $numadhoc ++;
                               }
                         }                          }
                         $numdh++;                          $numhelpdesk++;
                     }                      }
                 }                  }
             }              }
         }          }
     }      }
     return ($numdc,$numdh,$numadhoc);      return ($numdc,$numhelpdesk,$numadhoc);
 }  }
   
 sub adhoc_course_role {  sub adhoc_course_role {
Line 1822  sub adhoc_course_role { Line 1976  sub adhoc_course_role {
                 my %cgroups =                  my %cgroups =
                     &Apache::lonnet::get_active_groups($env{'user.domain'},                      &Apache::lonnet::get_active_groups($env{'user.domain'},
                                             $env{'user.name'},$cdom,$cnum);                                              $env{'user.name'},$cdom,$cnum);
                   my $ccrole;
                   if ($crstype eq 'Community') {
                       $ccrole = 'co';
                   } else {
                       $ccrole = 'cc';
                   }
                 foreach my $group (keys(%cgroups)) {                  foreach my $group (keys(%cgroups)) {
                     $group_privs{$group} =                      $group_privs{$group} =
                         $env{'user.priv.cc./'.$cdom.'/'.$cnum.'./'.$cdom.'/'.$cnum.'/'.$group};                          $env{'user.priv.'.$ccrole.'./'.$cdom.'/'.$cnum.'./'.$cdom.'/'.$cnum.'/'.$group};
                 }                  }
                 $newgroups{'/'.$cdom.'/'.$cnum} = \%group_privs;                  $newgroups{'/'.$cdom.'/'.$cnum} = \%group_privs;
                 my $area = '/'.$cdom.'/'.$cnum;                  my $area = '/'.$cdom.'/'.$cnum;
Line 1976  sub adhoc_roles_row { Line 2136  sub adhoc_roles_row {
     my ($dcdom,$rowtype) = @_;      my ($dcdom,$rowtype) = @_;
     my $output = &Apache::loncommon::continue_data_table_row()      my $output = &Apache::loncommon::continue_data_table_row()
                  .' <td colspan="5" class="LC_textsize_mobile">'                   .' <td colspan="5" class="LC_textsize_mobile">'
                  .&mt('[_1]Ad hoc[_2] roles in domain [_3] --'                   .&mt('[_1]Ad hoc[_2] roles in domain [_3]'
                      ,'<span class="LC_cusr_emph">','</span>',$dcdom)                       ,'<span class="LC_cusr_emph">','</span>',$dcdom)
                  .' ';                   .' -- ';
     my $role = 'cc';      my $role = 'cc';
     my $selectcclink = &courselink($dcdom,$rowtype,$role);      my $selectcclink = &courselink($dcdom,$rowtype,$role);
     my $ccrole = &Apache::lonnet::plaintext('co',undef,undef,1);      my $ccrole = &Apache::lonnet::plaintext('co',undef,undef,1);
Line 1991  sub adhoc_roles_row { Line 2151  sub adhoc_roles_row {
 }  }
   
 sub adhoc_customroles_row {  sub adhoc_customroles_row {
     my ($dhdom,$rowtype) = @_;      my ($role,$dhdom,$rowtype,$update,$then) = @_;
     my $output = &Apache::loncommon::continue_data_table_row()      my $liverole = 1;
                  .' <td colspan="5" class="LC_textsize_mobile">'      my ($tstart,$tend)=split(/\./,$env{"user.role.$role./$dhdom/"});
                  .&mt('[_1]Ad hoc[_2] course/community roles in domain [_3] --',      my $limit = $update;
                       '<span class="LC_cusr_emph">','</span>',$dhdom);      if (($role eq 'dh') && ($env{'request.role'} eq 'dh./'.$dhdom.'/')) {
     my @customroles = split(/,/,$env{'environment.adhocroles.'.$dhdom});          $limit = $then;
     my $count = 0;      }
     foreach my $role (@customroles) {      if ($tstart && $tstart>$limit) { $liverole = 0; }
         next if (($role eq '') || ($role =~ /\W/));      if ($tend   && $tend  <$limit) { $liverole = 0; }
         $output .= ' '.$role.': '.&courselink($dhdom,$rowtype,$role).' |';      return unless ($liverole);
         $count ++;      my %domdefaults = &Apache::lonnet::get_domain_defaults($dhdom); 
     }      if (ref($domdefaults{'adhocroles'}) eq 'HASH') {
     if ($count) {          if (scalar(keys(%{$domdefaults{'adhocroles'}})) > 0) {
         return $output;              return &Apache::loncommon::continue_data_table_row()
                     .' <td colspan="5" class="LC_textsize_mobile">'
                     .&mt('[_1]Ad hoc[_2] course/community roles in domain [_3]',
                          '<span class="LC_cusr_emph">','</span>',$dhdom)
                     .' -- '.&courselink($dhdom,$rowtype,$role);
           }
     }      }
     return;      return;
 }  }
Line 2949  sub get_queued { Line 3114  sub get_queued {
            $output.'</fieldset></div><br clear="all" />';             $output.'</fieldset></div><br clear="all" />';
 }  }
   
   sub process_lti {
       my ($r,$cdom,$cnum) = @_;
       my %lti = &Apache::lonnet::get_domain_lti($cdom,'provider');
       my $uriscope = &LONCAPA::ltiutils::lti_provider_scope($env{'request.lti.uri'},
                                                             $cdom,$cnum);
       my $lonhost = $r->dir_config('lonHostID');
       my $internet_names = &Apache::lonnet::get_internet_names($lonhost);
       if ($env{'request.lti.rosterid'} &&
           $env{'request.lti.rosterurl'}) {
           if (ref($lti{$env{'request.lti.login'}}) eq 'HASH') {
               if ($lti{$env{'request.lti.login'}}{'roster'}) {
                   my @lcroles = ('in','ta','ep','st');
                   my @possibleroles;
                   foreach my $role (@lcroles) {
                       if (&Apache::lonnet::allowed('c'.$role,"$cdom/$cnum")) {
                           push(@possibleroles,$role);
                       }
                   }
                   my $owner = $env{'course.'.$cdom.'_'.$cnum.'.internal.courseowner'};
                   if ($owner eq $env{'user.name'}.':'.$env{'user.domain'}) {
                       my $crstype = &Apache::loncommon::course_type($cdom.'_'.$cnum);
                       if ($crstype eq 'Community') {
                           unshift(@possibleroles,'co');
                       } else {
                           unshift(@possibleroles,'cc');
                       }
                   }
                   if (@possibleroles) {
                       push(@{$rosterupdates},{cid        => $cdom.'_'.$cnum,
                                               lti        => $env{'request.lti.login'},
                                               ltiref     => $lti{$env{'request.lti.login'}},
                                               id         => $env{'request.lti.rosterid'},
                                               url        => $env{'request.lti.rosterurl'},
                                               sourcecrs  => $env{'request.lti.sourcecrs'},
                                               uriscope   => $uriscope,
                                               possroles  => \@possibleroles,
                                               intdoms    => $internet_names,
                                              });
                       unless ($registered_cleanup) {
                           my $handlers = $r->get_handlers('PerlCleanupHandler');
                           $r->set_handlers('PerlCleanupHandler' =>
                                            [\&ltienroll,@{$handlers}]);
                           $registered_cleanup=1;
                       }
                   }
               }
           }
       }
       if ($env{'request.lti.passbackid'} &&
           $env{'request.lti.passbackurl'}) {
           if (ref($lti{$env{'request.lti.login'}}) eq 'HASH') {
               if ($lti{$env{'request.lti.login'}}{'passback'}) {
                   my ($pbnum,$error) =
                       &LONCAPA::ltiutils::store_passbackurl($env{'request.lti.login'},
                                                             $env{'request.lti.passbackurl'},
                                                             $cdom,$cnum);
                   if ($pbnum eq '') {
                       $pbnum = $env{'request.lti.passbackurl'};
                   }
                   &Apache::lonnet::put('nohist_'.$cdom.'_'.$cnum.'_passback',
                                        {"$uriscope\0$env{'request.lti.sourcecrs'}\0$env{'request.lti.login'}" =>
                                        "$pbnum\0$env{'request.lti.passbackid'}"});
               }
           }
       }
       return;
   }
   
   sub ltienroll {
       if (ref($rosterupdates) eq 'ARRAY') {
           foreach my $item (@{$rosterupdates}) {
               if (ref($item) eq 'HASH') {
                   &LONCAPA::ltiutils::batchaddroster($item);
               }
           }
       }
   }
   
 1;  1;
 __END__  __END__
   

Removed from v.1.317  
changed lines
  Added in v.1.342


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