--- loncom/lonnet/perl/lonnet.pm 2014/04/16 16:21:24 1.1172.2.43
+++ loncom/lonnet/perl/lonnet.pm 2015/04/01 23:22:13 1.1279
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1172.2.43 2014/04/16 16:21:24 raeburn Exp $
+# $Id: lonnet.pm,v 1.1279 2015/04/01 23:22:13 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -75,6 +75,9 @@ use LWP::UserAgent();
use HTTP::Date;
use Image::Magick;
+
+use Encode;
+
use vars qw(%perlvar %spareid %pr %prp $memcache %packagetab $tmpdir
$_64bit %env %protocol %loncaparevs %serverhomeIDs %needsrelease
%managerstab);
@@ -109,6 +112,7 @@ require Exporter;
our @ISA = qw (Exporter);
our @EXPORT = qw(%env);
+
# ------------------------------------ Logging (parameters, docs, slots, roles)
{
my $logid;
@@ -123,19 +127,19 @@ our @EXPORT = qw(%env);
$logid ++;
my $now = time();
my $id=$now.'00000'.$$.'00000'.$logid;
- my $logentry = {
- $id => {
- 'exe_uname' => $env{'user.name'},
- 'exe_udom' => $env{'user.domain'},
- 'exe_time' => $now,
- 'exe_ip' => $ENV{'REMOTE_ADDR'},
- 'delflag' => $delflag,
- 'logentry' => $storehash,
- 'uname' => $uname,
- 'udom' => $udom,
- }
+ my $logentry = {
+ $id => {
+ 'exe_uname' => $env{'user.name'},
+ 'exe_udom' => $env{'user.domain'},
+ 'exe_time' => $now,
+ 'exe_ip' => $ENV{'REMOTE_ADDR'},
+ 'delflag' => $delflag,
+ 'logentry' => $storehash,
+ 'uname' => $uname,
+ 'udom' => $udom,
+ }
};
- return &put('nohist_'.$hash_name,$logentry,$cdom,$cnum);
+ return &put('nohist_'.$hash_name,$logentry,$cdom,$cnum);
}
}
@@ -356,7 +360,8 @@ sub remote_devalidate_cache {
my $items;
return unless (ref($cachekeys) eq 'ARRAY');
my $cachestr = join('&',@{$cachekeys});
- return &reply('devalidatecache:'.&escape($cachestr),$lonhost);
+ my $response = &reply('devalidatecache:'.&escape($cachestr),$lonhost);
+ return $response;
}
# -------------------------------------------------- Non-critical communication
@@ -844,10 +849,8 @@ sub spareserver {
if (ref($spareshash) eq 'HASH') {
if (ref($spareshash->{'primary'}) eq 'ARRAY') {
foreach my $try_server (@{ $spareshash->{'primary'} }) {
- if ($uint_dom) {
- next unless (&spare_can_host($udom,$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);
}
@@ -858,10 +861,8 @@ sub spareserver {
if (!$found_server) {
if (ref($spareshash->{'default'}) eq 'ARRAY') {
foreach my $try_server (@{ $spareshash->{'default'} }) {
- if ($uint_dom) {
- next unless (&spare_can_host($udom,$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);
}
@@ -956,12 +957,29 @@ sub has_user_session {
# --------- determine least loaded server in a user's domain which allows login
sub choose_server {
- my ($udom,$checkloginvia,$required) = @_;
+ my ($udom,$checkloginvia,$required,$skiploadbal) = @_;
my %domconfhash = &Apache::loncommon::get_domainconf($udom);
my %servers = &get_servers($udom);
my $lowest_load = 30000;
- my ($login_host,$hostname,$portal_path,$isredirect);
+ my ($login_host,$hostname,$portal_path,$isredirect,$balancers);
+ if ($skiploadbal) {
+ ($balancers,my $cached)=&is_cached_new('loadbalancing',$udom);
+ unless (defined($cached)) {
+ my $cachetime = 60*60*24;
+ my %domconfig =
+ &Apache::lonnet::get_dom('configuration',['loadbalancing'],$udom);
+ if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
+ $balancers = &do_cache_new('loadbalancing',$udom,$domconfig{'loadbalancing'},
+ $cachetime);
+ }
+ }
+ }
foreach my $lonhost (keys(%servers)) {
+ if ($skiploadbal) {
+ if (ref($balancers) eq 'HASH') {
+ next if (exists($balancers->{$lonhost}));
+ }
+ }
my $loginvia;
if ($checkloginvia) {
$loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost};
@@ -1156,19 +1174,27 @@ sub can_host_session {
sub spare_can_host {
my ($udom,$uint_dom,$remotesessions,$try_server)=@_;
my $canhost=1;
- my @intdoms;
- my $internet_names = &Apache::lonnet::get_internet_names($try_server);
- if (ref($internet_names) eq 'ARRAY') {
- @intdoms = @{$internet_names};
- }
- unless (grep(/^\Q$uint_dom\E$/,@intdoms)) {
- my $serverhomeID = &Apache::lonnet::get_server_homeID($try_server);
- my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
- my %defdomdefaults = &Apache::lonnet::get_domain_defaults($serverhomedom);
- my $remoterev = &Apache::lonnet::get_server_loncaparev(undef,$try_server);
- $canhost = &can_host_session($udom,$try_server,$remoterev,
- $remotesessions,
- $defdomdefaults{'hostedsessions'});
+ my $try_server_hostname = &hostname($try_server);
+ my $serverhomeID = &get_server_homeID($try_server_hostname);
+ my $serverhomedom = &host_domain($serverhomeID);
+ my %defdomdefaults = &get_domain_defaults($serverhomedom);
+ if (ref($defdomdefaults{'offloadnow'}) eq 'HASH') {
+ if ($defdomdefaults{'offloadnow'}{$try_server}) {
+ $canhost = 0;
+ }
+ }
+ if (($canhost) && ($uint_dom)) {
+ my @intdoms;
+ my $internet_names = &get_internet_names($try_server);
+ if (ref($internet_names) eq 'ARRAY') {
+ @intdoms = @{$internet_names};
+ }
+ unless (grep(/^\Q$uint_dom\E$/,@intdoms)) {
+ my $remoterev = &get_server_loncaparev(undef,$try_server);
+ $canhost = &can_host_session($udom,$try_server,$remoterev,
+ $remotesessions,
+ $defdomdefaults{'hostedsessions'});
+ }
}
return $canhost;
}
@@ -1280,7 +1306,7 @@ sub check_loadbalancing {
}
}
if (ref($result) eq 'HASH') {
- ($is_balancer,$currtargets,$currrules) =
+ ($is_balancer,$currtargets,$currrules) =
&check_balancer_result($result,@hosts);
if ($is_balancer) {
if (ref($currrules) eq 'HASH') {
@@ -1339,7 +1365,7 @@ sub check_loadbalancing {
}
}
if (ref($result) eq 'HASH') {
- ($is_balancer,$currtargets,$currrules) =
+ ($is_balancer,$currtargets,$currrules) =
&check_balancer_result($result,@hosts);
if ($is_balancer) {
if (ref($currrules) eq 'HASH') {
@@ -1395,8 +1421,8 @@ sub check_loadbalancing {
$is_balancer = 0;
if ($uname ne '' && $udom ne '') {
if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) {
-
- &appenv({'user.loadbalexempt' => $lonhost,
+
+ &appenv({'user.loadbalexempt' => $lonhost,
'user.loadbalcheck.time' => time});
}
}
@@ -1585,7 +1611,7 @@ sub idput {
}
}
-# ---------------------------------------- Delete unwanted IDs from ids.db file
+# ---------------------------------------- Delete unwanted IDs from ids.db file
sub iddel {
my ($udom,$idshashref,$uhome)=@_;
@@ -1630,6 +1656,7 @@ sub dump_dom {
sub get_dom {
my ($namespace,$storearr,$udom,$uhome)=@_;
+ return if ($udom eq 'public');
my $items='';
foreach my $item (@$storearr) {
$items.=&escape($item).'&';
@@ -1637,6 +1664,7 @@ sub get_dom {
$items=~s/\&$//;
if (!$udom) {
$udom=$env{'user.domain'};
+ return if ($udom eq 'public');
if (defined(&domain($udom,'primary'))) {
$uhome=&domain($udom,'primary');
} else {
@@ -1740,14 +1768,13 @@ sub retrieve_inst_usertypes {
my %domdefs = &Apache::lonnet::get_domain_defaults($udom);
if ((ref($domdefs{'inststatustypes'}) eq 'HASH') &&
(ref($domdefs{'inststatusorder'}) eq 'ARRAY')) {
- %returnhash = %{$domdefs{'inststatustypes'}};
- @order = @{$domdefs{'inststatusorder'}};
+ return ($domdefs{'inststatustypes'},$domdefs{'inststatusorder'});
} else {
if (defined(&domain($udom,'primary'))) {
my $uhome=&domain($udom,'primary');
my $rep=&reply("inst_usertypes:$udom",$uhome);
if ($rep =~ /^(con_lost|error|no_such_host|refused)/) {
- &logthis("get_dom failed - $rep returned from $uhome in domain: $udom");
+ &logthis("retrieve_inst_usertypes failed - $rep returned from $uhome in domain: $udom");
return (\%returnhash,\@order);
}
my ($hashitems,$orderitems) = split(/:/,$rep);
@@ -1763,10 +1790,10 @@ sub retrieve_inst_usertypes {
push(@order,&unescape($item));
}
} else {
- &logthis("get_dom failed - no primary domain server for $udom");
+ &logthis("retrieve_inst_usertypes failed - no primary domain server for $udom");
}
+ return (\%returnhash,\@order);
}
- return (\%returnhash,\@order);
}
sub is_domainimage {
@@ -2007,7 +2034,8 @@ sub get_domain_defaults {
&Apache::lonnet::get_dom('configuration',['defaults','quotas',
'requestcourses','inststatus',
'coursedefaults','usersessions',
- 'requestauthor','selfenrollment'],$domain);
+ 'requestauthor','selfenrollment',
+ 'coursecategories'],$domain);
my @coursetypes = ('official','unofficial','community','textbook');
if (ref($domconfig{'defaults'}) eq 'HASH') {
$domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'};
@@ -2046,11 +2074,17 @@ sub get_domain_defaults {
$domdefaults{'requestauthor'} = $domconfig{'requestauthor'};
}
if (ref($domconfig{'inststatus'}) eq 'HASH') {
- foreach my $item ('inststatustypes','inststatusorder') {
+ foreach my $item ('inststatustypes','inststatusorder','inststatusguest') {
$domdefaults{$item} = $domconfig{'inststatus'}{$item};
}
}
if (ref($domconfig{'coursedefaults'}) eq 'HASH') {
+ $domdefaults{'canuse_pdfforms'} = $domconfig{'coursedefaults'}{'canuse_pdfforms'};
+ $domdefaults{'usejsme'} = $domconfig{'coursedefaults'}{'usejsme'};
+ $domdefaults{'uselcmath'} = $domconfig{'coursedefaults'}{'uselcmath'};
+ if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') {
+ $domdefaults{'postsubmit'} = $domconfig{'coursedefaults'}{'postsubmit'}{'client'};
+ }
foreach my $type (@coursetypes) {
if (ref($domconfig{'coursedefaults'}{'coursecredits'}) eq 'HASH') {
unless ($type eq 'community') {
@@ -2060,6 +2094,12 @@ sub get_domain_defaults {
if (ref($domconfig{'coursedefaults'}{'uploadquota'}) eq 'HASH') {
$domdefaults{$type.'quota'} = $domconfig{'coursedefaults'}{'uploadquota'}{$type};
}
+ if ($domdefaults{'postsubmit'} eq 'on') {
+ if (ref($domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') {
+ $domdefaults{$type.'postsubtimeout'} =
+ $domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}{$type};
+ }
+ }
}
}
if (ref($domconfig{'usersessions'}) eq 'HASH') {
@@ -2069,6 +2109,9 @@ sub get_domain_defaults {
if (ref($domconfig{'usersessions'}{'hosted'}) eq 'HASH') {
$domdefaults{'hostedsessions'} = $domconfig{'usersessions'}{'hosted'};
}
+ if (ref($domconfig{'usersessions'}{'offloadnow'}) eq 'HASH') {
+ $domdefaults{'offloadnow'} = $domconfig{'usersessions'}{'offloadnow'};
+ }
}
if (ref($domconfig{'selfenrollment'}) eq 'HASH') {
if (ref($domconfig{'selfenrollment'}{'admin'}) eq 'HASH') {
@@ -2098,6 +2141,16 @@ sub get_domain_defaults {
}
}
}
+ if (ref($domconfig{'coursecategories'}) eq 'HASH') {
+ $domdefaults{'catauth'} = 'std';
+ $domdefaults{'catunauth'} = 'std';
+ if ($domconfig{'coursecategories'}{'auth'}) {
+ $domdefaults{'catauth'} = $domconfig{'coursecategories'}{'auth'};
+ }
+ if ($domconfig{'coursecategories'}{'unauth'}) {
+ $domdefaults{'catunauth'} = $domconfig{'coursecategories'}{'unauth'};
+ }
+ }
&do_cache_new('domdefaults',$domain,\%domdefaults,$cachetime);
return %domdefaults;
}
@@ -2688,17 +2741,25 @@ sub ssi {
&Apache::lonenc::check_encrypt(\$fn);
if (%form) {
$request=new HTTP::Request('POST',&absolute_url().$fn);
- $request->content(join('&',map { &escape($_).'='.&escape($form{$_}) } keys(%form)));
+ $request->content(join('&',map {
+ my $name = escape($_);
+ "$name=" . ( ref($form{$_}) eq 'ARRAY'
+ ? join("&$name=", map {escape($_) } @{$form{$_}})
+ : &escape($form{$_}) );
+ } keys(%form)));
} else {
$request=new HTTP::Request('GET',&absolute_url().$fn);
}
$request->header(Cookie => $ENV{'HTTP_COOKIE'});
my $response= $ua->request($request);
+ my $content = $response->content;
+
+
if (wantarray) {
- return ($response->content, $response);
+ return ($content, $response);
} else {
- return $response->content;
+ return $content;
}
}
@@ -2730,7 +2791,7 @@ sub allowuploaded {
#
# Determine if the current user should be able to edit a particular resource,
# when viewing in course context.
-# (a) When viewing resource used to determine if "Edit" item is included in
+# (a) When viewing resource used to determine if "Edit" item is included in
# Functions.
# (b) When displaying folder contents in course editor, used to determine if
# "Edit" link will be displayed alongside resource.
@@ -2738,12 +2799,12 @@ sub allowuploaded {
# input: six args -- filename (decluttered), course number, course domain,
# url, symb (if registered) and group (if this is a group
# item -- e.g., bulletin board, group page etc.).
-# output: array of five scalars --
+# output: array of five scalars --
# $cfile -- url for file editing if editable on current server
# $home -- homeserver of resource (i.e., for author if published,
# or course if uploaded.).
# $switchserver -- 1 if server switch will be needed.
-# $forceedit -- 1 if icon/link should be to go to edit mode
+# $forceedit -- 1 if icon/link should be to go to edit mode
# $forceview -- 1 if icon/link should be to go to view mode
#
@@ -2832,7 +2893,7 @@ sub can_edit_resource {
$forceedit = 1;
}
$cfile = $resurl;
- } elsif (($resurl ne '') && (&is_on_map($resurl))) {
+ } elsif (($resurl ne '') && (&is_on_map($resurl))) {
if ($resurl =~ m{^/adm/$match_domain/$match_username/\d+/smppg|bulletinboard$}) {
$incourse = 1;
if ($env{'form.forceedit'}) {
@@ -2863,7 +2924,7 @@ sub can_edit_resource {
}
} elsif ($resurl eq '/res/lib/templates/simpleproblem.problem/smpedit') {
my $template = '/res/lib/templates/simpleproblem.problem';
- if (&is_on_map($template)) {
+ if (&is_on_map($template)) {
$incourse = 1;
$forceview = 1;
$cfile = $template;
@@ -2910,7 +2971,7 @@ sub can_edit_resource {
$cfile=$file;
}
}
- if (($cfile ne '') && (!$incourse || $uploaded) &&
+ if (($cfile ne '') && (!$incourse || $uploaded) &&
(($home ne '') && ($home ne 'no_host'))) {
my @ids=¤t_machine_ids();
unless (grep(/^\Q$home\E$/,@ids)) {
@@ -2937,9 +2998,9 @@ sub in_course {
if ($hideprivileged) {
my $skipuser;
my %coursehash = &coursedescription($cdom.'_'.$cnum);
- my @possdoms = ($cdom);
- if ($coursehash{'checkforpriv'}) {
- push(@possdoms,split(/,/,$coursehash{'checkforpriv'}));
+ my @possdoms = ($cdom);
+ if ($coursehash{'checkforpriv'}) {
+ push(@possdoms,split(/,/,$coursehash{'checkforpriv'}));
}
if (&privileged($uname,$udom,\@possdoms)) {
$skipuser = 1;
@@ -3443,7 +3504,7 @@ sub extract_embedded_items {
}
if (lc($tagname) eq 'a') {
unless (($attr->{'href'} =~ /^#/) || ($attr->{'href'} eq '')) {
- &add_filetype($allfiles,$attr->{'href'},'href');
+ &add_filetype($allfiles,$attr->{'href'},'href');
}
}
if (lc($tagname) eq 'script') {
@@ -4114,7 +4175,7 @@ sub get_my_roles {
} else {
my $possdoms = [$domain];
if (ref($roledoms) eq 'ARRAY') {
- push(@{$possdoms},@{$roledoms});
+ push(@{$possdoms},@{$roledoms});
}
if (&privileged($username,$domain,$possdoms,\@privroles)) {
if (!$nothide{$username.':'.$domain}) {
@@ -4222,16 +4283,16 @@ sub courseiddump {
if (($domfilter eq '') ||
(&host_domain($tryserver) eq $domfilter)) {
my $rep;
- if (grep { $_ eq $tryserver } ¤t_machine_ids()) {
- $rep = &LONCAPA::Lond::dump_course_id_handler(
- join(":", (&host_domain($tryserver), $sincefilter,
- &escape($descfilter), &escape($instcodefilter),
+ if (grep { $_ eq $tryserver } current_machine_ids()) {
+ $rep = LONCAPA::Lond::dump_course_id_handler(
+ join(":", (&host_domain($tryserver), $sincefilter,
+ &escape($descfilter), &escape($instcodefilter),
&escape($ownerfilter), &escape($coursefilter),
- &escape($typefilter), &escape($regexp_ok),
- $as_hash, &escape($selfenrollonly),
- &escape($catfilter), $showhidden, $caller,
- &escape($cloner), &escape($cc_clone), $cloneonly,
- &escape($createdbefore), &escape($createdafter),
+ &escape($typefilter), &escape($regexp_ok),
+ $as_hash, &escape($selfenrollonly),
+ &escape($catfilter), $showhidden, $caller,
+ &escape($cloner), &escape($cc_clone), $cloneonly,
+ &escape($createdbefore), &escape($createdafter),
&escape($creationcontext), $domcloner, $hasuniquecode)));
} else {
$rep = &reply('courseiddump:'.&host_domain($tryserver).':'.
@@ -4246,7 +4307,7 @@ sub courseiddump {
&escape($creationcontext).':'.$domcloner.':'.$hasuniquecode,
$tryserver);
}
-
+
my @pairs=split(/\&/,$rep);
foreach my $item (@pairs) {
my ($key,$value)=split(/\=/,$item,2);
@@ -4445,92 +4506,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 {
@@ -4901,7 +4876,7 @@ sub tmprestore {
# ----------------------------------------------------------------------- Store
sub store {
- my ($storehash,$symb,$namespace,$domain,$stuname) = @_;
+ my ($storehash,$symb,$namespace,$domain,$stuname,$laststore) = @_;
my $home='';
if ($stuname) { $home=&homeserver($stuname,$domain); }
@@ -4931,13 +4906,13 @@ sub store {
}
$namevalue=~s/\&$//;
&courselog($symb.':'.$stuname.':'.$domain.':STORE:'.$namevalue);
- return reply("store:$domain:$stuname:$namespace:$symb:$namevalue","$home");
+ return reply("store:$domain:$stuname:$namespace:$symb:$namevalue:$laststore","$home");
}
# -------------------------------------------------------------- Critical Store
sub cstore {
- my ($storehash,$symb,$namespace,$domain,$stuname) = @_;
+ my ($storehash,$symb,$namespace,$domain,$stuname,$laststore) = @_;
my $home='';
if ($stuname) { $home=&homeserver($stuname,$domain); }
@@ -4968,7 +4943,7 @@ sub cstore {
$namevalue=~s/\&$//;
&courselog($symb.':'.$stuname.':'.$domain.':CSTORE:'.$namevalue);
return critical
- ("store:$domain:$stuname:$namespace:$symb:$namevalue","$home");
+ ("store:$domain:$stuname:$namespace:$symb:$namevalue:$laststore","$home");
}
# --------------------------------------------------------------------- Restore
@@ -5124,7 +5099,7 @@ sub privileged {
my $now = time;
my $roles;
if (ref($possroles) eq 'ARRAY') {
- $roles = $possroles;
+ $roles = $possroles;
} else {
$roles = ['dc','su'];
}
@@ -5148,10 +5123,10 @@ sub privileged {
my %rolesdump = &dump("roles", $domain, $username) or return 0;
my $now = time;
- for my $role (@rolesdump{grep { ! /^rolesdef_/ } keys %rolesdump}) {
+ for my $role (@rolesdump{grep { ! /^rolesdef_/ } keys(%rolesdump)}) {
my ($trole, $tend, $tstart) = split(/_/, $role);
if (grep(/^\Q$trole\E$/,@{$roles})) {
- return 1 unless ($tend && $tend < $now)
+ return 1 unless ($tend && $tend < $now)
or ($tstart && $tstart > $now);
}
}
@@ -5189,7 +5164,7 @@ sub privileged_by_domain {
my ($trole,$uname,$udom,$rest) = split(/:/,$item,4);
my ($end,$start) = split(/:/,$dompersonnel{$server}{$item});
next if ($end && $end < $now);
- $privileged{$dom}{$trole}{$uname.':'.$udom} =
+ $privileged{$dom}{$trole}{$uname.':'.$udom} =
$dompersonnel{$server}{$item};
}
}
@@ -5237,7 +5212,7 @@ sub rolesinit {
my %allroles=();
my %allgroups=();
- for my $area (grep { ! /^rolesdef_/ } keys %rolesdump) {
+ for my $area (grep { ! /^rolesdef_/ } keys(%rolesdump)) {
my $role = $rolesdump{$area};
$area =~ s/\_\w\w$//;
@@ -5660,14 +5635,15 @@ sub unserialize {
return {} if $rep =~ /^error/;
my %returnhash=();
- foreach my $item (split(/\&/,$rep)) {
- my ($key, $value) = split(/=/, $item, 2);
- $key = unescape($key) unless $escapedkeys;
- next if $key =~ /^error: 2 /;
- $returnhash{$key} = &thaw_unescape($value);
- }
+ foreach my $item (split(/\&/,$rep)) {
+ my ($key, $value) = split(/=/, $item, 2);
+ $key = unescape($key) unless $escapedkeys;
+ next if $key =~ /^error: 2 /;
+ $returnhash{$key} = &thaw_unescape($value);
+ }
+ #return %returnhash;
return \%returnhash;
-}
+}
# see Lond::dump_with_regexp
# if $escapedkeys hash keys won't get unescaped.
@@ -5677,17 +5653,16 @@ sub dump {
if (!$uname) { $uname=$env{'user.name'}; }
my $uhome=&homeserver($uname,$udomain);
- my $reply;
- if (grep { $_ eq $uhome } ¤t_machine_ids()) {
- # user is hosted on this machine
- $reply = LONCAPA::Lond::dump_with_regexp(join(':', ($udomain,
- $uname, $namespace, $regexp, $range)), $perlvar{'lonVersion'});
- return %{&unserialize($reply, $escapedkeys)};
- }
if ($regexp) {
- $regexp=&escape($regexp);
+ $regexp=&escape($regexp);
} else {
- $regexp='.';
+ $regexp='.';
+ }
+ if (grep { $_ eq $uhome } current_machine_ids()) {
+ # user is hosted on this machine
+ my $reply = LONCAPA::Lond::dump_with_regexp(join(":", ($udomain,
+ $uname, $namespace, $regexp, $range)), $perlvar{'lonVersion'});
+ return %{unserialize($reply, $escapedkeys)};
}
my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome);
my @pairs=split(/\&/,$rep);
@@ -5695,7 +5670,8 @@ sub dump {
if (!($rep =~ /^error/ )) {
foreach my $item (@pairs) {
my ($key,$value)=split(/=/,$item,2);
- $key = &unescape($key) unless ($escapedkeys);
+ $key = unescape($key) unless $escapedkeys;
+ #$key = &unescape($key);
next if ($key =~ /^error: 2 /);
$returnhash{$key}=&thaw_unescape($value);
}
@@ -5736,7 +5712,15 @@ sub currentdump {
$sdom = $env{'user.domain'} if (! defined($sdom));
$sname = $env{'user.name'} if (! defined($sname));
my $uhome = &homeserver($sname,$sdom);
- my $rep=reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome);
+ my $rep;
+
+ if (grep { $_ eq $uhome } current_machine_ids()) {
+ $rep = LONCAPA::Lond::dump_profile_database(join(":", ($sdom, $sname,
+ $courseid)));
+ } else {
+ $rep = reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome);
+ }
+
return if ($rep =~ /^(error:|no_such_host)/);
#
my %returnhash=();
@@ -5857,7 +5841,7 @@ sub newput {
# --------------------------------------------------------- putstore interface
sub putstore {
- my ($namespace,$symb,$version,$storehash,$udomain,$uname)=@_;
+ my ($namespace,$symb,$version,$storehash,$udomain,$uname,$tolog)=@_;
if (!$udomain) { $udomain=$env{'user.domain'}; }
if (!$uname) { $uname=$env{'user.name'}; }
my $uhome=&homeserver($uname,$udomain);
@@ -5871,6 +5855,17 @@ sub putstore {
my $reply =
&reply("putstore:$udomain:$uname:$namespace:$esc_symb:$esc_v:$items",
$uhome);
+ if (($tolog) && ($reply eq 'ok')) {
+ my $namevalue='';
+ foreach my $key (keys(%{$storehash})) {
+ $namevalue.=&escape($key).'='.&freeze_escape($storehash->{$key}).'&';
+ }
+ $namevalue .= 'ip='.&escape($ENV{'REMOTE_ADDR'}).
+ '&host='.&escape($perlvar{'lonHostID'}).
+ '&version='.$esc_v.
+ '&by='.&escape($env{'user.name'}.':'.$env{'user.domain'});
+ &Apache::lonnet::courselog($symb.':'.$uname.':'.$udomain.':PUTSTORE:'.$namevalue);
+ }
if ($reply eq 'unknown_cmd') {
# gfall back to way things use to be done
return &old_putstore($namespace,$symb,$version,$storehash,$udomain,
@@ -5979,13 +5974,13 @@ sub tmpdel {
return &reply("tmpdel:$token",$server);
}
-# ------------------------------------------------------------ get_timebased_id
+# ------------------------------------------------------------ get_timebased_id
sub get_timebased_id {
my ($prefix,$keyid,$namespace,$cdom,$cnum,$idtype,$who,$locktries,
$maxtries) = @_;
my ($newid,$error,$dellock);
- unless (($prefix =~ /^\w+$/) && ($keyid =~ /^\w+$/) && ($namespace ne '')) {
+ unless (($prefix =~ /^\w+$/) && ($keyid =~ /^\w+$/) && ($namespace ne '')) {
return ('','ok','invalid call to get suffix');
}
@@ -5999,7 +5994,7 @@ sub get_timebased_id {
if (!$maxtries) {
$maxtries = 10;
}
-
+
if (($cdom eq '') || ($cnum eq '')) {
if ($env{'request.course.id'}) {
$cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
@@ -6029,10 +6024,15 @@ sub get_timebased_id {
my %inuse = &Apache::lonnet::dump('nohist_'.$namespace,$cdom,$cnum,$prefix);
my $id = time;
$newid = $id;
+ if ($idtype eq 'addcode') {
+ $newid .= &sixnum_code();
+ }
my $idtries = 0;
while (exists($inuse{$prefix."\0".$newid}) && $idtries < $maxtries) {
if ($idtype eq 'concat') {
$newid = $id.$idtries;
+ } elsif ($idtype eq 'addcode') {
+ $newid = $newid.&sixnum_code();
} else {
$newid ++;
}
@@ -6049,6 +6049,7 @@ sub get_timebased_id {
$error = 'error saving new item: '.$putresult;
}
} else {
+ undef($newid);
$error = ('error: no unique suffix available for the new item ');
}
# remove lock
@@ -6057,16 +6058,27 @@ sub get_timebased_id {
} else {
$error = "error: could not obtain lockfile\n";
$dellock = 'ok';
+ if (($prefix eq 'paste') && ($namespace eq 'courseeditor') && ($keyid eq 'num')) {
+ $dellock = 'nolock';
+ }
}
return ($newid,$dellock,$error);
}
+sub sixnum_code {
+ my $code;
+ for (0..6) {
+ $code .= int( rand(9) );
+ }
+ return $code;
+}
+
# -------------------------------------------------- portfolio access checking
sub portfolio_access {
- my ($requrl) = @_;
+ my ($requrl,$clientip) = @_;
my (undef,$udom,$unum,$file_name,$group) = &parse_portfolio_url($requrl);
- my $result = &get_portfolio_access($udom,$unum,$file_name,$group);
+ my $result = &get_portfolio_access($udom,$unum,$file_name,$group,$clientip);
if ($result) {
my %setters;
if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') {
@@ -6092,7 +6104,7 @@ sub portfolio_access {
}
sub get_portfolio_access {
- my ($udom,$unum,$file_name,$group,$access_hash) = @_;
+ my ($udom,$unum,$file_name,$group,$clientip,$access_hash) = @_;
if (!ref($access_hash)) {
my $current_perms = &get_portfile_permissions($udom,$unum);
@@ -6101,7 +6113,7 @@ sub get_portfolio_access {
$access_hash = $access_controls{$file_name};
}
- my ($public,$guest,@domains,@users,@courses,@groups);
+ my ($public,$guest,@domains,@users,@courses,@groups,@ips);
my $now = time;
if (ref($access_hash) eq 'HASH') {
foreach my $key (keys(%{$access_hash})) {
@@ -6125,10 +6137,25 @@ sub get_portfolio_access {
push(@courses,$key);
} elsif ($scope eq 'group') {
push(@groups,$key);
+ } elsif ($scope eq 'ip') {
+ push(@ips,$key);
}
}
if ($public) {
return 'ok';
+ } elsif (@ips > 0) {
+ my $allowed;
+ foreach my $ipkey (@ips) {
+ if (ref($access_hash->{$ipkey}{'ip'}) eq 'ARRAY') {
+ if (&Apache::loncommon::check_ip_acc(join(',',@{$access_hash->{$ipkey}{'ip'}}),$clientip)) {
+ $allowed = 1;
+ last;
+ }
+ }
+ }
+ if ($allowed) {
+ return 'ok';
+ }
}
if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') {
if ($guest) {
@@ -6350,7 +6377,7 @@ sub usertools_access {
my ($toolstatus,$inststatus,$envkey);
if ($context eq 'requestauthor') {
- $envkey = $context;
+ $envkey = $context;
} else {
$envkey = $context.'.'.$tool;
}
@@ -6612,7 +6639,7 @@ sub customaccess {
# ------------------------------------------------- Check for a user privilege
sub allowed {
- my ($priv,$uri,$symb,$role)=@_;
+ my ($priv,$uri,$symb,$role,$clientip)=@_;
my $ver_orguri=$uri;
$uri=&deversion($uri);
my $orguri=$uri;
@@ -6839,9 +6866,9 @@ sub allowed {
&& $thisallowed ne 'F'
&& $thisallowed ne '2'
&& &is_portfolio_url($uri)) {
- $thisallowed = &portfolio_access($uri);
+ $thisallowed = &portfolio_access($uri,$clientip);
}
-
+
# Full access at system, domain or course-wide level? Exit.
if ($thisallowed=~/F/) {
return 'F';
@@ -7428,9 +7455,9 @@ sub metadata_query {
my @server_list = (defined($server_array) ? @$server_array
: keys(%libserv) );
for my $server (@server_list) {
- my $domains = '';
+ my $domains = '';
if (ref($domains_hash) eq 'HASH') {
- $domains = $domains_hash->{$server};
+ $domains = $domains_hash->{$server};
}
unless ($custom or $customshow) {
my $reply=&reply("querysend:".&escape($query).':::'.&escape($domains),$server);
@@ -7961,7 +7988,7 @@ sub auto_validate_class_sec {
sub auto_crsreq_update {
my ($cdom,$cnum,$crstype,$action,$ownername,$ownerdomain,$fullname,$title,
- $code,$inbound) = @_;
+ $code,$accessstart,$accessend,$inbound) = @_;
my ($homeserver,%crsreqresponse);
if ($cdom =~ /^$match_domain$/) {
$homeserver = &domain($cdom,'primary');
@@ -7974,7 +8001,9 @@ sub auto_crsreq_update {
my $response=&reply('autocrsrequpdate:'.$cdom.':'.$cnum.':'.&escape($crstype).
':'.&escape($action).':'.&escape($ownername).':'.
&escape($ownerdomain).':'.&escape($fullname).':'.
- &escape($title).':'.&escape($code).':'.$info,$homeserver);
+ &escape($title).':'.&escape($code).':'.
+ &escape($accessstart).':'.&escape($accessend).':'.$info,
+ $homeserver);
unless ($response =~ /(con_lost|error|no_such_host|refused)/) {
my @items = split(/&/,$response);
foreach my $item (@items) {
@@ -8254,7 +8283,7 @@ sub assignrole {
}
}
} elsif ($context eq 'requestauthor') {
- if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'}) &&
+ if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'}) &&
($url eq '/'.$udom.'/') && ($role eq 'au')) {
if ($env{'environment.requestauthor'} eq 'automatic') {
$refused = '';
@@ -8262,13 +8291,13 @@ sub assignrole {
my %domdefaults = &get_domain_defaults($udom);
if (ref($domdefaults{'requestauthor'}) eq 'HASH') {
my $checkbystatus;
- if ($env{'user.adv'}) {
+ if ($env{'user.adv'}) {
my $disposition = $domdefaults{'requestauthor'}{'_LC_adv'};
if ($disposition eq 'automatic') {
$refused = '';
} elsif ($disposition eq '') {
$checkbystatus = 1;
- }
+ }
} else {
$checkbystatus = 1;
}
@@ -8355,7 +8384,7 @@ sub assignrole {
$context);
} elsif (($role eq 'ca') || ($role eq 'aa')) {
&coauthorrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag,
- $context);
+ $context);
}
if ($role eq 'cc') {
&autoupdate_coowners($url,$end,$start,$uname,$udom);
@@ -8670,7 +8699,7 @@ sub modifystudent {
# student's environment
$uid = undef if (!$forceid);
$reply = &modify_student_enrollment($udom,$uname,$uid,$first,$middle,$last,
- $gene,$usec,$end,$start,$type,$locktype,
+ $gene,$usec,$end,$start,$type,$locktype,
$cid,$selfenroll,$context,$credits);
return $reply;
}
@@ -9152,6 +9181,90 @@ sub files_not_in_path {
return (@return_files);
}
+#------------------------------Submitted/Handedback Portfolio Files Versioning
+
+sub portfiles_versioning {
+ my ($symb,$domain,$stu_name,$portfiles,$versioned_portfiles) = @_;
+ my $portfolio_root = '/userfiles/portfolio';
+ return unless ((ref($portfiles) eq 'ARRAY') && (ref($versioned_portfiles) eq 'ARRAY'));
+ foreach my $file (@{$portfiles}) {
+ &unmark_as_readonly($domain,$stu_name,[$symb,$env{'request.course.id'}],$file);
+ my ($directory,$answer_file) =($file =~ /^(.*?)([^\/]*)$/);
+ my ($answer_name,$answer_ver,$answer_ext) = &file_name_version_ext($answer_file);
+ my $getpropath = 1;
+ my ($dir_list,$listerror) = &dirlist($portfolio_root.$directory,$domain,
+ $stu_name,$getpropath);
+ my $version = &get_next_version($answer_name,$answer_ext,$dir_list);
+ my $new_answer =
+ &version_selected_portfile($domain,$stu_name,$directory,$answer_file,$version);
+ if ($new_answer ne 'problem getting file') {
+ push(@{$versioned_portfiles}, $directory.$new_answer);
+ &mark_as_readonly($domain,$stu_name,[$directory.$new_answer],
+ [$symb,$env{'request.course.id'},'graded']);
+ }
+ }
+}
+
+sub get_next_version {
+ my ($answer_name, $answer_ext, $dir_list) = @_;
+ my $version;
+ if (ref($dir_list) eq 'ARRAY') {
+ foreach my $row (@{$dir_list}) {
+ my ($file) = split(/\&/,$row,2);
+ my ($file_name,$file_version,$file_ext) =
+ &file_name_version_ext($file);
+ if (($file_name eq $answer_name) &&
+ ($file_ext eq $answer_ext)) {
+ # gets here if filename and extension match,
+ # regardless of version
+ if ($file_version ne '') {
+ # a versioned file is found so save it for later
+ if ($file_version > $version) {
+ $version = $file_version;
+ }
+ }
+ }
+ }
+ }
+ $version ++;
+ return($version);
+}
+
+sub version_selected_portfile {
+ my ($domain,$stu_name,$directory,$file_name,$version) = @_;
+ my ($answer_name,$answer_ver,$answer_ext) =
+ &file_name_version_ext($file_name);
+ my $new_answer;
+ $env{'form.copy'} =
+ &getfile("/uploaded/$domain/$stu_name/portfolio$directory$file_name");
+ if($env{'form.copy'} eq '-1') {
+ $new_answer = 'problem getting file';
+ } else {
+ $new_answer = $answer_name.'.'.$version.'.'.$answer_ext;
+ my $copy_result =
+ &finishuserfileupload($stu_name,$domain,'copy',
+ '/portfolio'.$directory.$new_answer);
+ }
+ undef($env{'form.copy'});
+ return ($new_answer);
+}
+
+sub file_name_version_ext {
+ my ($file)=@_;
+ my @file_parts = split(/\./, $file);
+ my ($name,$version,$ext);
+ if (@file_parts > 1) {
+ $ext=pop(@file_parts);
+ if (@file_parts > 1 && $file_parts[-1] =~ /^\d+$/) {
+ $version=pop(@file_parts);
+ }
+ $name=join('.',@file_parts);
+ } else {
+ $name=join('.',@file_parts);
+ }
+ return($name,$version,$ext);
+}
+
#----------------------------------------------Get portfolio file permissions
sub get_portfile_permissions {
@@ -9296,49 +9409,132 @@ sub modify_access_controls {
}
sub make_public_indefinitely {
- my ($requrl) = @_;
+ my (@requrl) = @_;
+ return &automated_portfile_access('public',\@requrl);
+}
+
+sub automated_portfile_access {
+ my ($accesstype,$addsref,$delsref,$info) = @_;
+ unless (($accesstype eq 'public') || ($accesstype eq 'ip')) {
+ return 'invalid';
+ }
+ my %urls;
+ if (ref($addsref) eq 'ARRAY') {
+ foreach my $requrl (@{$addsref}) {
+ if (&is_portfolio_url($requrl)) {
+ unless (exists($urls{$requrl})) {
+ $urls{$requrl} = 'add';
+ }
+ }
+ }
+ }
+ if (ref($delsref) eq 'ARRAY') {
+ foreach my $requrl (@{$delsref}) {
+ if (&is_portfolio_url($requrl)) {
+ unless (exists($urls{$requrl})) {
+ $urls{$requrl} = 'delete';
+ }
+ }
+ }
+ }
+ unless (keys(%urls)) {
+ return 'invalid';
+ }
+ my $ip;
+ if ($accesstype eq 'ip') {
+ if (ref($info) eq 'HASH') {
+ if ($info->{'ip'} ne '') {
+ $ip = $info->{'ip'};
+ }
+ }
+ if ($ip eq '') {
+ return 'invalid';
+ }
+ }
+ my $errors;
my $now = time;
- my $action = 'activate';
- my $aclnum = 0;
- if (&is_portfolio_url($requrl)) {
+ my %current_perms;
+ foreach my $requrl (sort(keys(%urls))) {
+ my $action;
+ if ($urls{$requrl} eq 'add') {
+ $action = 'activate';
+ } else {
+ $action = 'none';
+ }
+ my $aclnum = 0;
my (undef,$udom,$unum,$file_name,$group) =
&parse_portfolio_url($requrl);
- my $current_perms = &get_portfile_permissions($udom,$unum);
- my %access_controls = &get_access_controls($current_perms,
+ unless (exists($current_perms{$unum.':'.$udom})) {
+ $current_perms{$unum.':'.$udom} = &get_portfile_permissions($udom,$unum);
+ }
+ my %access_controls = &get_access_controls($current_perms{$unum.':'.$udom},
$group,$file_name);
foreach my $key (keys(%{$access_controls{$file_name}})) {
my ($num,$scope,$end,$start) =
($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
- if ($scope eq 'public') {
- if ($start <= $now && $end == 0) {
- $action = 'none';
- } else {
+ if ($scope eq $accesstype) {
+ if (($start <= $now) && ($end == 0)) {
+ if ($accesstype eq 'ip') {
+ if (ref($access_controls{$file_name}{$key}) eq 'HASH') {
+ if (ref($access_controls{$file_name}{$key}{'ip'}) eq 'ARRAY') {
+ if (grep(/^\Q$ip\E$/,@{$access_controls{$file_name}{$key}{'ip'}})) {
+ if ($urls{$requrl} eq 'add') {
+ $action = 'none';
+ last;
+ } else {
+ $action = 'delete';
+ $aclnum = $num;
+ last;
+ }
+ }
+ }
+ }
+ } elsif ($accesstype eq 'public') {
+ if ($urls{$requrl} eq 'add') {
+ $action = 'none';
+ last;
+ } else {
+ $action = 'delete';
+ $aclnum = $num;
+ last;
+ }
+ }
+ } elsif ($accesstype eq 'public') {
$action = 'update';
$aclnum = $num;
+ last;
}
- last;
}
}
if ($action eq 'none') {
- return 'ok';
+ next;
} else {
my %changes;
my $newend = 0;
my $newstart = $now;
- my $newkey = $aclnum.':public_'.$newend.'_'.$newstart;
+ my $newkey = $aclnum.':'.$accesstype.'_'.$newend.'_'.$newstart;
$changes{$action}{$newkey} = {
- type => 'public',
+ type => $accesstype,
time => {
start => $newstart,
end => $newend,
},
};
+ if ($accesstype eq 'ip') {
+ $changes{$action}{$newkey}{'ip'} = [$ip];
+ }
my ($outcome,$deloutcome,$new_values,$translation) =
&modify_access_controls($file_name,\%changes,$udom,$unum);
- return $outcome;
+ unless ($outcome eq 'ok') {
+ $errors .= $outcome.' ';
+ }
}
+ }
+ if ($errors) {
+ $errors =~ s/\s$//;
+ return $errors;
} else {
- return 'invalid';
+ return 'ok';
}
}
@@ -9815,7 +10011,7 @@ sub get_numsuppfiles {
unless ($chome eq 'no_host') {
($suppcount,my $errors) = (0,0);
my $suppmap = 'supplemental.sequence';
- ($suppcount,$errors) =
+ ($suppcount,$errors) =
&Apache::loncommon::recurse_supplemental($cnum,$cdom,$suppmap,$suppcount,$errors);
}
&do_cache_new('suppcount',$hashid,$suppcount,600);
@@ -10010,7 +10206,7 @@ sub EXT {
$courseid = $cid;
}
if (($symbparm && $courseid) &&
- (($courseid eq $env{'request.course.id'}) || ($courseid eq $cid))) {
+ (($courseid eq $env{'request.course.id'}) || ($courseid eq $cid))) {
#print '
'.$space.' - '.$qualifier.' - '.$spacequalifierrest;
@@ -10261,7 +10457,7 @@ sub metadata {
($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ m{^/*uploaded/.+\.sequence$})) {
return undef;
}
- if (($uri =~ /^priv/ || $uri=~/home\/httpd\/html\/priv/)
+ if (($uri =~ /^priv/ || $uri=~m{^home/httpd/html/priv})
&& &Apache::lonxml::get_state('target') =~ /^(|meta)$/) {
return undef;
}
@@ -10522,7 +10718,7 @@ sub metadata {
$metaentry{':keys'} = join(',',keys(%metathesekeys));
&metadata_generate_part0(\%metathesekeys,\%metaentry,$uri);
- $metaentry{':allpossiblekeys'}=join(',',keys %metathesekeys);
+ $metaentry{':allpossiblekeys'}=join(',',keys(%metathesekeys));
&do_cache_new('meta',$uri,\%metaentry,$cachetime);
# this is the end of "was not already recently cached
}
@@ -10798,7 +10994,7 @@ sub symbverify {
$ids=$bighash{'ids_'.&clutter($thisurl)};
}
unless ($ids) {
- my $idkey = 'ids_'.($thisurl =~ m{^/}? '' : '/').$thisurl;
+ my $idkey = 'ids_'.($thisurl =~ m{^/}? '' : '/').$thisurl;
$ids=$bighash{$idkey};
}
if ($ids) {
@@ -10814,14 +11010,14 @@ sub symbverify {
if (ref($encstate)) {
$$encstate = $bighash{'encrypted_'.$id};
}
- if (($env{'request.role.adv'}) ||
- ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) ||
+ if (($env{'request.role.adv'}) ||
+ ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) ||
($thisurl eq '/adm/navmaps')) {
- $okay=1;
+ $okay=1;
last;
- }
- }
- }
+ }
+ }
+ }
}
untie(%bighash);
}
@@ -10894,18 +11090,14 @@ sub deversion {
sub symbread {
my ($thisfn,$donotrecurse)=@_;
- my $cache_str;
- if ($thisfn ne '') {
- $cache_str='request.symbread.cached.'.$thisfn;
- if ($env{$cache_str} ne '') {
- return $env{$cache_str};
- }
- } else {
+ my $cache_str='request.symbread.cached.'.$thisfn;
+ if (defined($env{$cache_str})) { return $env{$cache_str}; }
# no filename provided? try from environment
+ unless ($thisfn) {
if ($env{'request.symb'}) {
- return $env{$cache_str}=&symbclean($env{'request.symb'});
- }
- $thisfn=$env{'request.filename'};
+ return $env{$cache_str}=&symbclean($env{'request.symb'});
+ }
+ $thisfn=$env{'request.filename'};
}
if ($thisfn=~m|^/enc/|) { $thisfn=&Apache::lonenc::unencrypted($thisfn); }
# is that filename actually a symb? Verify, clean, and return
@@ -11133,6 +11325,7 @@ sub rndseed {
$which =&get_rand_alg($courseid);
}
if (defined(&getCODE())) {
+
if ($which eq '64bit5') {
return &rndseed_CODE_64bit5($symb,$courseid,$domain,$username);
} elsif ($which eq '64bit4') {
@@ -11318,8 +11511,12 @@ sub rndseed_CODE_64bit5 {
sub setup_random_from_rndseed {
my ($rndseed)=@_;
if ($rndseed =~/([,:])/) {
- my ($num1,$num2)=split(/[,:]/,$rndseed);
- &Math::Random::random_set_seed(abs($num1),abs($num2));
+ my ($num1,$num2) = map { abs($_); } (split(/[,:]/,$rndseed));
+ if ((!$num1) || (!$num2) || ($num1 > 2147483562) || ($num2 > 2147483398)) {
+ &Math::Random::random_set_seed_from_phrase($rndseed);
+ } else {
+ &Math::Random::random_set_seed($num1,$num2);
+ }
} else {
&Math::Random::random_set_seed_from_phrase($rndseed);
}
@@ -11710,7 +11907,9 @@ sub default_login_domain {
sub declutter {
my $thisfn=shift;
if ($thisfn=~m|^/enc/|) { $thisfn=&Apache::lonenc::unencrypted($thisfn); }
- $thisfn=~s/^\Q$perlvar{'lonDocRoot'}\E//;
+ unless ($thisfn=~m{^/home/httpd/html/priv/}) {
+ $thisfn=~s{^/home/httpd/html}{};
+ }
$thisfn=~s/^\///;
$thisfn=~s|^adm/wrapper/||;
$thisfn=~s|^adm/coursedocs/showdoc/||;
@@ -11837,7 +12036,7 @@ sub get_dns {
$alldns{$host} = $protocol;
}
while (%alldns) {
- my ($dns) = keys(%alldns);
+ my ($dns) = sort { $b cmp $a } keys(%alldns);
my $ua=new LWP::UserAgent;
$ua->timeout(30);
my $request=new HTTP::Request('GET',"$alldns{$dns}://$dns$url");
@@ -11845,9 +12044,9 @@ sub get_dns {
delete($alldns{$dns});
next if ($response->is_error());
my @content = split("\n",$response->content);
- unless ($nocache) {
+ unless ($nocache) {
&do_cache_new('dns',$url,\@content,30*24*60*60);
- }
+ }
&$func(\@content,$hashref);
return;
}
@@ -11863,16 +12062,35 @@ sub get_dns {
# ------------------------------------------------------Get DNS checksums file
sub parse_dns_checksums_tab {
my ($lines,$hashref) = @_;
- my $machine_dom = &Apache::lonnet::host_domain($perlvar{'lonHostID'});
+ my $lonhost = $perlvar{'lonHostID'};
+ my $machine_dom = &Apache::lonnet::host_domain($lonhost);
my $loncaparev = &get_server_loncaparev($machine_dom);
+ my $distro = (split(/\:/,&get_server_distarch($lonhost)))[0];
+ my $webconfdir = '/etc/httpd/conf';
+ if ($distro =~ /^(ubuntu|debian)(\d+)$/) {
+ $webconfdir = '/etc/apache2';
+ } elsif ($distro =~ /^sles(\d+)$/) {
+ if ($1 >= 10) {
+ $webconfdir = '/etc/apache2';
+ }
+ } elsif ($distro =~ /^suse(\d+\.\d+)$/) {
+ if ($1 >= 10.0) {
+ $webconfdir = '/etc/apache2';
+ }
+ }
my ($release,$timestamp) = split(/\-/,$loncaparev);
my (%chksum,%revnum);
if (ref($lines) eq 'ARRAY') {
chomp(@{$lines});
my $version = shift(@{$lines});
- if ($version eq $release) {
+ if ($version eq $release) {
foreach my $line (@{$lines}) {
my ($file,$version,$shasum) = split(/,/,$line);
+ if ($file =~ m{^/etc/httpd/conf}) {
+ if ($webconfdir eq '/etc/apache2') {
+ $file =~ s{^\Q/etc/httpd/conf/\E}{$webconfdir/};
+ }
+ }
$chksum{$file} = $shasum;
$revnum{$file} = $version;
}
@@ -11890,7 +12108,7 @@ sub parse_dns_checksums_tab {
sub fetch_dns_checksums {
my %checksums;
my $machine_dom = &Apache::lonnet::host_domain($perlvar{'lonHostID'});
- my $loncaparev = &get_server_loncaparev($machine_dom);
+ my $loncaparev = &get_server_loncaparev($machine_dom,$perlvar{'lonHostID'});
my ($release,$timestamp) = split(/\-/,$loncaparev);
&get_dns("/adm/dns/checksums/$release",\&parse_dns_checksums_tab,1,1,
\%checksums);
@@ -12273,9 +12491,9 @@ sub all_loncaparevs {
return qw(1.1 1.2 1.3 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11);
}
-# ------------------------------------------------------- Read loncaparev table
+# ---------------------------------------------------------- Read loncaparev table
{
- sub load_loncaparevs {
+ sub load_loncaparevs {
if (-e "$perlvar{'lonTabDir'}/loncaparevs.tab") {
if (open(my $config,"<$perlvar{'lonTabDir'}/loncaparevs.tab")) {
while (my $configline=<$config>) {
@@ -12289,7 +12507,7 @@ sub all_loncaparevs {
}
}
-# ----------------------------------------------------- Read serverhostID table
+# ---------------------------------------------------------- Read serverhostID table
{
sub load_serverhomeIDs {
if (-e "$perlvar{'lonTabDir'}/serverhomeIDs.tab") {
@@ -12381,11 +12599,11 @@ BEGIN {
close($config);
}
-# --------------------------------------------------------- Read loncaparev table
+# ---------------------------------------------------------- Read loncaparev table
&load_loncaparevs();
-# ------------------------------------------------------- Read serverhostID table
+# ---------------------------------------------------------- Read serverhostID table
&load_serverhomeIDs();
@@ -12589,7 +12807,7 @@ were new keys. I.E. 1:foo will become 1:
Calling convention:
my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$uname);
- &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$uname);
+ &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$uname,$laststore);
For more detailed information, see lonnet specific documentation.
@@ -12783,9 +13001,9 @@ provided for types, will default to retu
=item *
in_course($udom,$uname,$cdom,$cnum,$type,$hideprivileged) : determine if
-user: $uname:$udom has a role in the course: $cdom_$cnum.
+user: $uname:$udom has a role in the course: $cdom_$cnum.
-Additional optional arguments are: $type (if role checking is to be restricted
+Additional optional arguments are: $type (if role checking is to be restricted
to certain user status types -- previous (expired roles), active (currently
available roles) or future (roles available in the future), and
$hideprivileged -- if true will not report course roles for users who
@@ -13022,7 +13240,7 @@ values that are the resource value. I b
versions are also returned.
get_numsuppfiles($cnum,$cdom) : retrieve number of files in a course's
-supplemental content area. This routine caches the number of files for
+supplemental content area. This routine caches the number of files for
10 minutes.
=back
@@ -13135,9 +13353,9 @@ and is a possible symb for the URL in $t
resource that the user accessed using /enc/ returns a 1 on success, 0
on failure, user must be in a course, as it assumes the existence of
the course initial hash, and uses $env('request.course.id'}. The third
-arg is an optional reference to a scalar. If this arg is passed in the
+arg is an optional reference to a scalar. If this arg is passed in the
call to symbverify, it will be set to 1 if the symb has been set to be
-encrypted; otherwise it will be null.
+encrypted; otherwise it will be null.
=item *
@@ -13190,13 +13408,13 @@ expirespread($uname,$udom,$stype,$usymb)
devalidate($symb) : devalidate temporary spreadsheet calculations,
forcing spreadsheet to reevaluate the resource scores next time.
-=item *
+=item *
can_edit_resource($file,$cnum,$cdom,$resurl,$symb,$group) : determine if current user can edit a particular resource,
when viewing in course context.
input: six args -- filename (decluttered), course number, course domain,
- url, symb (if registered) and group (if this is a
+ url, symb (if registered) and group (if this is a
group item -- e.g., bulletin board, group page etc.).
output: array of five scalars --
@@ -13204,15 +13422,15 @@ when viewing in course context.
$home -- homeserver of resource (i.e., for author if published,
or course if uploaded.).
$switchserver -- 1 if server switch will be needed.
- $forceedit -- 1 if icon/link should be to go to edit mode
+ $forceedit -- 1 if icon/link should be to go to edit mode
$forceview -- 1 if icon/link should be to go to view mode
=item *
is_course_upload($file,$cnum,$cdom)
-Used in course context to determine if current file was uploaded to
-the course (i.e., would be found in /userfiles/docs on the course's
+Used in course context to determine if current file was uploaded to
+the course (i.e., would be found in /userfiles/docs on the course's
homeserver.
input: 3 args -- filename (decluttered), course number and course domain.
@@ -13226,15 +13444,21 @@ homeserver.
=item *
-store($storehash,$symb,$namespace,$udom,$uname) : stores hash permanently
-for this url; hashref needs to be given and should be a \%hashname; the
-remaining args aren't required and if they aren't passed or are '' they will
-be derived from the env
+store($storehash,$symb,$namespace,$udom,$uname,$laststore) : stores hash
+permanently for this url; hashref needs to be given and should be a \%hashname;
+the remaining args aren't required and if they aren't passed or are '' they will
+be derived from the env (with the exception of $laststore, which is an
+optional arg used when a user's submission is stored in grading).
+$laststore is $version=$timestamp, where $version is the most recent version
+number retrieved for the corresponding $symb in the $namespace db file, and
+$timestamp is the timestamp for that transaction (UNIX time).
+$laststore is currently only passed when cstore() is called by
+structuretags::finalize_storage().
=item *
-cstore($storehash,$symb,$namespace,$udom,$uname) : same as store but
-uses critical subroutine
+cstore($storehash,$symb,$namespace,$udom,$uname,$laststore) : same as store
+but uses critical subroutine
=item *
@@ -13257,10 +13481,11 @@ $range should be either an integer '100'
=item *
-putstore($namespace,$symb,$version,$storehash,$udomain,$uname) :
+putstore($namespace,$symb,$version,$storehash,$udomain,$uname,$tolog) :
replaces a &store() version of data with a replacement set of data
for a particular resource in a namespace passed in the $storehash hash
-reference
+reference. If $tolog is true, the transaction is logged in the courselog
+with an action=PUTSTORE.
=item *
@@ -13370,7 +13595,7 @@ server ($udom and $uhome are optional)
=item *
-get_domain_defaults($target_domain,$ignore_cache) : returns hash with defaults
+get_domain_defaults($target_domain,$ignore_cache) : returns hash with defaults
for: authentication, language, quotas, timezone, date locale, and portal URL in
the target domain.
@@ -13414,7 +13639,7 @@ inststatus: types of institutional affil
=over
=item
-inststatustypes, inststatusorder
+inststatustypes, inststatusorder, inststatusguest
=back
@@ -13425,7 +13650,8 @@ for course's uploaded content.
=over
=item
-canuse_pdfforms, officialcredits, unofficialcredits, textbookcredits, officialquota, unofficialquota, communityquota, textbookquota
+canuse_pdfforms, officialcredits, unofficialcredits, textbookcredits, officialquota, unofficialquota,
+communityquota, textbookquota
=back
@@ -13435,7 +13661,7 @@ on your servers.
=over
-=item
+=item
remotesessions, hostedsessions
=back
@@ -13443,10 +13669,10 @@ remotesessions, hostedsessions
=back
In cases where a domain coordinator has never used the "Set Domain Configuration"
-utility to create a configuration.db file on a domain's primary library server
+utility to create a configuration.db file on a domain's primary library server
only the following domain defaults: auth_def, auth_arg_def, lang_def
-- corresponding values are authentication type (internal, krb4, krb5,
-or localauth), initial password or a kerberos realm, language (e.g., en-us) --
+or localauth), initial password or a kerberos realm, language (e.g., en-us) --
will be available. Values are retrieved from cache (if current), unless the
optional $ignore_cache arg is true, or from domain's configuration.db (if available),
or lastly from values in lonTabs/dns_domain,tab, or lonTabs/domain.tab.
@@ -13678,7 +13904,8 @@ filelocation except for hrefs
=item *
-declutter() : declutters URLs (remove docroot, beginning slashes, 'res' etc)
+declutter() : declutters URLs -- remove beginning slashes, 'res' etc.
+also removes beginning /home/httpd/html unless /priv/ follows it.
=back
@@ -13873,8 +14100,8 @@ Returns:
get_timebased_id():
-Attempts to get a unique timestamp-based suffix for use with items added to a
-course via the Course Editor (e.g., folders, composite pages,
+Attempts to get a unique timestamp-based suffix for use with items added to a
+course via the Course Editor (e.g., folders, composite pages,
group bulletin boards).
Args: (first three required; six others optional)
@@ -13885,24 +14112,24 @@ Args: (first three required; six others
2. keyid (alphanumeric): name of temporary locking key in hash,
e.g., num, boardids
-3. namespace: name of gdbm file used to store suffixes already assigned;
+3. namespace: name of gdbm file used to store suffixes already assigned;
file will be named nohist_namespace.db
4. cdom: domain of course; default is current course domain from %env
5. cnum: course number; default is current course number from %env
-6. idtype: set to concat if an additional digit is to be appended to the
+6. idtype: set to concat if an additional digit is to be appended to the
unix timestamp to form the suffix, if the plain timestamp is already
- in use. Default is to not do this, but simply increment the unix
+ in use. Default is to not do this, but simply increment the unix
timestamp by 1 until a unique key is obtained.
7. who: holder of locking key; defaults to user:domain for user.
-8. locktries: number of attempts to obtain a lock (sleep of 1s before
+8. locktries: number of attempts to obtain a lock (sleep of 1s before
retrying); default is 3.
-9. maxtries: number of attempts to obtain a unique suffix; default is 20.
+9. maxtries: number of attempts to obtain a unique suffix; default is 20.
Returns: