--- loncom/lonnet/perl/lonnet.pm 2010/11/11 21:03:30 1.1056.2.11 +++ loncom/lonnet/perl/lonnet.pm 2010/06/04 00:14:15 1.1070 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1056.2.11 2010/11/11 21:03:30 raeburn Exp $ +# $Id: lonnet.pm,v 1.1070 2010/06/04 00:14:15 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -665,30 +665,6 @@ 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 { @@ -1577,8 +1553,7 @@ sub getsection { # If there is a role which has expired, return it. # $courseid = &courseid_to_courseurl($courseid); - my $extra = &freeze_escape({'skipcheck' => 1}); - my %roleshash = &dump('roles',$udom,$unam,$courseid,undef,$extra); + my %roleshash = &dump('roles',$udom,$unam,$courseid); foreach my $key (keys(%roleshash)) { next if ($key !~/^\Q$courseid\E(?:\/)*(\w+)*\_st$/); my $section=$1; @@ -2195,7 +2170,7 @@ sub resizeImage { # --------------- Take an uploaded file and put it into the userfiles directory # input: $formname - the contents of the file are in $env{"form.$formname"} -# the desired filename is in $env{"form.$formname.filename"} +# the desired filenam is in $env{"form.$formname.filename"} # $coursedoc - if true up to the current course # if false # $subdir - directory in userfile to store the file into @@ -2254,7 +2229,7 @@ sub userfileupload { } if ($subdir eq 'scantron') { $fname = 'scantron_orig_'.$fname; - } else { + } else { # Create the directory if not present $fname="$subdir/$fname"; } @@ -2880,9 +2855,8 @@ 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') { - my $extra = &freeze_escape({'skipcheck' => 1}); - %dumphash = &dump('roles',$udom,$uname,'.',undef,$extra); + if ($context eq 'userroles') { + %dumphash = &dump('roles',$udom,$uname); } else { %dumphash= &dump('nohist_userroles',$udom,$uname); @@ -3061,7 +3035,7 @@ sub courseiddump { my ($domfilter,$descfilter,$sincefilter,$instcodefilter,$ownerfilter, $coursefilter,$hostidflag,$hostidref,$typefilter,$regexp_ok, $selfenrollonly,$catfilter,$showhidden,$caller,$cloner,$cc_clone, - $cloneonly,$createdbefore,$createdafter,$creationcontext,$domcloner)=@_; + $cloneonly,$createdbefore,$createdafter,$creationcontext)=@_; my $as_hash = 1; my %returnhash; if (!$domfilter) { $domfilter=''; } @@ -3083,8 +3057,7 @@ sub courseiddump { $showhidden.':'.$caller.':'.&escape($cloner).':'. &escape($cc_clone).':'.$cloneonly.':'. &escape($createdbefore).':'.&escape($createdafter).':'. - &escape($creationcontext).':'.$domcloner, - $tryserver); + &escape($creationcontext),$tryserver); my @pairs=split(/\&/,$rep); foreach my $item (@pairs) { my ($key,$value)=split(/\=/,$item,2); @@ -3210,7 +3183,7 @@ sub get_domain_roles { return %personnel; } -# ----------------------------------------------------------- Check out an item +# ----------------------------------------------------------- Interval timing sub get_first_access { my ($type,$argsymb)=@_; @@ -3246,91 +3219,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 { @@ -4036,7 +3924,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); } @@ -4059,7 +3947,7 @@ sub set_userprivs { foreach my $group (keys(%{$$allgroups{$area}})) { my $spec = $trole.'.'.$extendedarea; $grouproles{$spec.'.'.$area.'/'.$group} = - $$allgroups{$area}{$group}; + $$allgroups{$area}{$group}; } } } @@ -4112,7 +4000,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\//) { @@ -4129,7 +4017,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; @@ -4177,22 +4065,22 @@ sub role_status { } sub check_adhoc_privs { - my ($cdom,$cnum,$then,$refresh,$now,$checkrole,$caller) = @_; + my ($cdom,$cnum,$then,$refresh,$now,$checkrole) = @_; my $cckey = 'user.role.'.$checkrole.'./'.$cdom.'/'.$cnum; if ($env{$cckey}) { my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus,$tpstart,$tpend); &role_status($cckey,$then,$refresh,$now,\$role,\$where,\$trolecode,\$tstatus,\$tstart,\$tend); unless (($tstatus eq 'is') || ($tstatus eq 'will_not')) { - &set_adhoc_privileges($cdom,$cnum,$checkrole,$caller); + &set_adhoc_privileges($cdom,$cnum,$checkrole); } } else { - &set_adhoc_privileges($cdom,$cnum,$checkrole,$caller); + &set_adhoc_privileges($cdom,$cnum,$checkrole); } } sub set_adhoc_privileges { # role can be cc or ca - my ($dcdom,$pickedcourse,$role,$caller) = @_; + my ($dcdom,$pickedcourse,$role) = @_; my $area = '/'.$dcdom.'/'.$pickedcourse; my $spec = $role.'.'.$area; my %userroles = &set_arearole($role,$area,'','',$env{'user.domain'}, @@ -4202,16 +4090,14 @@ sub set_adhoc_privileges { my ($author,$adv)= &set_userprivs(\%userroles,\%ccrole); &appenv(\%userroles,[$role,'cm']); &log($env{'user.domain'},$env{'user.name'},$env{'user.home'},"Role ".$role); - unless ($caller eq 'constructaccess' && $env{'request.course.id'}) { - &appenv( {'request.role' => $spec, - 'request.role.domain' => $dcdom, - 'request.course.sec' => '' - } - ); - my $tadv=0; - if (&allowed('adv') eq 'F') { $tadv=1; } - &appenv({'request.role.adv' => $tadv}); - } + &appenv( {'request.role' => $spec, + 'request.role.domain' => $dcdom, + 'request.course.sec' => '' + } + ); + my $tadv=0; + if (&allowed('adv') eq 'F') { $tadv=1; } + &appenv({'request.role.adv' => $tadv}); } # --------------------------------------------------------------- get interface @@ -4260,7 +4146,7 @@ sub del { # -------------------------------------------------------------- dump interface sub dump { - my ($namespace,$udomain,$uname,$regexp,$range,$extra)=@_; + my ($namespace,$udomain,$uname,$regexp,$range)=@_; if (!$udomain) { $udomain=$env{'user.domain'}; } if (!$uname) { $uname=$env{'user.name'}; } my $uhome=&homeserver($uname,$udomain); @@ -4269,7 +4155,7 @@ sub dump { } else { $regexp='.'; } - my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range:$extra",$uhome); + my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome); my @pairs=split(/\&/,$rep); my %returnhash=(); foreach my $item (@pairs) { @@ -4945,11 +4831,6 @@ sub is_course_owner { 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'}; - } - } my %roleshash = &get_my_roles($uname,$udom,'userroles',undef,undef,undef,1); my %allroles; my $is_adv; @@ -5672,7 +5553,8 @@ sub update_allusers_table { 'generation='.&escape($names->{'generation'}).'%%'. 'permanentemail='.&escape($names->{'permanentemail'}).'%%'. 'id='.&escape($names->{'id'}),$homeserver); - return; + my $reply = &get_query_reply($queryid); + return $reply; } # ------- Request retrieval of institutional classlists for course(s) @@ -6235,8 +6117,7 @@ sub get_users_groups { } else { $grouplist = ''; my $courseurl = &courseid_to_courseurl($courseid); - my $extra = &freeze_escape({'skipcheck' => 1}); - my %roleshash = &dump('roles',$udom,$uname,$courseurl,undef,$extra); + my %roleshash = &dump('roles',$udom,$uname,$courseurl); my $access_end = $env{'course.'.$courseid. '.default_enrollment_end_date'}; my $now = time; @@ -6596,10 +6477,6 @@ sub modifyuser { ' by '.$env{'user.name'}.' at '.$env{'user.domain'}. ' in domain '.$env{'request.role.domain'}); my $uhome=&homeserver($uname,$udom,'true'); - my $newuser; - if ($uhome eq 'no_host') { - $newuser = 1; - } # ----------------------------------------------------------------- Create User if (($uhome eq 'no_host') && (($umode && $upass) || ($umode eq 'localauth'))) { @@ -6652,18 +6529,18 @@ sub modifyuser { ['firstname','middlename','lastname','generation','id', 'permanentemail','inststatus'], $udom,$uname); - my (%names,%oldnames); + my %names; if ($tmp[0] =~ m/^error:.*/) { %names=(); } else { %names = @tmp; - %oldnames = %names; } # # If name, email and/or uid are blank (e.g., because an uploaded file # of users did not contain them), do not overwrite existing values -# unless field is in $candelete array ref. +# unless field is in $candelete array ref. # + my @fields = ('firstname','middlename','lastname','generation', 'permanentemail','id'); my %newvalues; @@ -6676,7 +6553,7 @@ sub modifyuser { $names{$field} = $middle; } elsif ($field eq 'lastname') { $names{$field} = $last; - } elsif ($field eq 'generation') { + } elsif ($field eq 'generation') { $names{$field} = $gene; } elsif ($field eq 'permanentemail') { $names{$field} = $email; @@ -6686,7 +6563,6 @@ sub modifyuser { } } } - if ($first) { $names{'firstname'} = $first; } if (defined($middle)) { $names{'middlename'} = $middle; } if ($last) { $names{'lastname'} = $last; } @@ -6711,7 +6587,11 @@ sub modifyuser { } } } - my $logmsg = $udom.', '.$uname.', '.$uid.', '. + my $reply = &put('environment', \%names, $udom,$uname); + if ($reply ne 'ok') { return 'error: '.$reply; } + my $sqlresult = &update_allusers_table($uname,$udom,\%names); + &devalidate_cache_new('namescache',$uname.':'.$udom); + my $logmsg = 'Success modifying user '.$udom.', '.$uname.', '.$uid.', '. $umode.', '.$first.', '.$middle.', '. $last.', '.$gene.', '.$email.', '.$inststatus; if ($env{'user.name'} ne '' && $env{'user.domain'}) { @@ -6719,32 +6599,6 @@ sub modifyuser { } else { $logmsg .= ' during self creation'; } - my $changed; - if ($newuser) { - $changed = 1; - } else { - foreach my $field (@fields) { - if ($names{$field} ne $oldnames{$field}) { - $changed = 1; - last; - } - } - } - unless ($changed) { - $logmsg = 'No changes in user information needed for: '.$logmsg; - &logthis($logmsg); - return 'ok'; - } - my $reply = &put('environment', \%names, $udom,$uname); - if ($reply ne 'ok') { - return 'error: '.$reply; - } - if ($names{'permanentemail'} ne $oldnames{'permanentemail'}) { - &Apache::lonnet::devalidate_cache_new('emailscache',$uname.':'.$udom); - } - my $sqlresult = &update_allusers_table($uname,$udom,\%names); - &devalidate_cache_new('namescache',$uname.':'.$udom); - $logmsg = 'Success modifying user '.$logmsg; &logthis($logmsg); return 'ok'; } @@ -7118,7 +6972,7 @@ sub is_locked { my ($file_name, $domain, $user) = @_; 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); @@ -7135,7 +6989,6 @@ sub is_locked { } else { $is_locked = 'false'; } - return $is_locked; } sub declutter_portfile { @@ -8278,6 +8131,7 @@ sub add_prefix_and_part { # ---------------------------------------------------------------- Get metadata my %metaentry; +my %importedpartids; sub metadata { my ($uri,$what,$liburi,$prefix,$depthcount)=@_; $uri=&declutter($uri); @@ -8285,7 +8139,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|/$|) || ($uri =~ m|/.meta$|) ) { return undef; } if (($uri =~ /^~/ || $uri =~ m{home/$match_username/public_html/}) @@ -8304,6 +8158,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? # @@ -8387,27 +8245,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); @@ -8415,9 +8301,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'}; } @@ -8491,6 +8384,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); @@ -9851,6 +9760,12 @@ sub get_dns { return %libserv; } + sub unique_library { + #2x reverse removes all hostnames that appear more than once + my %unique = reverse &all_library(); + return reverse %unique; + } + sub get_servers { &load_hosts_tab() if (!$loaded); @@ -9874,6 +9789,11 @@ sub get_dns { return %result; } + sub get_unique_servers { + my %unique = reverse &get_servers(@_); + return reverse %unique; + } + sub host_domain { &load_hosts_tab() if (!$loaded); @@ -10442,7 +10362,7 @@ modifyuser($udom,$uname,$uid,$umode,$upa will update user information (firstname,middlename,lastname,generation, permanentemail), and if forceid is true, student/employee ID also. A user's institutional affiliation(s) can also be updated. -User information fields will not be overwritten with empty entries +User information fields will not be overwritten with empty entries unless the field is included in the $candelete array reference. This array is included when a single user is modified via "Manage Users", or when Autoupdate.pl is run by cron in a domain.