--- loncom/lonnet/perl/lonnet.pm 2011/01/11 22:36:11 1.1056.4.19
+++ loncom/lonnet/perl/lonnet.pm 2011/01/21 12:08:28 1.1101
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1056.4.19 2011/01/11 22:36:11 raeburn Exp $
+# $Id: lonnet.pm,v 1.1101 2011/01/21 12:08:28 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -264,7 +264,7 @@ sub get_server_homeID {
}
my $cachetime = 12*3600;
my $serverhomeID;
- if ($caller eq 'loncron') {
+ if ($caller eq 'loncron') {
my @machine_ids = &machine_ids($hostname);
foreach my $id (@machine_ids) {
my $response = &reply('serverhomeID',$id);
@@ -725,49 +725,25 @@ sub userload {
return $userloadpercent;
}
-# ------------------------------------------ Fight off request when overloaded
-
-sub overloaderror {
- my ($r,$checkserver)=@_;
- unless ($checkserver) { $checkserver=$perlvar{'lonHostID'}; }
- my $loadavg;
- if ($checkserver eq $perlvar{'lonHostID'}) {
- open(my $loadfile,'/proc/loadavg');
- $loadavg=<$loadfile>;
- $loadavg =~ s/\s.*//g;
- $loadavg = 100*$loadavg/$perlvar{'lonLoadLim'};
- close($loadfile);
- } else {
- $loadavg=&reply('load',$checkserver);
- }
- my $overload=$loadavg-100;
- if ($overload>0) {
- $r->err_headers_out->{'Retry-After'}=$overload;
- $r->log_error('Overload of '.$overload.' on '.$checkserver);
- return 413;
- }
- return '';
-}
-
# ------------------------------ Find server with least workload from spare.tab
sub spareserver {
- my ($loadpercent,$userloadpercent,$want_server_name) = @_;
+ my ($loadpercent,$userloadpercent,$want_server_name,$udom) = @_;
my $spare_server;
if ($userloadpercent !~ /\d/) { $userloadpercent=0; }
my $lowest_load=($loadpercent > $userloadpercent) ? $loadpercent
: $userloadpercent;
my ($uint_dom,$remotesessions);
- if ($env{'user.domain'}) {
- my $uprimary_id = &Apache::lonnet::domain($env{'user.domain'},'primary');
+ if (($udom ne '') && (&domain($udom) ne '')) {
+ my $uprimary_id = &Apache::lonnet::domain($udom,'primary');
$uint_dom = &Apache::lonnet::internet_dom($uprimary_id);
- my %udomdefaults = &Apache::lonnet::get_domain_defaults($env{'user.domain'});
+ my %udomdefaults = &Apache::lonnet::get_domain_defaults($udom);
$remotesessions = $udomdefaults{'remotesessions'};
}
foreach my $try_server (@{ $spareid{'primary'} }) {
if ($uint_dom) {
- next unless (&spare_can_host($env{'user.domain'},$uint_dom,
- $remotesessions,$try_server));
+ next unless (&spare_can_host($udom,$uint_dom,$remotesessions,
+ $try_server));
}
($spare_server, $lowest_load) =
&compare_server_load($try_server, $spare_server, $lowest_load);
@@ -778,8 +754,8 @@ sub spareserver {
if (!$found_server) {
foreach my $try_server (@{ $spareid{'default'} }) {
if ($uint_dom) {
- next unless (&spare_can_host($env{'user.domain'},$uint_dom,
- $remotesessions,$try_server));
+ next unless (&spare_can_host($udom,$uint_dom,$remotesessions,
+ $try_server));
}
($spare_server, $lowest_load) =
&compare_server_load($try_server, $spare_server, $lowest_load);
@@ -808,7 +784,7 @@ sub compare_server_load {
my $userloadans = &reply('userload',$try_server);
if ($loadans !~ /\d/ && $userloadans !~ /\d/) {
- return; #didn't get a number from the server
+ return; #didn't get a number from the server
}
my $load;
@@ -2266,7 +2242,7 @@ sub process_coursefile {
}
if (ref($mimetype)) {
$$mimetype = $type;
- }
+ }
}
$fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file,
$home);
@@ -2384,11 +2360,11 @@ sub resizeImage {
# input: $formname - the contents of the file are in $env{"form.$formname"}
# the desired filename is in $env{"form.$formname.filename"}
# $context - possible values: coursedoc, existingfile, overwrite,
-# canceloverwrite, or ''.
+# canceloverwrite, or ''.
# if 'coursedoc': upload to the current course
-# if 'existingfile': write file to tmp/overwrites directory
+# if 'existingfile': write file to tmp/overwrites directory
# if 'canceloverwrite': delete file written to tmp/overwrites directory
-# $context is passed as argument to &finishuserfileupload
+# $context is passed as argument to &finishuserfileupload
# $subdir - directory in userfile to store the file into
# $parser - instruction to parse file for objects ($parser = parse)
# $allfiles - reference to hash for embedded objects
@@ -2544,7 +2520,7 @@ sub finishuserfileupload {
my $target = $filepath.'/'.$file;
if (-e $source) {
my @info = stat($source);
- if ($info[9] eq $env{'form.timestamp'}) {
+ if ($info[9] eq $env{'form.timestamp'}) {
unless (&File::Copy::move($source,$target)) {
&logthis('Failed to overwrite '.$filepath.'/'.$file);
return "Moving from $source failed";
@@ -2555,7 +2531,7 @@ sub finishuserfileupload {
} else {
return "Temporary file: $source missing";
}
- } elsif (!print FH ($env{'form.'.$formname})) {
+ } elsif (!print FH ($env{'form.'.$formname})) {
&logthis('Failed to write to '.$filepath.'/'.$file);
print STDERR ('Failed to write to '.$filepath.'/'.$file."\n");
return '/adm/notfound.html';
@@ -3116,7 +3092,7 @@ sub get_my_roles {
unless (defined($uname)) { $uname=$env{'user.name'}; }
unless (defined($udom)) { $udom=$env{'user.domain'}; }
my (%dumphash,%nothide);
- if ($context eq 'userroles') {
+ if ($context eq 'userroles') {
my $extra = &freeze_escape({'skipcheck' => 1});
%dumphash = &dump('roles',$udom,$uname,'.',undef,$extra);
} else {
@@ -3446,7 +3422,7 @@ sub get_domain_roles {
return %personnel;
}
-# ----------------------------------------------------------- Check out an item
+# ----------------------------------------------------------- Interval timing
sub get_first_access {
my ($type,$argsymb)=@_;
@@ -3482,91 +3458,6 @@ sub set_first_access {
return 'already_set';
}
-sub checkout {
- my ($symb,$tuname,$tudom,$tcrsid)=@_;
- my $now=time;
- my $lonhost=$perlvar{'lonHostID'};
- my $infostr=&escape(
- 'CHECKOUTTOKEN&'.
- $tuname.'&'.
- $tudom.'&'.
- $tcrsid.'&'.
- $symb.'&'.
- $now.'&'.$ENV{'REMOTE_ADDR'});
- my $token=&reply('tmpput:'.$infostr,$lonhost);
- if ($token=~/^error\:/) {
- &logthis("WARNING: ".
- "Checkout tmpput failed ".$tudom.' - '.$tuname.' - '.$symb.
- "");
- return '';
- }
-
- $token=~s/^(\d+)\_.*\_(\d+)$/$1\*$2\*$lonhost/;
- $token=~tr/a-z/A-Z/;
-
- my %infohash=('resource.0.outtoken' => $token,
- 'resource.0.checkouttime' => $now,
- 'resource.0.outremote' => $ENV{'REMOTE_ADDR'});
-
- unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') {
- return '';
- } else {
- &logthis("WARNING: ".
- "Checkout cstore failed ".$tudom.' - '.$tuname.' - '.$symb.
- "");
- }
-
- if (&log($tudom,$tuname,&homeserver($tuname,$tudom),
- &escape('Checkout '.$infostr.' - '.
- $token)) ne 'ok') {
- return '';
- } else {
- &logthis("WARNING: ".
- "Checkout log failed ".$tudom.' - '.$tuname.' - '.$symb.
- "");
- }
- return $token;
-}
-
-# ------------------------------------------------------------ Check in an item
-
-sub checkin {
- my $token=shift;
- my $now=time;
- my ($ta,$tb,$lonhost)=split(/\*/,$token);
- $lonhost=~tr/A-Z/a-z/;
- my $dtoken=$ta.'_'.&hostname($lonhost).'_'.$tb;
- $dtoken=~s/\W/\_/g;
- my ($dummy,$tuname,$tudom,$tcrsid,$symb,$chtim,$rmaddr)=
- split(/\&/,&unescape(&reply('tmpget:'.$dtoken,$lonhost)));
-
- unless (($tuname) && ($tudom)) {
- &logthis('Check in '.$token.' ('.$dtoken.') failed');
- return '';
- }
-
- unless (&allowed('mgr',$tcrsid)) {
- &logthis('Check in '.$token.' ('.$dtoken.') unauthorized: '.
- $env{'user.name'}.' - '.$env{'user.domain'});
- return '';
- }
-
- my %infohash=('resource.0.intoken' => $token,
- 'resource.0.checkintime' => $now,
- 'resource.0.inremote' => $ENV{'REMOTE_ADDR'});
-
- unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') {
- return '';
- }
-
- if (&log($tudom,$tuname,&homeserver($tuname,$tudom),
- &escape('Checkin - '.$token)) ne 'ok') {
- return '';
- }
-
- return ($symb,$tuname,$tudom,$tcrsid);
-}
-
# --------------------------------------------- Set Expire Date for Spreadsheet
sub expirespread {
@@ -4311,7 +4202,7 @@ sub set_userprivs {
my $adv=0;
my %grouproles = ();
if (keys(%{$allgroups}) > 0) {
- my @groupkeys;
+ my @groupkeys;
foreach my $role (keys(%{$allroles})) {
push(@groupkeys,$role);
}
@@ -4387,7 +4278,7 @@ sub role_status {
my %userroles = (
'user.role.'.$$role.'.'.$$where => $$tstart.'.'.$$tend
);
- @rolecodes = ('cm');
+ @rolecodes = ('cm');
my $spec=$$role.'.'.$$where;
my ($tdummy,$tdomain,$trest)=split(/\//,$$where);
if ($$role =~ /^cr\//) {
@@ -4404,7 +4295,7 @@ sub role_status {
my %course_roles = &get_my_roles($env{'user.name'},$env{'user.domain'},'userroles',['active'],['cc','co','in','ta','ep','ad','st','cr'],[$tdomain],1);
if (keys(%course_roles) > 0) {
my ($tnum) = ($trest =~ /^($match_courseid)/);
- if ($tdomain ne '' && $tnum ne '') {
+ if ($tdomain ne '' && $tnum ne '') {
foreach my $key (keys(%course_roles)) {
if ($key =~ /^\Q$tnum\E:\Q$tdomain\E:([^:]+):?([^:]*)/) {
my $crsrole = $1;
@@ -4547,15 +4438,18 @@ sub dump {
my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range:$extra",$uhome);
my @pairs=split(/\&/,$rep);
my %returnhash=();
- foreach my $item (@pairs) {
- my ($key,$value)=split(/=/,$item,2);
- $key = &unescape($key);
- next if ($key =~ /^error: 2 /);
- $returnhash{$key}=&thaw_unescape($value);
+ if (!($rep =~ /^error/ )) {
+ foreach my $item (@pairs) {
+ my ($key,$value)=split(/=/,$item,2);
+ $key = &unescape($key);
+ next if ($key =~ /^error: 2 /);
+ $returnhash{$key}=&thaw_unescape($value);
+ }
}
return %returnhash;
}
+
# --------------------------------------------------------- dumpstore interface
sub dumpstore {
@@ -5089,7 +4983,7 @@ sub is_portfolio_file {
}
sub usertools_access {
- my ($uname,$udom,$tool,$action,$context,$userenvref,$domdefref,$is_advref) = @_;
+ my ($uname,$udom,$tool,$action,$context,$userenvref,$domdefref,$is_advref)=@_;
my ($access,%tools);
if ($context eq '') {
$context = 'tools';
@@ -5236,7 +5130,7 @@ sub is_advanced_user {
my ($udom,$uname) = @_;
if ($udom ne '' && $uname ne '') {
if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'})) {
- return $env{'user.adv'};
+ return $env{'user.adv'};
}
}
my %roleshash = &get_my_roles($uname,$udom,'userroles',undef,undef,undef,1);
@@ -6879,7 +6773,7 @@ sub modifyuser {
}
&logthis('Call to modify user '.$udom.', '.$uname.', '.$uid.', '.
$umode.', '.$first.', '.$middle.', '.
- $last.', '.$gene.'(forceid: '.$forceid.'; candelete: '.$showcandelete.')'.
+ $last.', '.$gene.'(forceid: '.$forceid.'; candelete: '.$showcandelete.')'.
(defined($desiredhome) ? ' desiredhome = '.$desiredhome :
' desiredhome not specified').
' by '.$env{'user.name'}.' at '.$env{'user.domain'}.
@@ -7025,7 +6919,7 @@ sub modifyuser {
return 'ok';
}
my $reply = &put('environment', \%names, $udom,$uname);
- if ($reply ne 'ok') {
+ if ($reply ne 'ok') {
return 'error: '.$reply;
}
if ($names{'permanentemail'} ne $oldnames{'permanentemail'}) {
@@ -7407,7 +7301,7 @@ sub is_locked {
my ($file_name, $domain, $user, $which) = @_;
my @check;
my $is_locked;
- push(@check,$file_name);
+ push (@check,$file_name);
my %locked = &get('file_permissions',\@check,
$env{'user.domain'},$env{'user.name'});
my ($tmp)=keys(%locked);
@@ -8571,6 +8465,7 @@ sub add_prefix_and_part {
# ---------------------------------------------------------------- Get metadata
my %metaentry;
+my %importedpartids;
sub metadata {
my ($uri,$what,$liburi,$prefix,$depthcount)=@_;
$uri=&declutter($uri);
@@ -8578,7 +8473,7 @@ sub metadata {
if (($uri eq '') ||
(($uri =~ m|^/*adm/|) &&
($uri !~ m|^adm/includes|) && ($uri !~ m|/bulletinboard$|)) ||
- ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ /^\*uploaded\/.+\.sequence$/) || ($uri =~ m{^/*uploaded/$match_domain/$match_courseid/docs/})) {
+ ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ m{^/*uploaded/.+\.sequence$}) || ($uri =~ m{^/*uploaded/$match_domain/$match_courseid/docs/})) {
return undef;
}
if (($uri =~ /^~/ || $uri =~ m{home/$match_username/public_html/})
@@ -8597,6 +8492,10 @@ sub metadata {
if (defined($cached)) { return $result->{':'.$what}; }
}
{
+# Imported parts would go here
+ my %importedids=();
+ my @origfileimportpartids=();
+ my $importedparts=0;
#
# Is this a recursive call for a library?
#
@@ -8680,27 +8579,55 @@ sub metadata {
# This is not a package - some other kind of start tag
#
my $entry=$token->[1];
- my $unikey;
- if ($entry eq 'import') {
- $unikey='';
- } else {
- $unikey=$entry;
- }
- $unikey.=&add_prefix_and_part($prefix,$token->[2]->{'part'});
-
- if (defined($token->[2]->{'id'})) {
- $unikey.='_'.$token->[2]->{'id'};
- }
+ my $unikey='';
if ($entry eq 'import') {
#
# Importing a library here
#
+ my $location=$parser->get_text('/import');
+ my $dir=$filename;
+ $dir=~s|[^/]*$||;
+ $location=&filelocation($dir,$location);
+
+ my $importmode=$token->[2]->{'importmode'};
+ if ($importmode eq 'problem') {
+# Import as problem/response
+ $unikey=&add_prefix_and_part($prefix,$token->[2]->{'part'});
+ } elsif ($importmode eq 'part') {
+# Import as part(s)
+ $importedparts=1;
+# We need to get the original file and the imported file to get the part order correct
+# Good news: we do not need to worry about nested libraries, since parts cannot be nested
+# Load and inspect original file
+ if ($#origfileimportpartids<0) {
+ undef(%importedpartids);
+ my $origfilelocation=$perlvar{'lonDocRoot'}.&clutter($uri);
+ my $origfile=&getfile($origfilelocation);
+ @origfileimportpartids=($origfile=~/<(part|import)[^>]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs);
+ }
+
+# Load and inspect imported file
+ my $impfile=&getfile($location);
+ my @impfilepartids=($impfile=~/]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs);
+ if ($#impfilepartids>=0) {
+# This problem had parts
+ $importedpartids{$token->[2]->{'id'}}=join(',',@impfilepartids);
+ } else {
+# Importing by turning a single problem into a problem part
+# It gets the import-tags ID as part-ID
+ $unikey=&add_prefix_and_part($prefix,$token->[2]->{'id'});
+ $importedpartids{$token->[2]->{'id'}}=$token->[2]->{'id'};
+ }
+ } else {
+# Normal import
+ $unikey=&add_prefix_and_part($prefix,$token->[2]->{'part'});
+ if (defined($token->[2]->{'id'})) {
+ $unikey.='_'.$token->[2]->{'id'};
+ }
+ }
+
if ($depthcount<20) {
- my $location=$parser->get_text('/import');
- my $dir=$filename;
- $dir=~s|[^/]*$||;
- $location=&filelocation($dir,$location);
my $metadata =
&metadata($uri,'keys', $location,$unikey,
$depthcount+1);
@@ -8708,8 +8635,16 @@ sub metadata {
$metaentry{':'.$meta}=$metaentry{':'.$meta};
$metathesekeys{$meta}=1;
}
- }
- } else {
+
+ }
+ } else {
+#
+# Not importing, some other kind of non-package, non-library start tag
+#
+ $unikey=$entry.&add_prefix_and_part($prefix,$token->[2]->{'part'});
+ if (defined($token->[2]->{'id'})) {
+ $unikey.='_'.$token->[2]->{'id'};
+ }
if (defined($token->[2]->{'name'})) {
$unikey.='_'.$token->[2]->{'name'};
}
@@ -8783,6 +8718,22 @@ sub metadata {
grep { ! $seen{$_} ++ } (split(',',$metaentry{':packages'}));
$metaentry{':packages'} = join(',',@uniq_packages);
+ if ($importedparts) {
+# We had imported parts and need to rebuild partorder
+ $metaentry{':partorder'}='';
+ $metathesekeys{'partorder'}=1;
+ for (my $index=0;$index<$#origfileimportpartids;$index+=2) {
+ if ($origfileimportpartids[$index] eq 'part') {
+# original part, part of the problem
+ $metaentry{':partorder'}.=','.$origfileimportpartids[$index+1];
+ } else {
+# we have imported parts at this position
+ $metaentry{':partorder'}.=','.$importedpartids{$origfileimportpartids[$index+1]};
+ }
+ }
+ $metaentry{':partorder'}=~s/^\,//;
+ }
+
$metaentry{':keys'} = join(',',keys(%metathesekeys));
&metadata_generate_part0(\%metathesekeys,\%metaentry,$uri);
$metaentry{':allpossiblekeys'}=join(',',keys %metathesekeys);
@@ -8981,7 +8932,8 @@ sub symbverify {
&symbclean(&declutter($bighash{'map_id_'.$mapid}).'___'.$resid.'___'.$thisfn)
eq $symb) {
if (($env{'request.role.adv'}) ||
- $bighash{'encrypted_'.$id} eq $env{'request.enc'}) {
+ ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) ||
+ ($thisurl eq '/adm/navmaps')) {
$okay=1;
}
}
@@ -10148,7 +10100,7 @@ sub get_dns {
}
sub unique_library {
- #2x reverse removes all hostnames that appear more than once
+ #2x reverse removes all hostnames that appear more than once
my %unique = reverse &all_library();
return reverse %unique;
}
@@ -10178,7 +10130,7 @@ sub get_dns {
sub get_unique_servers {
my %unique = reverse &get_servers(@_);
- return reverse %unique;
+ return reverse %unique;
}
sub host_domain {
@@ -10714,7 +10666,7 @@ $checkdefauth is optional (value is 1 if
authenticate user using default authentication method, and allow
account creation if username does not have account in the domain).
$clientcancheckhost is optional (value is 1 if checking whether the
- server can host will occur on the client side in lonauth.pm).
+ server can host will occur on the client side in lonauth.pm).
=item *
X
@@ -11464,7 +11416,7 @@ userfileupload(): main rotine for puttin
the filename is in $env{'form.'.$formname.'.filename'} and the
contents of the file is located in $env{'form.'.$formname}
context - if coursedoc, store the file in the course of the active role
- of the current user;
+ of the current user;
if 'existingfile': store in 'overwrites' in /home/httpd/perl/tmp
if 'canceloverwrite': delete file in tmp/overwrites directory
subdir - required - subdirectory to put the file in under ../userfiles/
@@ -11510,7 +11462,7 @@ userspace, probably shouldn't be called
returns either the url of the uploaded file (/uploaded/....) if successful
and /adm/notfound.html if unsuccessful (or an error message if context
was 'overwrite').
-
+
=item *