--- loncom/lonnet/perl/lonnet.pm 2011/10/31 13:44:37 1.1141 +++ loncom/lonnet/perl/lonnet.pm 2012/04/24 20:31:59 1.1165 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1141 2011/10/31 13:44:37 raeburn Exp $ +# $Id: lonnet.pm,v 1.1165 2012/04/24 20:31:59 droeschl Exp $ # # Copyright Michigan State University Board of Trustees # @@ -96,6 +96,7 @@ use Math::Random; use File::MMagic; use LONCAPA qw(:DEFAULT :match); use LONCAPA::Configuration; +use LONCAPA::lonmetadata; use File::Copy; @@ -595,13 +596,21 @@ sub transfer_profile_to_env { # ---------------------------------------------------- Check for valid session sub check_for_valid_session { - my ($r) = @_; + my ($r,$name) = @_; my %cookies=CGI::Cookie->parse($r->header_in('Cookie')); - my $lonid=$cookies{'lonID'}; + if ($name eq '') { + $name = 'lonID'; + } + my $lonid=$cookies{$name}; return undef if (!$lonid); my $handle=&LONCAPA::clean_handle($lonid->value); - my $lonidsdir=$r->dir_config('lonIDsDir'); + my $lonidsdir; + if ($name eq 'lonDAV') { + $lonidsdir=$r->dir_config('lonDAVsessDir'); + } else { + $lonidsdir=$r->dir_config('lonIDsDir'); + } return undef if (!-e "$lonidsdir/$handle.id"); my $opened = open(my $idf,'+<',"$lonidsdir/$handle.id"); @@ -930,7 +939,7 @@ sub choose_server { my %domconfhash = &Apache::loncommon::get_domainconf($udom); my %servers = &get_servers($udom); my $lowest_load = 30000; - my ($login_host,$hostname,$portal_path); + my ($login_host,$hostname,$portal_path,$isredirect); foreach my $lonhost (keys(%servers)) { my $loginvia; if ($checkloginvia) { @@ -941,12 +950,14 @@ sub choose_server { &compare_server_load($server, $login_host, $lowest_load); if ($login_host eq $server) { $portal_path = $path; + $isredirect = 1; } } else { ($login_host, $lowest_load) = &compare_server_load($lonhost, $login_host, $lowest_load); if ($login_host eq $lonhost) { $portal_path = ''; + $isredirect = ''; } } } else { @@ -957,7 +968,7 @@ sub choose_server { if ($login_host ne '') { $hostname = &hostname($login_host); } - return ($login_host,$hostname,$portal_path); + return ($login_host,$hostname,$portal_path,$isredirect); } # --------------------------------------------- Try to change a user's password @@ -1524,16 +1535,13 @@ sub idput { # ------------------------------dump from db file owned by domainconfig user sub dump_dom { - my ($namespace,$udom,$regexp,$range)=@_; - if (!$udom) { - $udom=$env{'user.domain'}; - } - my %returnhash; - if ($udom) { - my $uname = &get_domainconfiguser($udom); - %returnhash = &dump($namespace,$udom,$uname,$regexp,$range); - } - return %returnhash; + my ($namespace, $udom, $regexp) = @_; + + $udom ||= $env{'user.domain'}; + + return () unless $udom; + + return &dump($namespace, $udom, &get_domainconfiguser($udom), $regexp); } # ------------------------------------------ get items from domain db files @@ -1920,6 +1928,7 @@ sub get_domain_defaults { $domdefaults{'auth_arg_def'} = $domconfig{'defaults'}{'auth_arg_def'}; $domdefaults{'timezone_def'} = $domconfig{'defaults'}{'timezone_def'}; $domdefaults{'datelocale_def'} = $domconfig{'defaults'}{'datelocale_def'}; + $domdefaults{'portal_def'} = $domconfig{'defaults'}{'portal_def'}; } else { $domdefaults{'lang_def'} = &domain($domain,'lang_def'); $domdefaults{'auth_def'} = &domain($domain,'auth_def'); @@ -2429,10 +2438,11 @@ sub subscribe { sub repcopy { my $filename=shift; $filename=~s/\/+/\//g; - if ($filename=~m|^/home/httpd/html/adm/|) { return 'ok'; } - if ($filename=~m|^/home/httpd/html/lonUsers/|) { return 'ok'; } - if ($filename=~m|^/home/httpd/html/userfiles/| or - $filename=~m -^/*(uploaded|editupload)/-) { + my $londocroot = $perlvar{'lonDocRoot'}; + if ($filename=~m{^\Q$londocroot/adm/\E}) { return 'ok'; } + if ($filename=~m{^\Q/home/httpd/lonUsers/\E}) { return 'ok'; } + if ($filename=~m{^\Q$londocroot/userfiles/\E} or + $filename=~m{^/*(uploaded|editupload)/}) { return &repcopy_userfile($filename); } $filename=~s/[\n\r]//g; @@ -2459,7 +2469,7 @@ sub repcopy { unless ($home eq $perlvar{'lonHostID'}) { my @parts=split(/\//,$filename); my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]"; - if ($path ne "$perlvar{'lonDocRoot'}/res") { + if ($path ne "$londocroot/res") { &logthis("Malconfiguration for replication: $filename"); return 'bad_request'; } @@ -2797,7 +2807,7 @@ sub resizeImage { # $resizewidth - width (pixels) to which to resize uploaded image # $resizeheight - height (pixels) to which to resize uploaded image # $mimetype - reference to scalar to accommodate mime type determined -# from File::MMagic if $parser = parse. +# from File::MMagic. # # output: url of file in userspace, or error: # or /adm/notfound.html if failure to upload occurse @@ -2966,10 +2976,17 @@ sub finishuserfileupload { } } } + if (($context eq 'coursedoc') || ($parser eq 'parse')) { + if (ref($mimetype)) { + if ($$mimetype eq '') { + my $mm = new File::MMagic; + my $type = $mm->checktype_filename($filepath.'/'.$file); + $$mimetype = $type; + } + } + } if ($parser eq 'parse') { - my $mm = new File::MMagic; - my $type = $mm->checktype_filename($filepath.'/'.$file); - if ($type eq 'text/html') { + if ((ref($mimetype)) && ($$mimetype eq 'text/html')) { my $parse_result = &extract_embedded_items($filepath.'/'.$file, $allfiles,$codebase); unless ($parse_result eq 'ok') { @@ -2977,9 +2994,6 @@ sub finishuserfileupload { ' for embedded media: '.$parse_result); } } - if (ref($mimetype)) { - $$mimetype = $type; - } } if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) { my $input = $filepath.'/'.$file; @@ -3016,6 +3030,7 @@ sub finishuserfileupload { sub extract_embedded_items { my ($fullpath,$allfiles,$codebase,$content) = @_; my @state = (); + my (%lastids,%related,%shockwave,%flashvars); my %javafiles = ( codebase => '', code => '', @@ -3045,10 +3060,30 @@ sub extract_embedded_items { &add_filetype($allfiles,$attr->{'href'},'href'); } if (lc($tagname) eq 'script') { + my $src; if ($attr->{'archive'} =~ /\.jar$/i) { &add_filetype($allfiles,$attr->{'archive'},'archive'); } else { - &add_filetype($allfiles,$attr->{'src'},'src'); + if ($attr->{'src'} ne '') { + $src = $attr->{'src'}; + &add_filetype($allfiles,$src,'src'); + } + } + my $text = $p->get_trimmed_text(); + if ($text =~ /\Qswfobject.registerObject(\E([^\)]+)\)/) { + my @swfargs = split(/,/,$1); + foreach my $item (@swfargs) { + $item =~ s/["']//g; + $item =~ s/^\s+//; + $item =~ s/\s+$//; + } + if (($swfargs[0] ne'') && ($swfargs[2] ne '')) { + if (ref($related{$swfargs[0]}) eq 'ARRAY') { + push(@{$related{$swfargs[0]}},$swfargs[2]); + } else { + $related{$swfargs[0]} = [$swfargs[2]]; + } + } } } if (lc($tagname) eq 'link') { @@ -3061,6 +3096,9 @@ sub extract_embedded_items { foreach my $item (keys(%javafiles)) { $javafiles{$item} = ''; } + if ((lc($tagname) eq 'object') && (lc($state[-2]) ne 'object')) { + $lastids{lc($tagname)} = $attr->{'id'}; + } } if (lc($state[-2]) eq 'object' && lc($tagname) eq 'param') { my $name = lc($attr->{'name'}); @@ -3070,12 +3108,22 @@ sub extract_embedded_items { last; } } + my $pathfrom; foreach my $item (keys(%mediafiles)) { if ($name eq $item) { - &add_filetype($allfiles, $attr->{'value'}, 'value'); + $pathfrom = $attr->{'value'}; + $shockwave{$lastids{lc($state[-2])}} = $pathfrom; + &add_filetype($allfiles,$pathfrom,$name); last; } } + if ($name eq 'flashvars') { + $flashvars{$lastids{lc($state[-2])}} = $attr->{'value'}; + } + if ($pathfrom ne '') { + &embedded_dependency($allfiles,\%related,$lastids{lc($state[-2])}, + $pathfrom); + } } if (lc($tagname) eq 'embed' || lc($tagname) eq 'applet') { foreach my $item (keys(%javafiles)) { @@ -3090,7 +3138,16 @@ sub extract_embedded_items { last; } } + if (lc($tagname) eq 'embed') { + if (($attr->{'name'} ne '') && ($attr->{'src'} ne '')) { + &embedded_dependency($allfiles,\%related,$attr->{'name'}, + $attr->{'src'}); + } + } } + if ($t->[4] =~ m{/>$}) { + pop(@state); + } } elsif ($t->[0] eq 'E') { my ($tagname) = ($t->[1]); if ($javafiles{'codebase'} ne '') { @@ -3110,6 +3167,23 @@ sub extract_embedded_items { pop @state; } } + foreach my $id (sort(keys(%flashvars))) { + if ($shockwave{$id} ne '') { + my @pairs = split(/\&/,$flashvars{$id}); + foreach my $pair (@pairs) { + my ($key,$value) = split(/\=/,$pair); + if ($key eq 'thumb') { + &add_filetype($allfiles,$value,$key); + } elsif ($key eq 'content') { + my ($path) = ($shockwave{$id} =~ m{^(.+/)[^/]+$}); + my ($ext) = ($value =~ /\.([^.]+)$/); + if ($ext ne '') { + &add_filetype($allfiles,$path.$value,$ext); + } + } + } + } + } return 'ok'; } @@ -3124,6 +3198,21 @@ sub add_filetype { } } +sub embedded_dependency { + my ($allfiles,$related,$identifier,$pathfrom) = @_; + if ((ref($allfiles) eq 'HASH') && (ref($related) eq 'HASH')) { + if (($identifier ne '') && + (ref($related->{$identifier}) eq 'ARRAY') && + ($pathfrom ne '')) { + my ($path) = ($pathfrom =~ m{^(.+/)[^/]+$}); + foreach my $dep (@{$related->{$identifier}}) { + &add_filetype($allfiles,$path.$dep,'object'); + } + } + } + return; +} + sub removeuploadedurl { my ($url)=@_; my (undef,undef,$udom,$uname,$fname)=split('/',$url,5); @@ -3250,15 +3339,10 @@ sub flushcourselogs { my $result = &inc('nohist_accesscount',\%temphash,$dom,$name); if ($result eq 'ok') { delete $accesshash{$entry}; - } elsif ($result eq 'unknown_cmd') { - # Target server has old code running on it. - my %temphash=($entry => $value); - if (&put('nohist_resevaldata',\%temphash,$dom,$name) eq 'ok') { - delete $accesshash{$entry}; - } } } else { my ($dom,$name) = ($entry=~m{___($match_domain)/($match_name)/(.*)___(\w+)$}); + if (($dom eq 'uploaded') || ($dom eq 'adm')) { next; } my %temphash=($entry => $accesshash{$entry}); if (&put('nohist_resevaldata',\%temphash,$dom,$name) eq 'ok') { delete $accesshash{$entry}; @@ -3337,7 +3421,7 @@ sub courseacclog { my $fnsymb=shift; unless ($env{'request.course.id'}) { return ''; } my $what=$fnsymb.':'.$env{'user.name'}.':'.$env{'user.domain'}; - if ($fnsymb=~/(problem|exam|quiz|assess|survey|form|task|page)$/) { + if ($fnsymb=~/$LONCAPA::assess_re/) { $what.=':POST'; # FIXME: Probably ought to escape things.... foreach my $key (keys(%env)) { @@ -3369,7 +3453,13 @@ sub countacc { my $url=&declutter(shift); return if (! defined($url) || $url eq ''); unless ($env{'request.course.id'}) { return ''; } +# +# Mark that this url was used in this course +# $accesshash{$env{'request.course.id'}.'___'.$url.'___course'}=1; +# +# Increase the access count for this resource in this child process +# my $key=$$.$processmarker.'_'.$dumpcount.'___'.$url.'___count'; $accesshash{$key}++; } @@ -3381,6 +3471,22 @@ sub linklog { $accesshash{$from.'___'.$to.'___comefrom'}=1; $accesshash{$to.'___'.$from.'___goto'}=1; } + +sub statslog { + my ($symb,$part,$users,$av_attempts,$degdiff)=@_; + if ($users<2) { return; } + my %dynstore=&LONCAPA::lonmetadata::dynamic_metadata_storage({ + 'course' => $env{'request.course.id'}, + 'sections' => '"all"', + 'num_students' => $users, + 'part' => $part, + 'symb' => $symb, + 'mean_tries' => $av_attempts, + 'deg_of_diff' => $degdiff}); + foreach my $key (keys(%dynstore)) { + $accesshash{$key}=$dynstore{$key}; + } +} sub userrolelog { my ($trole,$username,$domain,$area,$tstart,$tend)=@_; @@ -3536,6 +3642,7 @@ sub get_my_roles { foreach my $entry (keys(%dumphash)) { my ($role,$tend,$tstart); if ($context eq 'userroles') { + next if ($entry =~ /^rolesdef/); ($role,$tend,$tstart)=split(/_/,$dumphash{$entry}); } else { ($tend,$tstart)=split(/\:/,$dumphash{$entry}); @@ -3849,11 +3956,34 @@ sub get_domain_roles { # ----------------------------------------------------------- Interval timing +{ +# Caches needed for speedup of navmaps +# We don't want to cache this for very long at all (5 seconds at most) +# +# The user for whom we cache +my $cachedkey=''; +# The cached times for this user +my %cachedtimes=(); +# When this was last done +my $cachedtime=(); + +sub load_all_first_access { + my ($uname,$udom)=@_; + if (($cachedkey eq $uname.':'.$udom) && + (abs($cachedtime-time)<5)) { + return; + } + $cachedtime=time; + $cachedkey=$uname.':'.$udom; + %cachedtimes=&dump('firstaccesstimes',$udom,$uname); +} + sub get_first_access { - my ($type,$argsymb)=@_; + my ($type,$argsymb,$argmap)=@_; my ($symb,$courseid,$udom,$uname)=&whichuser(); if ($argsymb) { $symb=$argsymb; } my ($map,$id,$res)=&decode_symb($symb); + if ($argmap) { $map = $argmap; } if ($type eq 'course') { $res='course'; } elsif ($type eq 'map') { @@ -3861,12 +3991,12 @@ sub get_first_access { } else { $res=$symb; } - my %times=&get('firstaccesstimes',["$courseid\0$res"],$udom,$uname); - return $times{"$courseid\0$res"}; + &load_all_first_access($uname,$udom); + return $cachedtimes{"$courseid\0$res"}; } sub set_first_access { - my ($type)=@_; + my ($type,$interval)=@_; my ($symb,$courseid,$udom,$uname)=&whichuser(); my ($map,$id,$res)=&decode_symb($symb); if ($type eq 'course') { @@ -3876,13 +4006,27 @@ sub set_first_access { } else { $res=$symb; } - my $firstaccess=&get_first_access($type,$symb); + $cachedkey=''; + my $firstaccess=&get_first_access($type,$symb,$map); if (!$firstaccess) { - return &put('firstaccesstimes',{"$courseid\0$res"=>time},$udom,$uname); + my $start = time; + my $putres = &put('firstaccesstimes',{"$courseid\0$res"=>$start}, + $udom,$uname); + if ($putres eq 'ok') { + &put('timerinterval',{"$courseid\0$res"=>$interval}, + $udom,$uname); + &appenv( + { + 'course.'.$courseid.'.firstaccess.'.$res => $start, + 'course.'.$courseid.'.timerinterval.'.$res => $interval, + } + ); + } + return $putres; } return 'already_set'; } - +} # --------------------------------------------- Set Expire Date for Spreadsheet sub expirespread { @@ -4511,8 +4655,20 @@ sub rolesinit { ($rolesdump =~ /^error:/)) { return \%userroles; } + my %firstaccess = &dump('firstaccesstimes',$domain,$username); + my %timerinterval = &dump('timerinterval',$domain,$username); + my (%coursetimerstarts,%firstaccchk,%firstaccenv, + %coursetimerintervals,%timerintchk,%timerintenv); + foreach my $key (keys(%firstaccess)) { + my ($cid,$rest) = split(/\0/,$key); + $coursetimerstarts{$cid}{$rest} = $firstaccess{$key}; + } + foreach my $key (keys(%timerinterval)) { + my ($cid,$rest) = split(/\0/,$key); + $coursetimerintervals{$cid}{$rest} = $timerinterval{$key}; + } my %allroles=(); - my %allgroups=(); + my %allgroups=(); if ($rolesdump ne '') { foreach my $entry (split(/&/,$rolesdump)) { @@ -4550,6 +4706,27 @@ sub rolesinit { } else { &standard_roleprivs(\%allroles,$trole,$tdomain,$spec,$trest,$area); } + if ($trole ne 'gr') { + my $cid = $tdomain.'_'.$trest; + unless ($firstaccchk{$cid}) { + if (ref($coursetimerstarts{$cid}) eq 'HASH') { + foreach my $item (keys(%{$coursetimerstarts{$cid}})) { + $firstaccenv{'course.'.$cid.'.firstaccess.'.$item} = + $coursetimerstarts{$cid}{$item}; + } + } + $firstaccchk{$cid} = 1; + } + unless ($timerintchk{$cid}) { + if (ref($coursetimerintervals{$cid}) eq 'HASH') { + foreach my $item (keys(%{$coursetimerintervals{$cid}})) { + $timerintenv{'course.'.$cid.'.timerinterval.'.$item} = + $coursetimerintervals{$cid}{$item}; + } + } + $timerintchk{$cid} = 1; + } + } } } } @@ -4558,7 +4735,7 @@ sub rolesinit { $userroles{'user.author'} = $author; $env{'user.adv'}=$adv; } - return \%userroles; + return (\%userroles,\%firstaccenv,\%timerintenv); } sub set_arearole { @@ -5939,7 +6116,12 @@ sub allowed { if ($match) { if ($env{'user.priv.'.$env{'request.role'}.'./'} =~/\Q$priv\E\&([^\:]*)/) { - $thisallowed.=$1; + my @blockers = &has_comm_blocking($priv,$symb,$uri); + if (@blockers > 0) { + $thisallowed = 'B'; + } else { + $thisallowed.=$1; + } } } else { my $refuri = $env{'httpref.'.$orguri} || $env{'httpref.'.$ver_orguri}; @@ -5950,7 +6132,12 @@ sub allowed { $refuri=&declutter($refuri); my ($match) = &is_on_map($refuri); if ($match) { - $thisallowed='F'; + my @blockers = &has_comm_blocking($priv,$symb,$refuri); + if (@blockers > 0) { + $thisallowed = 'B'; + } else { + $thisallowed='F'; + } } } } @@ -6002,7 +6189,17 @@ sub allowed { $statecond=$cond; if ($env{'user.priv.'.$env{'request.role'}.'./'.$courseprivid} =~/\Q$priv\E\&([^\:]*)/) { - $thisallowed.=$1; + my $value = $1; + if ($priv eq 'bre') { + my @blockers = &has_comm_blocking($priv,$symb,$uri); + if (@blockers > 0) { + $thisallowed = 'B'; + } else { + $thisallowed.=$value; + } + } else { + $thisallowed.=$value; + } $checkreferer=0; } } @@ -6030,7 +6227,17 @@ sub allowed { my $refstatecond=$cond; if ($env{'user.priv.'.$env{'request.role'}.'./'.$courseprivid} =~/\Q$priv\E\&([^\:]*)/) { - $thisallowed.=$1; + my $value = $1; + if ($priv eq 'bre') { + my @blockers = &has_comm_blocking($priv,$symb,$refuri); + if (@blockers > 0) { + $thisallowed = 'B'; + } else { + $thisallowed.=$value; + } + } else { + $thisallowed.=$value; + } $uri=$refuri; $statecond=$refstatecond; } @@ -6189,6 +6396,164 @@ sub allowed { } return 'F'; } + +sub get_comm_blocks { + my ($cdom,$cnum) = @_; + if ($cdom eq '' || $cnum eq '') { + return unless ($env{'request.course.id'}); + $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + } + my %commblocks; + my $hashid=$cdom.'_'.$cnum; + my ($blocksref,$cached)=&is_cached_new('comm_block',$hashid); + if ((defined($cached)) && (ref($blocksref) eq 'HASH')) { + %commblocks = %{$blocksref}; + } else { + %commblocks = &Apache::lonnet::dump('comm_block',$cdom,$cnum); + my $cachetime = 600; + &do_cache_new('comm_block',$hashid,\%commblocks,$cachetime); + } + return %commblocks; +} + +sub has_comm_blocking { + my ($priv,$symb,$uri,$blocks) = @_; + return unless ($env{'request.course.id'}); + return unless ($priv eq 'bre'); + return if ($env{'user.priv.'.$env{'request.role'}} =~/evb\&([^\:]*)/); + my %commblocks; + if (ref($blocks) eq 'HASH') { + %commblocks = %{$blocks}; + } else { + %commblocks = &get_comm_blocks(); + } + return unless (keys(%commblocks) > 0); + if (!$symb) { $symb=&symbread($uri,1); } + my ($map,$resid,undef)=&decode_symb($symb); + my %tocheck = ( + maps => $map, + resources => $symb, + ); + my @blockers; + my $now = time; + my $navmap = Apache::lonnavmaps::navmap->new(); + foreach my $block (keys(%commblocks)) { + if ($block =~ /^(\d+)____(\d+)$/) { + my ($start,$end) = ($1,$2); + if ($start <= $now && $end >= $now) { + if (ref($commblocks{$block}{'blocks'}) eq 'HASH') { + if (ref($commblocks{$block}{'blocks'}{'docs'}) eq 'HASH') { + if (ref($commblocks{$block}{'blocks'}{'docs'}{'maps'}) eq 'HASH') { + if ($commblocks{$block}{'blocks'}{'docs'}{'maps'}{$map}) { + unless (grep(/^\Q$block\E$/,@blockers)) { + push(@blockers,$block); + } + } + } + if (ref($commblocks{$block}{'blocks'}{'docs'}{'resources'}) eq 'HASH') { + if ($commblocks{$block}{'blocks'}{'docs'}{'resources'}{$symb}) { + unless (grep(/^\Q$block\E$/,@blockers)) { + push(@blockers,$block); + } + } + } + } + } + } + } elsif ($block =~ /^firstaccess____(.+)$/) { + my $item = $1; + my @to_test; + if (ref($commblocks{$block}{'blocks'}) eq 'HASH') { + if (ref($commblocks{$block}{'blocks'}{'docs'}) eq 'HASH') { + my $check_interval; + if (&check_docs_block($commblocks{$block}{'blocks'}{'docs'},\%tocheck)) { + my @interval; + my $type = 'map'; + if ($item eq 'course') { + $type = 'course'; + @interval=&EXT("resource.0.interval"); + } else { + if ($item =~ /___\d+___/) { + $type = 'resource'; + @interval=&EXT("resource.0.interval",$item); + if (ref($navmap)) { + my $res = $navmap->getBySymb($item); + push(@to_test,$res); + } + } else { + my $mapsymb = &symbread($item,1); + if ($mapsymb) { + if (ref($navmap)) { + my $mapres = $navmap->getBySymb($mapsymb); + @to_test = $mapres->retrieveResources($mapres,undef,0,1); + foreach my $res (@to_test) { + my $symb = $res->symb(); + next if ($symb eq $mapsymb); + if ($symb ne '') { + @interval=&EXT("resource.0.interval",$symb); + last; + } + } + } + } + } + } + if ($interval[0] =~ /\d+/) { + my $first_access; + if ($type eq 'resource') { + $first_access=&get_first_access($interval[1],$item); + } elsif ($type eq 'map') { + $first_access=&get_first_access($interval[1],undef,$item); + } else { + $first_access=&get_first_access($interval[1]); + } + if ($first_access) { + my $timesup = $first_access+$interval[0]; + if ($timesup > $now) { + foreach my $res (@to_test) { + if ($res->is_problem()) { + if ($res->completable()) { + unless (grep(/^\Q$block\E$/,@blockers)) { + push(@blockers,$block); + } + last; + } + } + } + } + } + } + } + } + } + } + } + return @blockers; +} + +sub check_docs_block { + my ($docsblock,$tocheck) =@_; + if ((ref($docsblock) ne 'HASH') || (ref($tocheck) ne 'HASH')) { + return; + } + if (ref($docsblock->{'maps'}) eq 'HASH') { + if ($tocheck->{'maps'}) { + if ($docsblock->{'maps'}{$tocheck->{'maps'}}) { + return 1; + } + } + } + if (ref($docsblock->{'resources'}) eq 'HASH') { + if ($tocheck->{'resources'}) { + if ($docsblock->{'resources'}{$tocheck->{'resources'}}) { + return 1; + } + } + } + return; +} + # # Removes the versino from a URI and # splits it in to its filename and path to the filename. @@ -7513,14 +7878,16 @@ sub modify_student_enrollment { $uid = $tmp{'id'} if (!defined($uid) || $uid eq ''); } my $fullname = &format_name($first,$middle,$last,$gene,'lastname'); + my $user = "$uname:$udom"; + my %old_entry = &Apache::lonnet::get('classlist',[$user],$cdom,$cnum); my $reply=cput('classlist', - {"$uname:$udom" => + {$user => join(':',$end,$start,$uid,$usec,$fullname,$type,$locktype) }, $cdom,$cnum); - unless (($reply eq 'ok') || ($reply eq 'delayed')) { + if (($reply eq 'ok') || ($reply eq 'delayed')) { + &devalidate_getsection_cache($udom,$uname,$cid); + } else { return 'error: '.$reply; - } else { - &devalidate_getsection_cache($udom,$uname,$cid); } # Add student role to user my $uurl='/'.$cid; @@ -7528,7 +7895,16 @@ sub modify_student_enrollment { if ($usec) { $uurl.='/'.$usec; } - return &assignrole($udom,$uname,$uurl,'st',$end,$start,undef,$selfenroll,$context); + my $result = &assignrole($udom,$uname,$uurl,'st',$end,$start,undef, + $selfenroll,$context); + if ($result ne 'ok') { + if ($old_entry{$user} ne '') { + $reply = &cput('classlist',\%old_entry,$cdom,$cnum); + } else { + $reply = &del('classlist',[$user],$cdom,$cnum); + } + } + return $result; } sub format_name { @@ -8708,15 +9084,7 @@ sub EXT { } elsif ($realm eq 'request') { # ------------------------------------------------------------- request.browser if ($space eq 'browser') { - if ($qualifier eq 'textremote') { - if (&Apache::lonlocal::mt('textual_remote_display') eq 'on') { - return 1; - } else { - return 0; - } - } else { - return $env{'browser.'.$qualifier}; - } + return $env{'browser.'.$qualifier}; # ------------------------------------------------------------ request.filename } else { return $env{'request.'.$spacequalifierrest}; @@ -9361,6 +9729,10 @@ sub gettitle { } $title=~s/\&colon\;/\:/gs; if ($title) { +# Remember both $symb and $title for dynamic metadata + $accesshash{$symb.'___crstitle'}=$title; + $accesshash{&declutter($map).'___'.&declutter($url).'___usage'}=time; +# Cache this title and then return it return &do_cache_new('title',$key,$title,600); } $urlsymb=$url; @@ -9393,6 +9765,49 @@ sub get_slot { } return $slotinfo{$which}; } + +sub get_reservable_slots { + my ($cnum,$cdom,$uname,$udom) = @_; + my $now = time; + my $reservable_info; + my $key=join("\0",'reservableslots',$cdom,$cnum,$uname,$udom); + if (exists($remembered{$key})) { + $reservable_info = $remembered{$key}; + } else { + my %resv; + ($resv{'now_order'},$resv{'now'},$resv{'future_order'},$resv{'future'}) = + &Apache::loncommon::get_future_slots($cnum,$cdom,$now); + $reservable_info = \%resv; + $remembered{$key} = $reservable_info; + } + return $reservable_info; +} + +sub get_course_slots { + my ($cnum,$cdom) = @_; + my $hashid=$cnum.':'.$cdom; + my ($result,$cached) = &Apache::lonnet::is_cached_new('allslots',$hashid); + if (defined($cached)) { + if (ref($result) eq 'HASH') { + return %{$result}; + } + } else { + my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum); + my ($tmp) = keys(%slots); + if ($tmp !~ /^(con_lost|error|no_such_host)/i) { + &Apache::lonnet::do_cache_new('allslots',$hashid,\%slots,600); + return %slots; + } + } + return; +} + +sub devalidate_slots_cache { + my ($cnum,$cdom)=@_; + my $hashid=$cnum.':'.$cdom; + &devalidate_cache_new('allslots',$hashid); +} + # ------------------------------------------------- Update symbolic store links sub symblist { @@ -9758,9 +10173,11 @@ sub rndseed { if (!defined($symb)) { unless ($symb=$wsymb) { return time; } } - if (!$courseid) { $courseid=$wcourseid; } - if (!$domain) { $domain=$wdomain; } - if (!$username) { $username=$wusername } + if (!defined $courseid) { + $courseid=$wcourseid; + } + if (!defined $domain) { $domain=$wdomain; } + if (!defined $username) { $username=$wusername } my $which; if (defined($cenv->{'rndseed'})) { @@ -9768,7 +10185,6 @@ sub rndseed { } else { $which =&get_rand_alg($courseid); } - if (defined(&getCODE())) { if ($which eq '64bit5') { @@ -10094,8 +10510,9 @@ sub getfile { sub repcopy_userfile { my ($file)=@_; - if ($file =~ m -^/*(uploaded|editupload)/-) { $file=&filelocation("",$file); } - if ($file =~ m|^/home/httpd/html/lonUsers/|) { return 'ok'; } + my $londocroot = $perlvar{'lonDocRoot'}; + if ($file =~ m{^/*(uploaded|editupload)/}) { $file=&filelocation("",$file); } + if ($file =~ m{^\Q/home/httpd/lonUsers/\E}) { return 'ok'; } my ($cdom,$cnum,$filename) = ($file=~m|^\Q$perlvar{'lonDocRoot'}\E/+userfiles/+($match_domain)/+($match_name)/+(.*)|); my $uri="/uploaded/$cdom/$cnum/$filename"; @@ -10248,7 +10665,7 @@ sub filelocation { if ( !( $file =~ m:^/:) ) { $location = $dir. '/'.$file; } else { - $location = '/home/httpd/html/'.$space.$file; + $location = $perlvar{'lonDocRoot'}.'/'.$space.$file; } } $location=~s://+:/:g; # remove duplicate / @@ -10274,8 +10691,8 @@ sub hreflocation { if ($file=~m-^\Q$perlvar{'lonDocRoot'}\E-) { $file=~s-^\Q$perlvar{'lonDocRoot'}\E--; } elsif ($file=~m-^\Q$perlvar{'lonUsersDir'}\E-) { - $file=~s-^/home/httpd/lonUsers/($match_domain)/./././($match_name)/userfiles/ - -/uploaded/$1/$2/-x; + $file=~s{^/home/httpd/lonUsers/($match_domain)/./././($match_name)/userfiles/} + {/uploaded/$1/$2/}x; } if ($file=~ m{^/userfiles/}) { $file =~ s{^/userfiles/}{/uploaded/};