--- loncom/lonnet/perl/lonnet.pm 2004/04/01 15:12:26 1.483
+++ loncom/lonnet/perl/lonnet.pm 2004/08/25 16:03:17 1.532
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.483 2004/04/01 15:12:26 albertel Exp $
+# $Id: lonnet.pm,v 1.532 2004/08/25 16:03:17 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -32,12 +32,13 @@ package Apache::lonnet;
use strict;
use LWP::UserAgent();
use HTTP::Headers;
-use Date::Parse;
+use HTTP::Date;
+# use Date::Parse;
use vars
qw(%perlvar %hostname %homecache %badServerCache %hostip %iphost %spareid %hostdom
%libserv %pr %prp %metacache %packagetab %titlecache %courseresversioncache %resversioncache
%courselogs %accesshash %userrolehash $processmarker $dumpcount
- %coursedombuf %coursenumbuf %coursehombuf %coursedescrbuf %courseresdatacache
+ %coursedombuf %coursenumbuf %coursehombuf %coursedescrbuf %courseinstcodebuf %courseresdatacache
%userresdatacache %usectioncache %domaindescription %domain_auth_def %domain_auth_arg_def
%domain_lang_def %domain_city %domain_longi %domain_lati $tmpdir);
@@ -433,7 +434,7 @@ sub overloaderror {
if ($overload>0) {
$r->err_headers_out->{'Retry-After'}=$overload;
$r->log_error('Overload of '.$overload.' on '.$checkserver);
- return 413;
+ return 409;
}
return '';
}
@@ -616,6 +617,7 @@ sub idput {
my ($udom,%ids)=@_;
my %servers=();
foreach (keys %ids) {
+ &cput('environment',{'id'=>$ids{$_}},$udom,$_);
my $uhom=&homeserver($_,$udom);
if ($uhom ne 'no_host') {
my $id=&escape($ids{$_});
@@ -626,7 +628,6 @@ sub idput {
} else {
$servers{$uhom}=$id.'='.$unam;
}
- &critical('put:'.$udom.':'.$unam.':environment:id='.$id,$uhom);
}
}
foreach (keys %servers) {
@@ -641,14 +642,18 @@ sub assign_access_key {
# a valid key looks like uname:udom#comments
# comments are being appended
#
- my ($ckey,$cdom,$cnum,$udom,$uname,$logentry)=@_;
+ my ($ckey,$kdom,$knum,$cdom,$cnum,$udom,$uname,$logentry)=@_;
+ $kdom=
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'} unless (defined($kdom));
+ $knum=
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'} unless (defined($knum));
$cdom=
$ENV{'course.'.$ENV{'request.course.id'}.'.domain'} unless (defined($cdom));
$cnum=
$ENV{'course.'.$ENV{'request.course.id'}.'.num'} unless (defined($cnum));
$udom=$ENV{'user.name'} unless (defined($udom));
$uname=$ENV{'user.domain'} unless (defined($uname));
- my %existing=&get('accesskeys',[$ckey],$cdom,$cnum);
+ my %existing=&get('accesskeys',[$ckey],$kdom,$knum);
if (($existing{$ckey}=~/^\#(.*)$/) || # - new key
($existing{$ckey}=~/^\Q$uname\E\:\Q$udom\E\#(.*)$/)) {
# assigned to this person
@@ -657,8 +662,8 @@ sub assign_access_key {
# the first time around
# ready to assign
$logentry=$1.'; '.$logentry;
- if (&put('accesskey',{$ckey=>$uname.':'.$udom.'#'.$logentry},
- $cdom,$cnum) eq 'ok') {
+ if (&put('accesskeys',{$ckey=>$uname.':'.$udom.'#'.$logentry},
+ $kdom,$knum) eq 'ok') {
# key now belongs to user
my $envkey='key.'.$cdom.'_'.$cnum;
if (&put('environment',{$envkey => $ckey}) eq 'ok') {
@@ -754,8 +759,8 @@ sub validate_access_key {
$ENV{'course.'.$ENV{'request.course.id'}.'.domain'} unless (defined($cdom));
$cnum=
$ENV{'course.'.$ENV{'request.course.id'}.'.num'} unless (defined($cnum));
- $udom=$ENV{'user.name'} unless (defined($udom));
- $uname=$ENV{'user.domain'} unless (defined($uname));
+ $udom=$ENV{'user.domain'} unless (defined($udom));
+ $uname=$ENV{'user.name'} unless (defined($uname));
my %existing=&get('accesskeys',[$ckey],$cdom,$cnum);
return ($existing{$ckey}=~/^\Q$uname\E\:\Q$udom\E\#/);
}
@@ -1042,6 +1047,7 @@ sub currentversion {
sub subscribe {
my $fname=shift;
if ($fname=~/\/(aboutme|syllabus|bulletinboard|smppg)$/) { return ''; }
+ $fname=~s/[\n\r]//g;
my $author=$fname;
$author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;
my ($udom,$uname)=split(/\//,$author);
@@ -1062,6 +1068,7 @@ sub repcopy {
my $filename=shift;
$filename=~s/\/+/\//g;
if ($filename=~/^\/home\/httpd\/html\/adm\//) { return OK; }
+ $filename=~s/[\n\r]//g;
my $transname="$filename.in.transfer";
if ((-e $filename) || (-e $transname)) { return OK; }
my $remoteurl=subscribe($filename);
@@ -1126,10 +1133,10 @@ sub ssi_body {
my ($filelink,%form)=@_;
my $output=($filelink=~/^http\:/?&externalssi($filelink):
&ssi($filelink,%form));
- $output=~s/^.*?\
]*\>//si;
- $output=~s/(.*)\<\/body\s*\>.*?$/$1/si;
$output=~
s/\/\/ BEGIN LON\-CAPA Internal.+\/\/ END LON\-CAPA Internal\s//gs;
+ $output=~s/^.*?\]*\>//si;
+ $output=~s/(.*)\<\/body\s*\>.*?$/$1/si;
return $output;
}
@@ -1164,29 +1171,24 @@ sub externalssi {
return $response->content;
}
-# ------- Add a token to a remote URI's query string to vouch for access rights
+# -------------------------------- Allow a /uploaded/ URI to be vouched for
-sub tokenwrapper {
- my $uri=shift;
- $uri=~s/^http\:\/\/([^\/]+)//;
- $uri=~s/^\///;
- $ENV{'user.environment'}=~/\/([^\/]+)\.id/;
- my $token=$1;
-# if ($uri=~/^uploaded\/([^\/]+)\/([^\/]+)\/([^\/]+)(\?\.*)*$/) {
- if ($uri=~m|^uploaded/([^/]+)/([^/]+)/(.+)(\?\.*)*$|) {
- &appenv('userfile.'.$1.'/'.$2.'/'.$3 => $ENV{'request.course.id'});
- return 'http://'.$hostname{ &homeserver($2,$1)}.'/'.$uri.
- (($uri=~/\?/)?'&':'?').'token='.$token.
- '&tokenissued='.$perlvar{'lonHostID'};
- } else {
- return '/adm/notfound.html';
- }
+sub allowuploaded {
+ my ($srcurl,$url)=@_;
+ $url=&clutter(&declutter($url));
+ my $dir=$url;
+ $dir=~s/\/[^\/]+$//;
+ my %httpref=();
+ my $httpurl=&hreflocation('',$url);
+ $httpref{'httpref.'.$httpurl}=$srcurl;
+ &Apache::lonnet::appenv(%httpref);
}
# --------- File operations in /home/httpd/html/userfiles/$domain/1/2/3/$course
# input: action, courseID, current domain, home server for course, intended
# path to file, source of file.
-# output: ok if successful, diagnostic message otherwise
+# output: url to file (if action was uploaddoc),
+# ok if successful, or diagnostic message otherwise (if action was propagate or copy)
#
# Allows directory structure to be used within lonUsers/../userfiles/ for a
# course.
@@ -1201,8 +1203,9 @@ sub tokenwrapper {
# and will then be copied to
# /home/httpd/lonUsers/$domain/1/2/3/$course/userfiles/$file in
# course's home server.
+#
# action = uploaddoc - /home/httpd/html/userfiles/$domain/1/2/3/$course/$file
-# will be retrived from $ENV{form.$source} via DOCS interface to
+# will be retrived from $ENV{form.uploaddoc} (from DOCS interface) to
# /home/httpd/html/userfiles/$domain/1/2/3/$course/$file
# and will then be copied to /home/httpd/lonUsers/1/2/3/$course/userfiles/$file
# in course's home server.
@@ -1255,7 +1258,7 @@ sub process_coursefile {
}
}
}
- unless ( ($fetchresult eq 'ok') || ($fetchresult eq 'no source file') ) {
+ unless ( $fetchresult eq 'ok') {
&logthis('Failed to transfer '.$docudom.'/'.$docuname.'/'.$file.
' to host '.$docuhome.': '.$fetchresult);
}
@@ -1266,9 +1269,8 @@ sub process_coursefile {
# input: name of form element, coursedoc=1 means this is for the course
# output: url of file in userspace
-sub userfileupload {
- my ($formname,$coursedoc)=@_;
- my $fname=$ENV{'form.'.$formname.'.filename'};
+sub clean_filename {
+ my ($fname)=@_;
# Replace Windows backslashes by forward slashes
$fname=~s/\\/\//g;
# Get rid of everything but the actual filename
@@ -1277,37 +1279,66 @@ sub userfileupload {
$fname=~s/\s+/\_/g;
# Replace all other weird characters by nothing
$fname=~s/[^\w\.\-]//g;
+ return $fname;
+}
+
+sub userfileupload {
+ my ($formname,$coursedoc,$subdir)=@_;
+ if (!defined($subdir)) { $subdir='unknown'; }
+ my $fname=$ENV{'form.'.$formname.'.filename'};
+ $fname=&clean_filename($fname);
# See if there is anything left
unless ($fname) { return 'error: no uploaded file'; }
chop($ENV{'form.'.$formname});
- my $url = '';
+ if (($formname eq 'screenshot') && ($subdir eq 'helprequests')) { #files uploaded to help request form are handled differently
+ my $now = time;
+ my $filepath = 'tmp/helprequests/'.$now;
+ my @parts=split(/\//,$filepath);
+ my $fullpath = $perlvar{'lonDaemons'};
+ for (my $i=0;$i<@parts;$i++) {
+ $fullpath .= '/'.$parts[$i];
+ if ((-e $fullpath)!=1) {
+ mkdir($fullpath,0777);
+ }
+ }
+ open(my $fh,'>'.$fullpath.'/'.$fname);
+ print $fh $ENV{'form.'.$formname};
+ close($fh);
+ return $fullpath.'/'.$fname;
+ }
# Create the directory if not present
my $docuname='';
my $docudom='';
my $docuhome='';
+ $fname="$subdir/$fname";
if ($coursedoc) {
$docuname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
$docudom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
$docuhome=$ENV{'course.'.$ENV{'request.course.id'}.'.home'};
if ($ENV{'form.folder'} =~ m/^default/) {
- $url = &finishuserfileupload($docuname,$docudom,$docuhome,$formname,$fname);
+ return &finishuserfileupload($docuname,$docudom,$docuhome,$formname,$fname);
} else {
$fname=$ENV{'form.folder'}.'/'.$fname;
- $url = &process_coursefile('uploaddoc',$docuname,$docudom,$docuhome,$fname,$formname);
+ return &process_coursefile('uploaddoc',$docuname,$docudom,$docuhome,$fname,$formname);
}
} else {
$docuname=$ENV{'user.name'};
$docudom=$ENV{'user.domain'};
$docuhome=$ENV{'user.home'};
+ return &finishuserfileupload($docuname,$docudom,$docuhome,$formname,$fname);
}
- return
- &finishuserfileupload($docuname,$docudom,$docuhome,$formname,$fname);
}
sub finishuserfileupload {
my ($docuname,$docudom,$docuhome,$formname,$fname)=@_;
my $path=$docudom.'/'.$docuname.'/';
my $filepath=$perlvar{'lonDocRoot'};
+ my ($fnamepath,$file);
+ $file=$fname;
+ if ($fname=~m|/|) {
+ ($fnamepath,$file) = ($fname =~ m|^(.*)/([^/]+)$|);
+ $path.=$fnamepath.'/';
+ }
my @parts=split(/\//,$filepath.'/userfiles/'.$path);
my $count;
for ($count=4;$count<=$#parts;$count++) {
@@ -1318,25 +1349,50 @@ sub finishuserfileupload {
}
# Save the file
{
- open(my $fh,'>'.$filepath.'/'.$fname);
+ #&Apache::lonnet::logthis("Saving to $filepath $file");
+ open(my $fh,'>'.$filepath.'/'.$file);
print $fh $ENV{'form.'.$formname};
close($fh);
}
# Notify homeserver to grep it
#
- my $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$fname,
- $docuhome);
+ my $fetchresult= &reply('fetchuserfile:'.$path.$file,$docuhome);
if ($fetchresult eq 'ok') {
#
# Return the URL to it
- return '/uploaded/'.$path.$fname;
+ return '/uploaded/'.$path.$file;
} else {
- &logthis('Failed to transfer '.$docudom.'/'.$docuname.'/'.$fname.
- ' to host '.$docuhome.': '.$fetchresult);
+ &logthis('Failed to transfer '.$path.$file.' to host '.$docuhome.
+ ': '.$fetchresult);
return '/adm/notfound.html';
}
}
+sub removeuploadedurl {
+ my ($url)=@_;
+ my (undef,undef,$udom,$uname,$fname)=split('/',$url,5);
+ return &Apache::lonnet::removeuserfile($uname,$udom,$fname);
+}
+
+sub removeuserfile {
+ my ($docuname,$docudom,$fname)=@_;
+ my $home=&homeserver($docuname,$docudom);
+ return &reply("removeuserfile:$docudom/$docuname/$fname",$home);
+}
+
+sub mkdiruserfile {
+ my ($docuname,$docudom,$dir)=@_;
+ my $home=&homeserver($docuname,$docudom);
+ return &reply("mkdiruserfile:".&escape("$docudom/$docuname/$dir"),$home);
+}
+
+sub renameuserfile {
+ my ($docuname,$docudom,$old,$new)=@_;
+ my $home=&homeserver($docuname,$docudom);
+ return &reply("renameuserfile:$docudom:$docuname:".&escape("$old").':'.
+ &escape("$new"),$home);
+}
+
# ------------------------------------------------------------------------- Log
sub log {
@@ -1376,10 +1432,12 @@ sub flushcourselogs {
}
if ($courseidbuffer{$coursehombuf{$crsid}}) {
$courseidbuffer{$coursehombuf{$crsid}}.='&'.
- &escape($crsid).'='.&escape($coursedescrbuf{$crsid});
+ &escape($crsid).'='.&escape($coursedescrbuf{$crsid}).
+ '='.&escape($courseinstcodebuf{$crsid});
} else {
$courseidbuffer{$coursehombuf{$crsid}}=
- &escape($crsid).'='.&escape($coursedescrbuf{$crsid});
+ &escape($crsid).'='.&escape($coursedescrbuf{$crsid}).
+ '='.&escape($courseinstcodebuf{$crsid});
}
}
#
@@ -1453,6 +1511,8 @@ sub courselog {
$ENV{'course.'.$ENV{'request.course.id'}.'.home'};
$coursedescrbuf{$ENV{'request.course.id'}}=
$ENV{'course.'.$ENV{'request.course.id'}.'.description'};
+ $courseinstcodebuf{$ENV{'request.course.id'}}=
+ $ENV{'course.'.$ENV{'request.course.id'}.'.internal.coursecode'};
if (defined $courselogs{$ENV{'request.course.id'}}) {
$courselogs{$ENV{'request.course.id'}}.='&'.$what;
} else {
@@ -1577,7 +1637,7 @@ sub getannounce {
if ($announcement=~/\w/) {
return
'';
+ ''.$announcement.' |
';
} else {
return '';
}
@@ -1596,21 +1656,22 @@ sub courseidput {
}
sub courseiddump {
- my ($domfilter,$descfilter,$sincefilter)=@_;
+ my ($domfilter,$descfilter,$sincefilter,$hostidflag,$hostidref)=@_;
my %returnhash=();
unless ($domfilter) { $domfilter=''; }
foreach my $tryserver (keys %libserv) {
- if ((!$domfilter) || ($hostdom{$tryserver} eq $domfilter)) {
- foreach (
- split(/\&/,&reply('courseiddump:'.$hostdom{$tryserver}.':'.
+ if ( ($hostidflag == 1 && grep/^$tryserver$/,@{$hostidref}) || (!defined($hostidflag)) ) {
+ if ((!$domfilter) || ($hostdom{$tryserver} eq $domfilter)) {
+ foreach (
+ split(/\&/,&reply('courseiddump:'.$hostdom{$tryserver}.':'.
$sincefilter.':'.&escape($descfilter),
$tryserver))) {
- my ($key,$value)=split(/\=/,$_);
- if (($key) && ($value)) {
- $returnhash{&unescape($key)}=&unescape($value);
+ my ($key,$value)=split(/\=/,$_);
+ if (($key) && ($value)) {
+ $returnhash{&unescape($key)}=$value;
+ }
}
}
-
}
}
return %returnhash;
@@ -1619,6 +1680,28 @@ sub courseiddump {
#
# ----------------------------------------------------------- Check out an item
+sub get_first_access {
+ my ($type,$argsymb)=@_;
+ my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser();
+ if ($argsymb) { $symb=$argsymb; }
+ my ($map,$id,$res)=&decode_symb($symb);
+ if ($type eq 'map') { $res=$map; }
+ my %times=&get('firstaccesstimes',[$res],$udom,$uname);
+ return $times{$res};
+}
+
+sub set_first_access {
+ my ($type)=@_;
+ my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser();
+ my ($map,$id,$res)=&decode_symb($symb);
+ if ($type eq 'map') { $res=$map; }
+ my $firstaccess=&get_first_access($type);
+ if (!$firstaccess) {
+ return &put('firstaccesstimes',{$res=>time},$udom,$uname);
+ }
+ return 'already_set';
+}
+
sub checkout {
my ($symb,$tuname,$tudom,$tcrsid)=@_;
my $now=time;
@@ -1797,7 +1880,7 @@ sub hash2str {
sub hashref2str {
my ($hashref)=@_;
my $result='__HASH_REF__';
- foreach (keys(%$hashref)) {
+ foreach (sort(keys(%$hashref))) {
if (ref($_) eq 'ARRAY') {
$result.=&arrayref2str($_).'=';
} elsif (ref($_) eq 'HASH') {
@@ -2529,6 +2612,30 @@ sub put {
return &reply("put:$udomain:$uname:$namespace:$items",$uhome);
}
+# ---------------------------------------------------------- putstore interface
+
+sub putstore {
+ my ($namespace,$storehash,$udomain,$uname)=@_;
+ if (!$udomain) { $udomain=$ENV{'user.domain'}; }
+ if (!$uname) { $uname=$ENV{'user.name'}; }
+ my $uhome=&homeserver($uname,$udomain);
+ my $items='';
+ my %allitems = ();
+ foreach (keys %$storehash) {
+ if ($_ =~ m/^([^\:]+):([^\:]+):([^\:]+)$/) {
+ my $key = $1.':keys:'.$2;
+ $allitems{$key} .= $3.':';
+ }
+ $items.=$_.'='.&escape($$storehash{$_}).'&';
+ }
+ foreach (keys %allitems) {
+ $allitems{$_} =~ s/\:$//;
+ $items.= $_.'='.$allitems{$_}.'&';
+ }
+ $items=~s/\&$//;
+ return &reply("put:$udomain:$uname:$namespace:$items",$uhome);
+}
+
# ------------------------------------------------------ critical put interface
sub cput {
@@ -2611,8 +2718,8 @@ sub allowed {
if (defined($ENV{'allowed.'.$priv})) { return $ENV{'allowed.'.$priv}; }
# Free bre access to adm and meta resources
-
- if ((($uri=~/^adm\//) || ($uri=~/\.meta$/)) && ($priv eq 'bre')) {
+ if (((($uri=~/^adm\//) && ($uri !~ m|/bulletinboard$|))
+ || ($uri=~/\.meta$/)) && ($priv eq 'bre')) {
return 'F';
}
@@ -2681,10 +2788,15 @@ sub allowed {
# URI is an uploaded document for this course
- if (($priv eq 'bre') &&
- ($uri=~/^uploaded\/$ENV{'course.'.$ENV{'request.course.id'}.'.domain'}\/$ENV{'course.'.$ENV{'request.course.id'}.'.num'}/)) {
- return 'F';
+ if (($priv eq 'bre') && ($uri=~m|^uploaded/|)) {
+ my $refuri=$ENV{'httpref.'.$orguri};
+ if ($refuri) {
+ if ($refuri =~ m|^/adm/|) {
+ $thisallowed='F';
+ }
+ }
}
+
# Full access at system, domain or course-wide level? Exit.
if ($thisallowed=~/F/) {
@@ -3007,6 +3119,68 @@ sub log_query {
return get_query_reply($queryid);
}
+# ------- Request retrieval of institutional classlists for course(s)
+
+sub fetch_enrollment_query {
+ my ($context,$affiliatesref,$replyref,$dom,$cnum) = @_;
+ my $homeserver;
+ if ($context eq 'automated') {
+ $homeserver = $perlvar{'lonHostID'};
+ } else {
+ $homeserver = &homeserver($cnum,$dom);
+ }
+ my $host=$hostname{$homeserver};
+ my $cmd = '';
+ foreach (keys %{$affiliatesref}) {
+ $cmd .= $_.'='.join(",",@{$$affiliatesref{$_}}).'%%';
+ }
+ $cmd =~ s/%%$//;
+ $cmd = &escape($cmd);
+ my $query = 'fetchenrollment';
+ my $queryid=&reply("querysend:".$query.':'.$dom.':'.$ENV{'user.name'}.':'.$cmd,$homeserver);
+ unless ($queryid=~/^\Q$host\E\_/) {
+ &logthis('fetch_enrollment_query: invalid queryid: '.$queryid.' for host: '.$host.' and homeserver: '.$homeserver.' context: '.$context.' '.$cnum);
+ return 'error: '.$queryid;
+ }
+ my $reply = &get_query_reply($queryid);
+ if ( ($reply =~/^timeout/) || ($reply =~/^error/) ) {
+ &logthis('fetch_enrollment_query error: '.$reply.' for '.$dom.' '.$ENV{'user.name'}.' for '.$queryid.' context: '.$context.' '.$cnum);
+ } else {
+ my @responses = split/:/,$reply;
+ if ($homeserver eq $perlvar{'lonHostID'}) {
+ foreach (@responses) {
+ my ($key,$value) = split/=/,$_;
+ $$replyref{$key} = $value;
+ }
+ } else {
+ my $pathname = $perlvar{'lonDaemons'}.'/tmp';
+ foreach (@responses) {
+ my ($key,$value) = split/=/,$_;
+ $$replyref{$key} = $value;
+ if ($value > 0) {
+ foreach (@{$$affiliatesref{$key}}) {
+ my $filename = $dom.'_'.$key.'_'.$_.'_classlist.xml';
+ my $destname = $pathname.'/'.$filename;
+ my $xml_classlist = &reply("autoretrieve:".$filename,$homeserver);
+ if ($xml_classlist =~ /^error/) {
+ &logthis('fetch_enrollment_query - autoretrieve error: '.$xml_classlist.' for '.$filename.' from server: '.$homeserver.' '.$context.' '.$cnum);
+ } else {
+ if ( open(FILE,">$destname") ) {
+ print FILE &unescape($xml_classlist);
+ close(FILE);
+ } else {
+ &logthis('fetch_enrollment_query - error opening classlist file '.$destname.' '.$context.' '.$cnum);
+ }
+ }
+ }
+ }
+ }
+ }
+ return 'ok';
+ }
+ return 'error';
+}
+
sub get_query_reply {
my $queryid=shift;
my $replyfile=$perlvar{'lonDaemons'}.'/tmp/'.$queryid;
@@ -3051,6 +3225,80 @@ sub userlog_query {
return &log_query($uname,$udom,'userlog',%filters);
}
+#--------- Call auto-enrollment subs in localenroll.pm for homeserver for course
+
+sub auto_run {
+ my ($cnum,$cdom) = @_;
+ my $homeserver = &homeserver($cnum,$cdom);
+ my $response = &reply('autorun:'.$cdom,$homeserver);
+ return $response;
+}
+
+sub auto_get_sections {
+ my ($cnum,$cdom,$inst_coursecode) = @_;
+ my $homeserver = &homeserver($cnum,$cdom);
+ my @secs = ();
+ my $response=&unescape(&reply('autogetsections:'.$inst_coursecode.':'.$cdom,$homeserver));
+ unless ($response eq 'refused') {
+ @secs = split/:/,$response;
+ }
+ return @secs;
+}
+
+sub auto_new_course {
+ my ($cnum,$cdom,$inst_course_id,$owner) = @_;
+ my $homeserver = &homeserver($cnum,$cdom);
+ my $response=&unescape(&reply('autonewcourse:'.$inst_course_id.':'.$owner.':'.$cdom,$homeserver));
+ return $response;
+}
+
+sub auto_validate_courseID {
+ my ($cnum,$cdom,$inst_course_id) = @_;
+ my $homeserver = &homeserver($cnum,$cdom);
+ my $response=&unescape(&reply('autovalidatecourse:'.$inst_course_id.':'.$cdom,$homeserver));
+ return $response;
+}
+
+sub auto_create_password {
+ my ($cnum,$cdom,$authparam) = @_;
+ my $homeserver = &homeserver($cnum,$cdom);
+ my $create_passwd = 0;
+ my $authchk = '';
+ my $response=&unescape(&reply('autocreatepassword:'.$authparam.':'.$cdom,$homeserver));
+ if ($response eq 'refused') {
+ $authchk = 'refused';
+ } else {
+ ($authparam,$create_passwd,$authchk) = split/:/,$response;
+ }
+ return ($authparam,$create_passwd,$authchk);
+}
+
+sub auto_instcode_format {
+ my ($caller,$codedom,$instcodes,$codes,$codetitles,$cat_titles,$cat_order) = @_;
+ my $courses = '';
+ my $homeserver;
+ if ($caller eq 'global') {
+ $homeserver = $perlvar{'lonHostID'};
+ } else {
+ $homeserver = &homeserver($caller,$codedom);
+ }
+ my $host=$hostname{$homeserver};
+ foreach (keys %{$instcodes}) {
+ $courses .= &escape($_).'='.&escape($$instcodes{$_}).'&';
+ }
+ chop($courses);
+ my $response=&reply('autoinstcodeformat:'.$codedom.':'.$courses,$homeserver);
+ unless ($response =~ /(con_lost|error|no_such_host|refused)/) {
+ my ($codes_str,$codetitles_str,$cat_titles_str,$cat_order_str) = split/:/,$response;
+ %{$codes} = &str2hash($codes_str);
+ @{$codetitles} = &str2array($codetitles_str);
+ %{$cat_titles} = &str2hash($cat_titles_str);
+ %{$cat_order} = &str2hash($cat_order_str);
+ return 'ok';
+ }
+ return $response;
+}
+
# ------------------------------------------------------------------ Plain Text
sub plaintext {
@@ -3241,7 +3489,7 @@ sub modifyuser {
sub modifystudent {
my ($udom,$uname,$uid,$umode,$upass,$first,$middle,$last,$gene,$usec,
- $end,$start,$forceid,$desiredhome,$email,$type,$cid)=@_;
+ $end,$start,$forceid,$desiredhome,$email,$type,$locktype,$cid)=@_;
if (!$cid) {
unless ($cid=$ENV{'request.course.id'}) {
return 'not_in_class';
@@ -3256,13 +3504,12 @@ sub modifystudent {
# students environment
$uid = undef if (!$forceid);
$reply = &modify_student_enrollment($udom,$uname,$uid,$first,$middle,$last,
- $gene,$usec,$end,$start,$type,$cid);
+ $gene,$usec,$end,$start,$type,$locktype,$cid);
return $reply;
}
sub modify_student_enrollment {
- my ($udom,$uname,$uid,$first,$middle,$last,$gene,$usec,$end,$start,$type,
- $cid) = @_;
+ my ($udom,$uname,$uid,$first,$middle,$last,$gene,$usec,$end,$start,$type,$locktype,$cid) = @_;
my ($cdom,$cnum,$chome);
if (!$cid) {
unless ($cid=$ENV{'request.course.id'}) {
@@ -3306,9 +3553,10 @@ sub modify_student_enrollment {
}
my $fullname = &Apache::loncoursedata::ProcessFullName($last,$gene,
$first,$middle);
- my $value=&escape($uname.':'.$udom).'='.
- &escape(join(':',$end,$start,$uid,$usec,$fullname,$type));
- my $reply=critical('put:'.$cdom.':'.$cnum.':classlist:'.$value,$chome);
+ my $reply=cput('classlist',
+ {"$uname:$udom" =>
+ join(':',$end,$start,$uid,$usec,$fullname,$type,$locktype) },
+ $cdom,$cnum);
unless (($reply eq 'ok') || ($reply eq 'delayed')) {
return 'error: '.$reply;
}
@@ -3343,7 +3591,7 @@ sub writecoursepref {
# ---------------------------------------------------------- Make/modify course
sub createcourse {
- my ($udom,$description,$url,$course_server,$nonstandard)=@_;
+ my ($udom,$description,$url,$course_server,$nonstandard,$inst_code)=@_;
$url=&declutter($url);
my $cid='';
unless (&allowed('ccc',$udom)) {
@@ -3376,9 +3624,9 @@ sub createcourse {
return 'error: no such course';
}
# ----------------------------------------------------------------- Course made
-# log existance
- &courseidput($udom,&escape($udom.'_'.$uname).'='.&escape($description),
- $uhome);
+# log existence
+ &courseidput($udom,&escape($udom.'_'.$uname).'='.&escape($description).
+ '='.&escape($inst_code),$uhome);
&flushcourselogs();
# set toplevel url
my $topurl=$url;
@@ -3431,6 +3679,42 @@ sub revokecustomrole {
$deleteflag);
}
+
+# ------------------------------------------------------------ Portfolio Director Lister
+# returns listing of contents of user's /userfiles/portfolio/ directory
+#
+
+sub portfoliolist {
+ my ($currentPath, $currentFile) = @_;
+ my ($udom, $uname, $portfolioRoot);
+ $uname=$ENV{'user.name'};
+ $udom=$ENV{'user.domain'};
+ # really should interrogate the system for home directory information, but . . .
+ $portfolioRoot = '/home/httpd/lonUsers/'.$udom.'/';
+ $uname =~ /^(.?)(.?)(.?)/;
+ $portfolioRoot = $portfolioRoot.$1.'/'.$2.'/'.$3.'/'.$uname.'/userfiles/portfolio';
+ my $listing = &reply('ls:'.$portfolioRoot.$currentPath, &homeserver($uname,$udom));
+ return $listing;
+}
+
+sub portfoliomanage {
+
+#FIXME please user the existing remove userfile function instead and
+#add a userfilerename functions.
+#FIXME uhome should never be an argument to any lonnet functions
+
+ # handles deleting and renaming files in user's userfiles/portfolio/ directory
+ #
+ my ($filename, $fileaction, $filenewname) = @_;
+ my ($udom, $uname, $uhome);
+ $uname=$ENV{'user.name'};
+ $udom=$ENV{'user.domain'};
+ $uhome=$ENV{'user.home'};
+ my $listing = reply('portfoliomanage:'.$uname.':'.$udom.':'.$filename.':'.$fileaction.':'.$filenewname, $uhome);
+ return $listing;
+}
+
+
# ------------------------------------------------------------ Directory lister
sub dirlist {
@@ -3934,9 +4218,11 @@ sub metadata {
my ($uri,$what,$liburi,$prefix,$depthcount)=@_;
$uri=&declutter($uri);
# if it is a non metadata possible uri return quickly
- if (($uri eq '') || (($uri =~ m|^/*adm/|) && ($uri !~ m|^adm/includes|)) ||
+ if (($uri eq '') ||
+ (($uri =~ m|^/*adm/|) &&
+ ($uri !~ m|^adm/includes|) && ($uri !~ m|/bulletinboard$|)) ||
($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ /^~/) ||
- ($uri =~ m|home/[^/]+/public_html/|) || ($uri =~ m|^uploaded/|)) {
+ ($uri =~ m|home/[^/]+/public_html/|)) {
return undef;
}
my $filename=$uri;
@@ -3965,7 +4251,10 @@ sub metadata {
}
my %metathesekeys=();
unless ($filename=~/\.meta$/) { $filename.='.meta'; }
- my $metastring=&getfile(&filelocation('',&clutter($filename)));
+ my $metastring;
+ if ($uri !~ m|^uploaded/|) {
+ $metastring=&getfile(&filelocation('',&clutter($filename)));
+ }
my $parser=HTML::LCParser->new(\$metastring);
my $token;
undef %metathesekeys;
@@ -4081,14 +4370,14 @@ sub metadata {
#&logthis("extsion1 $extension $key !!");
#no specific packages #how's our extension
if ($key!~/^extension_\Q$extension\E&/) { next; }
- &metadata_create_pacakge_def($uri,$key,'extension_'.$extension,
+ &metadata_create_package_def($uri,$key,'extension_'.$extension,
\%metathesekeys);
}
if (!exists($metacache{$uri}->{':packages'})) {
foreach my $key (sort(keys(%packagetab))) {
#no specific packages well let's get default then
if ($key!~/^default&/) { next; }
- &metadata_create_pacakge_def($uri,$key,'default',
+ &metadata_create_package_def($uri,$key,'default',
\%metathesekeys);
}
}
@@ -4120,7 +4409,7 @@ sub metadata {
return $metacache{$uri}->{':'.$what};
}
-sub metadata_create_pacakge_def {
+sub metadata_create_package_def {
my ($uri,$key,$package,$metathesekeys)=@_;
my ($pack,$name,$subp)=split(/\&/,$key);
if ($subp eq 'default') { next; }
@@ -4223,7 +4512,10 @@ sub symblist {
# --------------------------------------------------------------- Verify a symb
sub symbverify {
- my ($symb,$thisfn)=@_;
+ my ($symb,$thisurl)=@_;
+ my $thisfn=$thisurl;
+# wrapper not part of symbs
+ $thisfn=~s/^\/adm\/wrapper//;
$thisfn=&declutter($thisfn);
# direct jump to resource in page or to a sequence - will construct own symbs
if ($thisfn=~/\.(page|sequence)$/) { return 1; }
@@ -4233,6 +4525,7 @@ sub symbverify {
unless ($url eq $thisfn) { return 0; }
$symb=&symbclean($symb);
+ $thisurl=&deversion($thisurl);
$thisfn=&deversion($thisfn);
my %bighash;
@@ -4240,9 +4533,9 @@ sub symbverify {
if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',
&GDBM_READER(),0640)) {
- my $ids=$bighash{'ids_'.&clutter($thisfn)};
+ my $ids=$bighash{'ids_'.&clutter($thisurl)};
unless ($ids) {
- $ids=$bighash{'ids_/'.$thisfn};
+ $ids=$bighash{'ids_/'.$thisurl};
}
if ($ids) {
# ------------------------------------------------------------------- Has ID(s)
@@ -4271,6 +4564,9 @@ sub symbclean {
# remove version from URL
$symb=~s/\.(\d+)\.(\w+)$/\.$2/;
+# remove wrapper
+
+ $symb=~s/(\_\_\_\d+\_\_\_)adm\/wrapper\/(res\/)*/$1/;
return $symb;
}
@@ -4418,8 +4714,41 @@ sub numval {
return int($txt);
}
+sub numval2 {
+ my $txt=shift;
+ $txt=~tr/A-J/0-9/;
+ $txt=~tr/a-j/0-9/;
+ $txt=~tr/K-T/0-9/;
+ $txt=~tr/k-t/0-9/;
+ $txt=~tr/U-Z/0-5/;
+ $txt=~tr/u-z/0-5/;
+ $txt=~s/\D//g;
+ my @txts=split(/(\d\d\d\d\d\d\d\d\d)/,$txt);
+ my $total;
+ foreach my $val (@txts) { $total+=$val; }
+ return int($total);
+}
+
sub latest_rnd_algorithm_id {
- return '64bit2';
+ return '64bit3';
+}
+
+sub get_rand_alg {
+ my ($courseid)=@_;
+ if (!$courseid) { $courseid=(&Apache::lonxml::whichuser())[1]; }
+ if ($courseid) {
+ return $ENV{"course.$courseid.rndseed"};
+ }
+ return &latest_rnd_algorithm_id();
+}
+
+sub getCODE {
+ if (defined($ENV{'form.CODE'})) { return $ENV{'form.CODE'}; }
+ if (defined($Apache::lonhomework::parsing_a_problem) &&
+ defined($Apache::lonhomework::history{'resource.CODE'})) {
+ return $Apache::lonhomework::history{'resource.CODE'};
+ }
+ return undef;
}
sub rndseed {
@@ -4432,10 +4761,11 @@ sub rndseed {
if (!$courseid) { $courseid=$wcourseid; }
if (!$domain) { $domain=$wdomain; }
if (!$username) { $username=$wusername }
- my $which=$ENV{"course.$courseid.rndseed"};
- my $CODE=$ENV{'scantron.CODE'};
- if (defined($CODE)) {
- &rndseed_CODE_64bit($symb,$courseid,$domain,$username);
+ my $which=&get_rand_alg();
+ if (defined(&getCODE())) {
+ return &rndseed_CODE_64bit($symb,$courseid,$domain,$username);
+ } elsif ($which eq '64bit3') {
+ return &rndseed_64bit3($symb,$courseid,$domain,$username);
} elsif ($which eq '64bit2') {
return &rndseed_64bit2($symb,$courseid,$domain,$username);
} elsif ($which eq '64bit') {
@@ -4503,26 +4833,49 @@ sub rndseed_64bit2 {
}
}
+sub rndseed_64bit3 {
+ my ($symb,$courseid,$domain,$username)=@_;
+ {
+ use integer;
+ # strings need to be an even # of cahracters long, it it is odd the
+ # last characters gets thrown away
+ my $symbchck=unpack("%32S*",$symb.' ') << 21;
+ my $symbseed=numval2($symb) << 10;
+ my $namechck=unpack("%32S*",$username.' ');
+
+ my $nameseed=numval2($username) << 21;
+ my $domainseed=unpack("%32S*",$domain.' ') << 10;
+ my $courseseed=unpack("%32S*",$courseid.' ');
+
+ my $num1=$symbchck+$symbseed+$namechck;
+ my $num2=$nameseed+$domainseed+$courseseed;
+ #&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
+ #&Apache::lonxml::debug("rndseed :$num:$symb");
+ return "$num1:$num2";
+ }
+}
+
sub rndseed_CODE_64bit {
my ($symb,$courseid,$domain,$username)=@_;
{
use integer;
my $symbchck=unpack("%32S*",$symb.' ') << 16;
- my $symbseed=numval($symb);
- my $CODEseed=numval($ENV{'scantron.CODE'}) << 16;
+ my $symbseed=numval2($symb);
+ my $CODEchck=unpack("%32S*",&getCODE().' ') << 16;
+ my $CODEseed=numval(&getCODE());
my $courseseed=unpack("%32S*",$courseid.' ');
- my $num1=$symbseed+$CODEseed;
- my $num2=$courseseed+$symbchck;
- #&Apache::lonxml::debug("$symbseed:$CODEseed|$courseseed:$symbchck");
+ my $num1=$symbseed+$CODEchck;
+ my $num2=$CODEseed+$courseseed+$symbchck;
+ #&Apache::lonxml::debug("$symbseed:$CODEchck|$CODEseed:$courseseed:$symbchck");
#&Apache::lonxml::debug("rndseed :$num1:$num2:$symb");
- return "$num1,$num2";
+ return "$num1:$num2";
}
}
sub setup_random_from_rndseed {
my ($rndseed)=@_;
- if ($rndseed =~/,/) {
- my ($num1,$num2)=split(/,/,$rndseed);
+ if ($rndseed =~/([,:])/) {
+ my ($num1,$num2)=split(/[,:]/,$rndseed);
&Math::Random::random_set_seed(abs($num1),abs($num2));
} else {
&Math::Random::random_set_seed_from_phrase($rndseed);
@@ -4627,6 +4980,14 @@ sub getfile {
if ($rtncode eq '404') {
unlink($localfile);
}
+ #my $ua=new LWP::UserAgent;
+ #my $request=new HTTP::Request('GET',&tokenwrapper($file));
+ #my $response=$ua->request($request);
+ #if ($response->is_success()) {
+ # return $response->content;
+ # } else {
+ # return -1;
+ # }
return -1;
}
if ($info < $fileinfo[9]) {
@@ -4640,12 +5001,19 @@ sub getfile {
} else {
$lwpresp = &getuploaded('GET',$file,$cdom,$cnum,\$info,\$rtncode);
if ($lwpresp ne 'ok') {
- return -1;
+ my $ua=new LWP::UserAgent;
+ my $request=new HTTP::Request('GET',&tokenwrapper($file));
+ my $response=$ua->request($request);
+ if ($response->is_success()) {
+ return $response->content;
+ } else {
+ return -1;
+ }
}
my @parts = ($cdom,$cnum);
if ($filename =~ m|^(.+)/[^/]+$|) {
push @parts, split(/\//,$1);
- }
+ }
foreach my $part (@parts) {
$path .= '/'.$part;
if (!-e $path) {
@@ -4662,6 +5030,22 @@ sub getfile {
return $info;
}
+sub tokenwrapper {
+ my $uri=shift;
+ $uri=~s/^http\:\/\/([^\/]+)//;
+ $uri=~s/^\///;
+ $ENV{'user.environment'}=~/\/([^\/]+)\.id/;
+ my $token=$1;
+ if ($uri=~/^uploaded\/([^\/]+)\/([^\/]+)\/([^\/]+)(\?\.*)*$/) {
+ &appenv('userfile.'.$1.'/'.$2.'/'.$3 => $ENV{'request.course.id'});
+ return 'http://'.$hostname{ &homeserver($2,$1)}.'/'.$uri.
+ (($uri=~/\?/)?'&':'?').'token='.$token.
+ '&tokenissued='.$perlvar{'lonHostID'};
+ } else {
+ return '/adm/notfound.html';
+ }
+}
+
sub getuploaded {
my ($reqtype,$uri,$cdom,$cnum,$info,$rtncode) = @_;
$uri=~s/^\///;
@@ -4674,7 +5058,7 @@ sub getuploaded {
return 'failed';
}
if ($reqtype eq 'HEAD') {
- $$info = &Date::Parse::str2time( $response->header('Last-modified') );
+ $$info = &HTTP::Date::str2time( $response->header('Last-modified') );
} elsif ($reqtype eq 'GET') {
$$info = $response->content;
}
@@ -4699,7 +5083,21 @@ sub filelocation {
$location = $file;
$location =~ s:/~(.*?)/(.*):/home/$1/public_html/$2:;
} elsif ($file=~/^\/*uploaded/) { # is an uploaded file
- $location=$file;
+ if ($file=~/^\/uploaded\/([^\/]+)\/([^\/]+)\/(\/)?simplepage\/([^\/]+)$/) {
+ $location=&Apache::loncommon::propath($1,$2).'/userfiles/simplepage/'.$4;
+ if (not -e $location) {
+ $file=~/^\/uploaded\/(.*)$/;
+ $location=$Apache::lonnet::perlvar{'lonDocRoot'}.'/userfiles/'.$1;
+ }
+ } elsif ($file=~/^\/uploaded\/([^\/]+)\/([^\/]+)\/aboutme\/([^\/]+)$/) {
+ $location=&Apache::loncommon::propath($1,$2).'/userfiles/aboutme/'.$3;
+ if (not -e $location) {
+ $file=~/^\/uploaded\/(.*)$/;
+ $location=$Apache::lonnet::perlvar{'lonDocRoot'}.'/userfiles/'.$1;
+ }
+ } else {
+ $location=$file;
+ }
} else {
$file=~s/^\Q$perlvar{'lonDocRoot'}\E//;
$file=~s:^/res/:/:;
@@ -4769,7 +5167,7 @@ sub declutter {
sub clutter {
my $thisfn='/'.&declutter(shift);
- unless ($thisfn=~/^\/(uploaded|adm|userfiles|ext|raw|priv)\//) {
+ unless ($thisfn=~/^\/(uploaded|adm|userfiles|ext|raw|priv|public)\//) {
$thisfn='/res'.$thisfn;
}
return $thisfn;
@@ -4831,7 +5229,7 @@ BEGIN {
open(my $config,") {
- if ($configline =~ /^[^\#]*PerlSetVar/) {
+ if ($configline=~/\S/ && $configline =~ /^[^\#]*PerlSetVar/) {
my ($dummy,$varname,$varvalue)=split(/\s+/,$configline);
chomp($varvalue);
$perlvar{$varname}=$varvalue;
@@ -5590,6 +5988,17 @@ put($namespace,$storehash,$udom,$uname)
=item *
+putstore($namespace,$storehash,$udomain,$uname) : stores hash in namesp
+keys used in storehash include version information (e.g., 1:$symb:message etc.) as
+used in records written by &store and retrieved by &restore. This function
+was created for use in editing discussion posts, without incrementing the
+version number included in the key for a particular post. The colon
+separated list of attribute names (e.g., the value associated with the key
+1:keys:$symb) is also generated and passed in the ampersand separated
+items sent to lonnet::reply().
+
+=item *
+
cput($namespace,$storehash,$udom,$uname) : critical put
($udom and $uname are optional)