--- loncom/lonnet/perl/lonnet.pm 2015/05/21 23:40:25 1.1287
+++ loncom/lonnet/perl/lonnet.pm 2016/03/02 18:23:17 1.1302
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1287 2015/05/21 23:40:25 raeburn Exp $
+# $Id: lonnet.pm,v 1.1302 2016/03/02 18:23:17 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -92,7 +92,7 @@ use GDBM_File;
use HTML::LCParser;
use Fcntl qw(:flock);
use Storable qw(thaw nfreeze);
-use Time::HiRes qw( gettimeofday tv_interval );
+use Time::HiRes qw( sleep gettimeofday tv_interval );
use Cache::Memcached;
use Digest::MD5;
use Math::Random;
@@ -105,7 +105,7 @@ use LONCAPA::Lond;
use File::Copy;
my $readit;
-my $max_connection_retries = 10; # Or some such value.
+my $max_connection_retries = 20; # Or some such value.
require Exporter;
@@ -375,7 +375,7 @@ sub subreply {
my $lockfile=$peerfile.".lock";
while (-e $lockfile) { # Need to wait for the lockfile to disappear.
- sleep(1);
+ sleep(0.1);
}
# At this point, either a loncnew parent is listening or an old lonc
# or loncnew child is listening so we can connect or everything's dead.
@@ -393,7 +393,7 @@ sub subreply {
} else {
&create_connection(&hostname($server),$server);
}
- sleep(1); # Try again later if failed connection.
+ sleep(0.1); # Try again later if failed connection.
}
my $answer;
if ($client) {
@@ -422,8 +422,8 @@ sub reply {
sub reconlonc {
my ($lonid) = @_;
- my $hostname = &hostname($lonid);
if ($lonid) {
+ my $hostname = &hostname($lonid);
my $peerfile="$perlvar{'lonSockDir'}/$hostname";
if ($hostname && -e $peerfile) {
&logthis("Trying to reconnect lonc for $lonid ($hostname)");
@@ -448,7 +448,7 @@ sub reconlonc {
&logthis("lonc at pid $loncpid responding, sending USR1");
kill USR1 => $loncpid;
sleep 1;
- } else {
+ } else {
&logthis(
"WARNING:".
" lonc at pid $loncpid not responding, giving up");
@@ -469,7 +469,7 @@ sub critical {
}
my $answer=reply($cmd,$server);
if ($answer eq 'con_lost') {
- &reconlonc("$perlvar{'lonSockDir'}/$server");
+ &reconlonc($server);
my $answer=reply($cmd,$server);
if ($answer eq 'con_lost') {
my $now=time;
@@ -486,7 +486,7 @@ sub critical {
close($dfh);
}
}
- sleep 2;
+ sleep 1;
my $wcmd='';
{
my $dfh;
@@ -1551,17 +1551,33 @@ sub homeserver {
return 'no_host';
}
-# ------------------------------------- Find the usernames behind a list of IDs
+# ----- Find the usernames behind a list of student/employee IDs or clicker IDs
sub idget {
- my ($udom,@ids)=@_;
+ my ($udom,$idsref,$namespace)=@_;
my %returnhash=();
+ my @ids=();
+ if (ref($idsref) eq 'ARRAY') {
+ @ids = @{$idsref};
+ } else {
+ return %returnhash;
+ }
+ if ($namespace eq '') {
+ $namespace = 'ids';
+ }
my %servers = &get_servers($udom,'library');
foreach my $tryserver (keys(%servers)) {
- my $idlist=join('&',@ids);
- $idlist=~tr/A-Z/a-z/;
- my $reply=&reply("idget:$udom:".$idlist,$tryserver);
+ my $idlist=join('&', map { &escape($_); } @ids);
+ if ($namespace eq 'ids') {
+ $idlist=~tr/A-Z/a-z/;
+ }
+ my $reply;
+ if ($namespace eq 'ids') {
+ $reply=&reply("idget:$udom:".$idlist,$tryserver);
+ } else {
+ $reply=&reply("getdom:$udom:$namespace:$idlist",$tryserver);
+ }
my @answer=();
if (($reply ne 'con_lost') && ($reply!~/^error\:/)) {
@answer=split(/\&/,$reply);
@@ -1569,10 +1585,10 @@ sub idget {
my $i;
for ($i=0;$i<=$#ids;$i++) {
if ($answer[$i]) {
- $returnhash{$ids[$i]}=$answer[$i];
- }
+ $returnhash{$ids[$i]}=&unescape($answer[$i]);
+ }
}
- }
+ }
return %returnhash;
}
@@ -1587,60 +1603,141 @@ sub idrget {
return %returnhash;
}
-# ------------------------------- Store away a list of names and associated IDs
+# Store away a list of names and associated student/employee IDs or clicker IDs
sub idput {
- my ($udom,%ids)=@_;
+ my ($udom,$idsref,$uhom,$namespace)=@_;
my %servers=();
+ my %ids=();
+ my %byid = ();
+ if (ref($idsref) eq 'HASH') {
+ %ids=%{$idsref};
+ }
+ if ($namespace eq '') {
+ $namespace = 'ids';
+ }
foreach my $uname (keys(%ids)) {
&cput('environment',{'id'=>$ids{$uname}},$udom,$uname);
- my $uhom=&homeserver($uname,$udom);
+ if ($uhom eq '') {
+ $uhom=&homeserver($uname,$udom);
+ }
if ($uhom ne 'no_host') {
- my $id=&escape($ids{$uname});
- $id=~tr/A-Z/a-z/;
my $esc_unam=&escape($uname);
- if ($servers{$uhom}) {
- $servers{$uhom}.='&'.$id.'='.$esc_unam;
+ if ($namespace eq 'ids') {
+ my $id=&escape($ids{$uname});
+ $id=~tr/A-Z/a-z/;
+ my $esc_unam=&escape($uname);
+ $servers{$uhom}.=$id.'='.$esc_unam.'&';
} else {
- $servers{$uhom}=$id.'='.$esc_unam;
+ my @currids = split(/,/,$ids{$uname});
+ foreach my $id (@currids) {
+ $byid{$uhom}{$id} .= $uname.',';
+ }
+ }
+ }
+ }
+ if ($namespace eq 'clickers') {
+ foreach my $server (keys(%byid)) {
+ if (ref($byid{$server}) eq 'HASH') {
+ foreach my $id (keys(%{$byid{$server}})) {
+ $byid{$server} =~ s/,$//;
+ $servers{$uhom}.=&escape($id).'='.&escape($byid{$server}).'&';
+ }
}
}
}
foreach my $server (keys(%servers)) {
- &critical('idput:'.$udom.':'.$servers{$server},$server);
+ $servers{$server} =~ s/\&$//;
+ if ($namespace eq 'ids') {
+ &critical('idput:'.$udom.':'.$servers{$server},$server);
+ } else {
+ &critical('updateclickers:'.$udom.':add:'.$servers{$server},$server);
+ }
}
}
-# ---------------------------------------- Delete unwanted IDs from ids.db file
+# ------------- Delete unwanted student/employee IDs or clicker IDs from domain
sub iddel {
- my ($udom,$idshashref,$uhome)=@_;
+ my ($udom,$idshashref,$uhome,$namespace)=@_;
my %result=();
- unless (ref($idshashref) eq 'HASH') {
+ my %ids=();
+ my %byid = ();
+ if (ref($idshashref) eq 'HASH') {
+ %ids=%{$idshashref};
+ } else {
return %result;
}
+ if ($namespace eq '') {
+ $namespace = 'ids';
+ }
my %servers=();
- while (my ($id,$uname) = each(%{$idshashref})) {
- my $uhom;
- if ($uhome) {
- $uhom = $uhome;
- } else {
- $uhom=&homeserver($uname,$udom);
- }
- if ($uhom ne 'no_host') {
- if ($servers{$uhom}) {
+ while (my ($id,$unamestr) = each(%ids)) {
+ if ($namespace eq 'ids') {
+ my $uhom = $uhome;
+ if ($uhom eq '') {
+ $uhom=&homeserver($unamestr,$udom);
+ }
+ if ($uhom ne 'no_host') {
$servers{$uhom}.='&'.&escape($id);
- } else {
- $servers{$uhom}=&escape($id);
+ }
+ } else {
+ my @curritems = split(/,/,$ids{$id});
+ foreach my $uname (@curritems) {
+ my $uhom = $uhome;
+ if ($uhom eq '') {
+ $uhom=&homeserver($uname,$udom);
+ }
+ if ($uhom ne 'no_host') {
+ $byid{$uhom}{$id} .= $uname.',';
+ }
+ }
+ }
+ }
+ if ($namespace eq 'clickers') {
+ foreach my $server (keys(%byid)) {
+ if (ref($byid{$server}) eq 'HASH') {
+ foreach my $id (keys(%{$byid{$server}})) {
+ $byid{$server}{$id} =~ s/,$//;
+ $servers{$server}.=&escape($id).'='.&escape($byid{$server}{$id}).'&';
+ }
}
}
}
foreach my $server (keys(%servers)) {
- $result{$server} = &critical('iddel:'.$udom.':'.$servers{$server},$uhome);
+ $servers{$server} =~ s/\&$//;
+ if ($namespace eq 'ids') {
+ $result{$server} = &critical('iddel:'.$udom.':'.$servers{$server},$uhome);
+ } elsif ($namespace eq 'clickers') {
+ $result{$server} = &critical('updateclickers:'.$udom.':del:'.$servers{$server},$server);
+ }
}
return %result;
}
+# ----- Update clicker ID-to-username look-ups in clickers.db on library server
+
+sub updateclickers {
+ my ($udom,$action,$idshashref,$uhome,$critical) = @_;
+ my %clickers;
+ if (ref($idshashref) eq 'HASH') {
+ %clickers=%{$idshashref};
+ } else {
+ return;
+ }
+ my $items='';
+ foreach my $item (keys(%clickers)) {
+ $items.=&escape($item).'='.&escape($clickers{$item}).'&';
+ }
+ $items=~s/\&$//;
+ my $request = "updateclickers:$udom:$action:$items";
+ if ($critical) {
+ return &critical($request,$uhome);
+ } else {
+ return &reply($request,$uhome);
+ }
+}
+
# ------------------------------dump from db file owned by domainconfig user
sub dump_dom {
my ($namespace, $udom, $regexp) = @_;
@@ -1939,6 +2036,63 @@ sub get_instuser {
return ($outcome,%userinfo);
}
+sub get_multiple_instusers {
+ my ($udom,$users,$caller) = @_;
+ my ($outcome,$results);
+ if (ref($users) eq 'HASH') {
+ my $count = keys(%{$users});
+ my $requested = &freeze_escape($users);
+ my $homeserver = &domain($udom,'primary');
+ if ($homeserver ne '') {
+ my $queryid=&reply('querysend:getmultinstusers:::'.$caller.'='.$requested,$homeserver);
+ my $host=&hostname($homeserver);
+ if ($queryid !~/^\Q$host\E\_/) {
+ &logthis('get_multiple_instusers invalid queryid: '.$queryid.
+ ' for host: '.$homeserver.'in domain '.$udom);
+ return ($outcome,$results);
+ }
+ my $response = &get_query_reply($queryid);
+ my $maxtries = 5;
+ if ($count > 100) {
+ $maxtries = 1+int($count/20);
+ }
+ my $tries = 1;
+ while (($response=~/^timeout/) && ($tries <= $maxtries)) {
+ $response = &get_query_reply($queryid);
+ $tries ++;
+ }
+ if ($response eq '') {
+ $results = {};
+ foreach my $key (keys(%{$users})) {
+ my ($uname,$id);
+ if ($caller eq 'id') {
+ $id = $key;
+ } else {
+ $uname = $key;
+ }
+ my ($resp,%info) = &get_instuser($udom,$uname,$id);
+ $outcome = $resp;
+ if ($resp eq 'ok') {
+ %{$results} = (%{$results}, %info);
+ } else {
+ last;
+ }
+ }
+ } elsif(!&error($response) && ($response ne 'refused')) {
+ if (($response eq 'unavailable') || ($response eq 'invalid') || ($response eq 'timeout')) {
+ $outcome = $response;
+ } else {
+ ($outcome,my $userdata) = split(/=/,$response,2);
+ if ($outcome eq 'ok') {
+ $results = &thaw_unescape($userdata);
+ }
+ }
+ }
+ }
+ }
+ return ($outcome,$results);
+}
+
sub inst_rulecheck {
my ($udom,$uname,$id,$item,$rules) = @_;
my %returnhash;
@@ -2923,6 +3077,14 @@ sub can_edit_resource {
$forceedit = 1;
}
$cfile = $resurl;
+ } elsif ($resurl =~ m{^/adm/wrapper/adm/$cdom/$cnum/\d+/exttools?$}) {
+ $incourse = 1;
+ if ($env{'form.forceedit'}) {
+ $forceview = 1;
+ } else {
+ $forceedit = 1;
+ }
+ $cfile = $resurl;
} elsif ($resurl =~ m{^/?adm/viewclasslist$}) {
$incourse = 1;
if ($env{'form.forceedit'}) {
@@ -2947,6 +3109,14 @@ sub can_edit_resource {
$forceedit = 1;
}
$cfile = $resurl;
+ } elsif (($resurl =~ m{^/adm/wrapper/adm/$cdom/$cnum/\d+/exttools?$}) && ($env{'form.folderpath'} =~ /^supplemental/)) {
+ $incourse = 1;
+ if ($env{'form.forceedit'}) {
+ $forceview = 1;
+ } else {
+ $forceedit = 1;
+ }
+ $cfile = $resurl;
} elsif (($resurl eq '/adm/extresedit') && ($symb || $env{'form.folderpath'})) {
$incourse = 1;
$forceview = 1;
@@ -2956,8 +3126,13 @@ sub can_edit_resource {
$cfile = &clutter($res);
} else {
$cfile = $env{'form.suppurl'};
- $cfile =~ s{^http://}{};
- $cfile = '/adm/wrapper/ext/'.$cfile;
+ my $escfile = &unescape($cfile);
+ if ($escfile =~ m{^/adm/$cdom/$cnum/\d+/exttools?$}) {
+ $cfile = '/adm/wrapper'.$escfile;
+ } else {
+ $escfile =~ s{^http://}{};
+ $cfile = &escape("/adm/wrapper/ext/$escfile");
+ }
}
} elsif ($resurl =~ m{^/?adm/viewclasslist$}) {
if ($env{'form.forceedit'}) {
@@ -7156,7 +7331,7 @@ sub constructaccess {
my ($ownername,$ownerdomain,$ownerhome);
($ownerdomain,$ownername) =
- ($url=~ m{^(?:\Q$perlvar{'lonDocRoot'}\E|)/priv/($match_domain)/($match_username)/});
+ ($url=~ m{^(?:\Q$perlvar{'lonDocRoot'}\E|)(?:/daxepage|/daxeopen)?/priv/($match_domain)/($match_username)/});
# The URL does not really point to any authorspace, forget it
unless (($ownername) && ($ownerdomain)) { return ''; }
@@ -7329,7 +7504,8 @@ sub get_commblock_resources {
}
}
}
- if ($interval[0] =~ /^\d+$/) {
+ if ($interval[0] =~ /^\d+/) {
+ my ($timelimit) = split(/_/,$interval[0]);
my $first_access;
if ($type eq 'resource') {
$first_access=&get_first_access($interval[1],$item);
@@ -7339,7 +7515,7 @@ sub get_commblock_resources {
$first_access=&get_first_access($interval[1]);
}
if ($first_access) {
- my $timesup = $first_access+$interval[0];
+ my $timesup = $first_access+$timelimit;
if ($timesup > $now) {
my $activeblock;
foreach my $res (@to_test) {
@@ -7678,7 +7854,7 @@ sub get_query_reply {
my $replyfile=LONCAPA::tempdir().$queryid;
my $reply='';
for (1..100) {
- sleep 2;
+ sleep(0.2);
if (-e $replyfile.'.end') {
if (open(my $fh,$replyfile)) {
$reply = join('',<$fh>);
@@ -8734,7 +8910,7 @@ sub modifyuser {
'current user id "'.$uidhash{$uname}.'".';
}
} else {
- &idput($udom,($uname => $uid));
+ &idput($udom,{$uname => $uid},$uhome,'ids');
}
}
# -------------------------------------------------------------- Add names, etc
@@ -9521,9 +9697,9 @@ sub modify_access_controls {
my $tries = 0;
my $gotlock = &newput('file_permissions',$lockhash,$domain,$user);
- while (($gotlock ne 'ok') && $tries <3) {
+ while (($gotlock ne 'ok') && $tries < 10) {
$tries ++;
- sleep 1;
+ sleep(0.1);
$gotlock = &newput('file_permissions',$lockhash,$domain,$user);
}
if ($gotlock eq 'ok') {
@@ -10116,10 +10292,12 @@ sub get_userresdata {
}
#error 2 occurs when the .db doesn't exist
if ($tmp!~/error: 2 /) {
- &logthis("WARNING:".
- " Trying to get resource data for ".
- $uname." at ".$udom.": ".
- $tmp."");
+ if ((!defined($cached)) || ($tmp ne 'con_lost')) {
+ &logthis("WARNING:".
+ " Trying to get resource data for ".
+ $uname." at ".$udom.": ".
+ $tmp."");
+ }
} elsif ($tmp=~/error: 2 /) {
#&EXT_cache_set($udom,$uname);
&do_cache_new('userres',$hashid,undef,600);
@@ -10134,6 +10312,13 @@ sub get_userresdata {
# $name - Course/user name.
# $domain - Name of the domain the user/course is registered on.
# $type - Type of thing $name is (must be 'course' or 'user'
+# $mapp - decluttered URL of enclosing map
+# $recursed - Ref to scalar -- set to 1, if nested maps have been recursed.
+# $recurseup - Ref to array of map URLs, starting with map containing
+# $mapp up through hierarchy of nested maps to top level map.
+# $courseid - CourseID (first part of param identifier).
+# $modifier - Middle part of param identifier.
+# $what - Last part of param identifier.
# @which - Array of names of resources desired.
# Returns:
# The value of the first reasource in @which that is found in the
@@ -10143,7 +10328,8 @@ sub get_userresdata {
# 'user', an undefined reference is returned.
# If none of the resources are found, an undef is returned
sub resdata {
- my ($name,$domain,$type,@which)=@_;
+ my ($name,$domain,$type,$mapp,$recursed,$recurseup,$courseid,
+ $modifier,$what,@which)=@_;
my $result;
if ($type eq 'course') {
$result=&get_courseresdata($name,$domain);
@@ -10152,13 +10338,46 @@ sub resdata {
}
if (!ref($result)) { return $result; }
foreach my $item (@which) {
- if (defined($result->{$item->[0]})) {
+ if ($item->[1] eq 'course') {
+ if ((ref($recurseup) eq 'ARRAY') && (ref($recursed) eq 'SCALAR')) {
+ unless ($$recursed) {
+ @{$recurseup} = &get_map_hierarchy($mapp,$courseid);
+ $$recursed = 1;
+ }
+ foreach my $item (@${recurseup}) {
+ my $norecursechk=$courseid.$modifier.$item.'___(all).'.$what;
+ last if (defined($result->{$norecursechk}));
+ my $recursechk=$courseid.$modifier.$item.'___(rec).'.$what;
+ if (defined($result->{$recursechk})) { return [$result->{$recursechk},'map']; }
+ }
+ }
+ }
+ if (defined($result->{$item->[0]})) {
return [$result->{$item->[0]},$item->[1]];
}
}
return undef;
}
+sub get_domain_ltitools {
+ my ($cdom) = @_;
+ my %ltitools;
+ my ($result,$cached)=&is_cached_new('ltitools',$cdom);
+ if (defined($cached)) {
+ if (ref($result) eq 'HASH') {
+ %ltitools = %{$result};
+ }
+ } else {
+ my %domconfig = &get_dom('configuration',['ltitools'],$cdom);
+ if (ref($domconfig{'ltitools'}) eq 'HASH') {
+ %ltitools = %{$domconfig{'ltitools'}};
+ }
+ my $cachetime = 24*60*60;
+ &do_cache_new('ltitools',$cdom,\%ltitools,$cachetime);
+ }
+ return %ltitools;
+}
+
sub get_numsuppfiles {
my ($cnum,$cdom,$ignorecache)=@_;
my $hashid=$cnum.':'.$cdom;
@@ -10183,6 +10402,16 @@ sub get_numsuppfiles {
# EXT resource caching routines
#
+{
+# Cache (5 seconds) of map hierarchy for speedup of navmaps display
+#
+# The course for which we cache
+my $cachedmapkey='';
+# The cached recursive maps for this course
+my %cachedmaps=();
+# When this was last done
+my $cachedmaptime='';
+
sub clear_EXT_cache_status {
&delenv('cache.EXT.');
}
@@ -10360,8 +10589,8 @@ sub EXT {
}
}
- my ($section, $group, @groups);
- my ($courselevelm,$courselevel);
+ my ($section, $group, @groups, @recurseup, $recursed);
+ my ($courselevelm,$courseleveli,$courselevel,$mapp);
if (($courseid eq '') && ($cid)) {
$courseid = $cid;
}
@@ -10372,11 +10601,10 @@ sub EXT {
# ----------------------------------------------------- Cascading lookup scheme
my $symbp=$symbparm;
- my $mapp=&deversion((&decode_symb($symbp))[0]);
-
+ $mapp=&deversion((&decode_symb($symbp))[0]);
my $symbparm=$symbp.'.'.$spacequalifierrest;
+ my $recurseparm=$mapp.'___(rec).'.$spacequalifierrest;
my $mapparm=$mapp.'___(all).'.$spacequalifierrest;
-
if (($env{'user.name'} eq $uname) &&
($env{'user.domain'} eq $udom)) {
$section=$env{'request.course.sec'};
@@ -10393,17 +10621,21 @@ sub EXT {
my $seclevel=$courseid.'.['.$section.'].'.$spacequalifierrest;
my $seclevelr=$courseid.'.['.$section.'].'.$symbparm;
+ my $secleveli=$courseid.'.['.$section.'].'.$recurseparm;
my $seclevelm=$courseid.'.['.$section.'].'.$mapparm;
$courselevel=$courseid.'.'.$spacequalifierrest;
my $courselevelr=$courseid.'.'.$symbparm;
+ $courseleveli=$courseid.'.'.$recurseparm;
$courselevelm=$courseid.'.'.$mapparm;
# ----------------------------------------------------------- first, check user
- my $userreply=&resdata($uname,$udom,'user',
+ my $userreply=&resdata($uname,$udom,'user',$mapp,\$recursed,
+ \@recurseup,$courseid,'.',$spacequalifierrest,
([$courselevelr,'resource'],
[$courselevelm,'map' ],
+ [$courseleveli,'map' ],
[$courselevel, 'course' ]));
if (defined($userreply)) { return &get_reply($userreply); }
@@ -10411,15 +10643,18 @@ sub EXT {
my $coursereply;
if (@groups > 0) {
$coursereply = &check_group_parms($courseid,\@groups,$symbparm,
- $mapparm,$spacequalifierrest);
- if (defined($coursereply)) { return &get_reply($coursereply); }
+ $recurseparm,$mapparm,$spacequalifierrest,
+ $mapp,\$recursed,\@recurseup);
+ if (defined($coursereply)) { return &get_reply($coursereply); }
}
$coursereply=&resdata($env{'course.'.$courseid.'.num'},
$env{'course.'.$courseid.'.domain'},
- 'course',
+ 'course',$mapp,\$recursed,\@recurseup,
+ $courseid,'.['.$section.'].',$spacequalifierrest,
([$seclevelr, 'resource'],
[$seclevelm, 'map' ],
+ [$secleveli, 'map' ],
[$seclevel, 'course' ],
[$courselevelr,'resource']));
if (defined($coursereply)) { return &get_reply($coursereply); }
@@ -10436,8 +10671,9 @@ sub EXT {
if ($thisparm) { return &get_reply([$thisparm,'resource']); }
}
# ------------------------------------------ fourth, look in resource metadata
-
- $spacequalifierrest=~s/\./\_/;
+
+ my $what = $spacequalifierrest;
+ $what=~s/\./\_/;
my $filename;
if (!$symbparm) { $symbparm=&symbread(); }
if ($symbparm) {
@@ -10445,18 +10681,20 @@ sub EXT {
} else {
$filename=$env{'request.filename'};
}
- my $metadata=&metadata($filename,$spacequalifierrest);
+ my $metadata=&metadata($filename,$what);
if (defined($metadata)) { return &get_reply([$metadata,'resource']); }
- $metadata=&metadata($filename,'parameter_'.$spacequalifierrest);
+ $metadata=&metadata($filename,'parameter_'.$what);
if (defined($metadata)) { return &get_reply([$metadata,'resource']); }
-# ---------------------------------------------- fourth, look in rest of course
+# ----------------------------------------------- fifth, look in rest of course
if ($symbparm && defined($courseid) &&
$courseid eq $env{'request.course.id'}) {
my $coursereply=&resdata($env{'course.'.$courseid.'.num'},
$env{'course.'.$courseid.'.domain'},
- 'course',
+ 'course',$mapp,\$recursed,\@recurseup,
+ $courseid,'.',$spacequalifierrest,
([$courselevelm,'map' ],
+ [$courseleveli,'map' ],
[$courselevel, 'course']));
if (defined($coursereply)) { return &get_reply($coursereply); }
}
@@ -10513,22 +10751,51 @@ sub get_reply {
}
sub check_group_parms {
- my ($courseid,$groups,$symbparm,$mapparm,$what) = @_;
- my @groupitems = ();
- my $resultitem;
- my @levels = ([$symbparm,'resource'],[$mapparm,'map'],[$what,'course']);
+ my ($courseid,$groups,$symbparm,$recurseparm,$mapparm,$what,$mapp,
+ $recursed,$recurseupref) = @_;
+ my @levels = ([$symbparm,'resource'],[$mapparm,'map'],[$recurseparm,'map'],
+ [$what,'course']);
+ my $coursereply;
foreach my $group (@{$groups}) {
+ my @groupitems = ();
foreach my $level (@levels) {
my $item = $courseid.'.['.$group.'].'.$level->[0];
push(@groupitems,[$item,$level->[1]]);
}
+ my $coursereply = &resdata($env{'course.'.$courseid.'.num'},
+ $env{'course.'.$courseid.'.domain'},
+ 'course',$mapp,$recursed,$recurseupref,
+ $courseid,'.['.$group.'].',$what,
+ @groupitems);
+ last if (defined($coursereply));
}
- my $coursereply = &resdata($env{'course.'.$courseid.'.num'},
- $env{'course.'.$courseid.'.domain'},
- 'course',@groupitems);
return $coursereply;
}
+sub get_map_hierarchy {
+ my ($mapname,$courseid) = @_;
+ my @recurseup = ();
+ if ($mapname) {
+ if (($cachedmapkey eq $courseid) &&
+ (abs($cachedmaptime-time)<5)) {
+ if (ref($cachedmaps{$mapname}) eq 'ARRAY') {
+ return @{$cachedmaps{$mapname}};
+ }
+ }
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ if (ref($navmap)) {
+ @recurseup = $navmap->recurseup_maps($mapname);
+ undef($navmap);
+ $cachedmaps{$mapname} = \@recurseup;
+ $cachedmaptime=time;
+ $cachedmapkey=$courseid;
+ }
+ }
+ return @recurseup;
+}
+
+}
+
sub sort_course_groups { # Sort groups based on defined rankings. Default is sort().
my ($courseid,@groups) = @_;
@groups = sort(@groups);
@@ -10613,7 +10880,7 @@ sub metadata {
# if it is a non metadata possible uri return quickly
if (($uri eq '') ||
(($uri =~ m|^/*adm/|) &&
- ($uri !~ m|^adm/includes|) && ($uri !~ m{/(smppg|bulletinboard)$})) ||
+ ($uri !~ m|^adm/includes|) && ($uri !~ m{/(smppg|bulletinboard|exttools?)$})) ||
($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ m{^/*uploaded/.+\.sequence$})) {
return undef;
}
@@ -12146,6 +12413,8 @@ sub clutter {
# &logthis("Got a blank emb style");
}
}
+ } elsif ($thisfn =~ m{^/adm/$match_domain/$match_courseid/\d+/exttools?$}) {
+ $thisfn='/adm/wrapper'.$thisfn;
}
return $thisfn;
}
@@ -12337,8 +12606,8 @@ sub fetch_dns_checksums {
}
sub load_domain_tab {
- my ($ignore_cache) = @_;
- &get_dns('/adm/dns/domain',\&parse_domain_tab,$ignore_cache);
+ my ($ignore_cache,$nocache) = @_;
+ &get_dns('/adm/dns/domain',\&parse_domain_tab,$ignore_cache,$nocache);
my $fh;
if (open($fh,"<".$perlvar{'lonTabDir'}.'/domain.tab')) {
my @lines = <$fh>;
@@ -12424,8 +12693,8 @@ sub fetch_dns_checksums {
}
sub load_hosts_tab {
- my ($ignore_cache) = @_;
- &get_dns('/adm/dns/hosts',\&parse_hosts_tab,$ignore_cache);
+ my ($ignore_cache,$nocache) = @_;
+ &get_dns('/adm/dns/hosts',\&parse_hosts_tab,$ignore_cache,$nocache);
open(my $config,"<$perlvar{'lonTabDir'}/hosts.tab");
my @config = <$config>;
&parse_hosts_tab(\@config);
@@ -12447,7 +12716,8 @@ sub fetch_dns_checksums {
}
sub all_names {
- &load_hosts_tab() if (!$loaded);
+ my ($ignore_cache,$nocache) = @_;
+ &load_hosts_tab($ignore_cache,$nocache) if (!$loaded);
return %name_to_host;
}
@@ -12569,7 +12839,7 @@ sub fetch_dns_checksums {
}
sub get_iphost {
- my ($ignore_cache) = @_;
+ my ($ignore_cache,$nocache) = @_;
if (!$ignore_cache) {
if (%iphost) {
@@ -12593,7 +12863,7 @@ sub fetch_dns_checksums {
%old_name_to_ip = %{$ip_info->[1]};
}
- my %name_to_host = &all_names();
+ my %name_to_host = &all_names($ignore_cache,$nocache);
foreach my $name (keys(%name_to_host)) {
my $ip;
if (!exists($name_to_ip{$name})) {
@@ -12618,9 +12888,11 @@ sub fetch_dns_checksums {
}
push(@{$iphost{$ip}},@{$name_to_host{$name}});
}
- &do_cache_new('iphost','iphost',
- [\%iphost,\%name_to_ip,\%lonid_to_ip],
- 48*60*60);
+ unless ($nocache) {
+ &do_cache_new('iphost','iphost',
+ [\%iphost,\%name_to_ip,\%lonid_to_ip],
+ 48*60*60);
+ }
return %iphost;
}
@@ -13085,10 +13357,12 @@ the answer, and also caches if there is
=item *
X
-B: find the usernames behind a list of IDs
-(IDs are a unique resource in a domain, there must be only 1 ID per
-username, and only 1 username per ID in a specific domain) (returns
-hash: id=>name,id=>name)
+B: find the usernames behind either
+a list of student/employee IDs or clicker IDs
+(student/employee IDs are a unique resource in a domain, there must be
+only 1 ID per username, and only 1 username per ID in a specific domain).
+clickerIDs are not necessarily unique, as students might share clickers.
+(returns hash: id=>name,id=>name)
=item *
X
@@ -13097,7 +13371,27 @@ usernames (returns hash: name=>id,name=>
=item *
X
-B: store away a list of names and associated IDs
+B: store away a list of
+names and associated student/employee IDs or clicker IDs.
+
+=item *
+X
+B: delete unwanted
+student/employee ID or clicker ID username look-ups from domain.
+The homeserver ($uhome) and namespace ($namespace) are optional.
+If no $uhome is provided, it will be determined usig &homeserver()
+for each user. If no $namespace is provided, the default is ids.
+
+=item *
+X
+B: update
+clicker ID-to-username look-ups in clickers.db on library server.
+Permitted actions are add or del (i.e., add or delete). The
+clickers.db contains clickerID as keys (escaped), and each corresponding
+value is an escaped comma-separated list of usernames (for whom the
+library server is the homeserver), who registered that particular ID.
+If $critical is true, the update will be sent via &critical, otherwise
+&reply() will be used.
=item *
X