--- rat/lonuserstate.pm 2006/05/11 23:56:27 1.107.2.1 +++ rat/lonuserstate.pm 2007/08/28 01:13:19 1.122 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Construct and maintain state and binary representation of course for user # -# $Id: lonuserstate.pm,v 1.107.2.1 2006/05/11 23:56:27 albertel Exp $ +# $Id: lonuserstate.pm,v 1.122 2007/08/28 01:13:19 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -33,6 +33,7 @@ package Apache::lonuserstate; use strict; use HTML::TokeParser; use Apache::lonnet; +use Apache::lonlocal; use Apache::loncommon(); use GDBM_File; use Apache::lonmsg; @@ -41,6 +42,8 @@ use Safe::Hole; use Opcode; use Apache::lonenc; use Fcntl qw(:flock); +use LONCAPA; + # ---------------------------------------------------- Globals for this package @@ -49,7 +52,8 @@ my %hash; # The big tied hash my %parmhash;# The hash with the parameters my @cond; # Array with all of the conditions my $errtext; # variable with all errors -my $retfurl; # variable with the very first URL in the course +my $retfrid; # variable with the very first RID in the course +my $retfurl; # first URL my %randompick; # randomly picked resources my %randompickseed; # optional seed for randomly picking resources my %encurl; # URLs in this folder are supposed to be encrypted @@ -103,8 +107,12 @@ sub processversionfile { sub loadmap { my $uri=shift; - if ($hash{'map_pc_'.$uri}) { return; } - + if ($hash{'map_pc_'.$uri}) { + $errtext.='

'. + &mt('Multiple use of sequence/page [_1]! The course will not function properly.',''.$uri.''). + '

'; + return; + } $pc++; my $lpc=$pc; $hash{'map_pc_'.$uri}=$lpc; @@ -117,7 +125,7 @@ sub loadmap { unless (($fn=~/\.sequence$/) || ($fn=~/\.page$/)) { - $errtext.="Invalid map: $fn\n"; + $errtext.=&mt("
Invalid map: [_1]",$fn); return; } @@ -277,22 +285,19 @@ sub loadmap { } $name=~s/^.*_([^_]*)$/$1/; my $newparam= - &Apache::lonnet::escape($token->[2]->{'type'}).':'. - &Apache::lonnet::escape($part.'.'.$name).'='. - &Apache::lonnet::escape($token->[2]->{'value'}); + &escape($token->[2]->{'type'}).':'. + &escape($part.'.'.$name).'='. + &escape($token->[2]->{'value'}); if (defined($hash{'param_'.$referid})) { $hash{'param_'.$referid}.='&'.$newparam; } else { $hash{'param_'.$referid}=''.$newparam; } - if ($token->[2]->{'name'}=~/^parameter_(0_)*mapalias$/) { - $hash{'mapalias_'.$token->[2]->{'value'}}=$referid; - } if ($token->[2]->{'name'}=~/^parameter_(0_)*randompick$/) { $randompick{$referid}=$token->[2]->{'value'}; } if ($token->[2]->{'name'}=~/^parameter_(0_)*randompickseed$/) { - $randompick{$referid}=$token->[2]->{'value'}; + $randompickseed{$referid}=$token->[2]->{'value'}; } if ($token->[2]->{'name'}=~/^parameter_(0_)*encrypturl$/) { if ($token->[2]->{'value'}=~/^yes$/i) { @@ -310,7 +315,29 @@ sub loadmap { } } else { - $errtext.='Map not loaded: The file ('.$fn.') does not exist. '; + $errtext.=&mt('
Map not loaded: The file [_1] does not exist.',$fn); + } + + my $parser = HTML::TokeParser->new(\$instr); + $parser->attr_encoded(1); + # last parse out the mapalias params so as to ignore anything + # refering to non-existant resources + while (my $token = $parser->get_token) { + next if ($token->[0] ne 'S'); + if ($token->[1] eq 'param') { + &parse_mapalias_param($token,$lpc); + } + } +} + +sub parse_mapalias_param { + my ($token,$lpc) = @_; + my $referid=$lpc.'.'.$token->[2]->{'to'}; + return if (!exists($hash{'src_'.$referid})); + + if ($token->[2]->{'name'}=~/^parameter_(0_)*mapalias$/) { + &count_mapalias($token->[2]->{'value'},$referid); + $hash{'mapalias_'.$token->[2]->{'value'}}=$referid; } } @@ -342,7 +369,7 @@ sub simplify { sub traceroute { my ($sofar,$rid,$beenhere,$encflag,$hdnflag)=@_; my $newsofar=$sofar=simplify($sofar); - unless ($beenhere=~/\&$rid\&/) { + unless ($beenhere=~/\&\Q$rid\E\&/) { $beenhere.=$rid.'&'; my ($mapid,$resid)=split(/\./,$rid); my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,$hash{'src_'.$rid}); @@ -357,10 +384,9 @@ sub traceroute { my $encrypt=&Apache::lonnet::EXT('resource.0.encrypturl',$symb); if ($encflag || lc($encrypt) eq 'yes') { $encurl{$rid}=1; } - if (($retfurl eq '') && ($hash{'src_'.$rid}) + if (($retfrid eq '') && ($hash{'src_'.$rid}) && ($hash{'src_'.$rid}!~/\.sequence$/)) { - $retfurl=$hash{'src_'.$rid}.(($hash{'src_'.$rid}=~/\?/)?'&':'?'). - 'symb='.$symb; + $retfrid=$rid; } if (defined($hash{'conditions_'.$rid})) { $hash{'conditions_'.$rid}=simplify( @@ -390,8 +416,7 @@ sub traceroute { $further=simplify('('.'_'.$rid.')&('. $hash{'condid_'.$hash{'undercond_'.$id}}.')'); } else { - $errtext.='Undefined condition ID: ' - .$hash{'undercond_'.$id}.'. '; + $errtext.=&mt('
Undefined condition ID: [_1]',$hash{'undercond_'.$id}); } } $newsofar=&traceroute($further,$hash{'goesto_'.$id},$beenhere, @@ -438,10 +463,10 @@ sub accinit { foreach my $param (split(/\&/,$hash{$key})) { my ($typename,$value)=split(/\=/,$param); my ($type,$name)=split(/\:/,$typename); - $parmhash{$prefix.'.'.&Apache::lonnet::unescape($name)}= - &Apache::lonnet::unescape($value); - $parmhash{$prefix.'.'.&Apache::lonnet::unescape($name).'.type'}= - &Apache::lonnet::unescape($type); + $parmhash{$prefix.'.'.&unescape($name)}= + &unescape($value); + $parmhash{$prefix.'.'.&unescape($name).'.type'}= + &unescape($type); } } } @@ -545,14 +570,14 @@ sub hiddenurls { sub readmap { my $short=shift; $short=~s/^\///; - my %cenv=&Apache::lonnet::coursedescription($short); + my %cenv=&Apache::lonnet::coursedescription($short,{'freshen_cache'=>1}); my $fn=$cenv{'fn'}; my $uri; $short=~s/\//\_/g; unless ($uri=$cenv{'url'}) { &Apache::lonnet::logthis("WARNING: ". "Could not load course $short."); - return 'No course data available.'; + return ('',&mt('No course data available.'));; } @cond=('true:normal'); @@ -568,13 +593,14 @@ sub readmap { undef %randompick; undef %hiddenurl; undef %encurl; - $retfurl=''; + $retfrid=''; if ($lock && (tie(%hash,'GDBM_File',"$fn.db",&GDBM_WRCREAT(),0640)) && (tie(%parmhash,'GDBM_File',$fn.'_parms.db',&GDBM_WRCREAT(),0640))) { %hash=(); %parmhash=(); $errtext=''; $pc=0; + &clear_mapalias_count(); &processversionfile(%cenv); my $furi=&Apache::lonnet::clutter($uri); $hash{'src_0.0'}=&versiontrack($furi); @@ -586,19 +612,19 @@ sub readmap { &Apache::lonnet::appenv("request.course.id" => $short, "request.course.fn" => $fn, "request.course.uri" => $uri); + $env{'request.course.id'}=$short; &traceroute('0',$hash{'map_start_'.$uri},'&'); &accinit($uri,$short,$fn); &hiddenurls(); } + $errtext .= &get_mapalias_errors(); # ------------------------------------------------------- Put versions into src foreach my $key (keys(%hash)) { if ($key=~/^src_/) { $hash{$key}=&putinversion($hash{$key}); } elsif ($key =~ /^(map_(?:start|finish|pc)_)(.*)/) { - &Apache::lonnet::logthis($key); my ($type, $url) = ($1,$2); my $value = $hash{$key}; - delete($hash{$key}); $hash{$type.&putinversion($url)}=$value; } } @@ -609,6 +635,14 @@ sub readmap { } # ----------------------------------------------- Close hashes to finally store # --------------------------------- Routine must pass this point, no early outs + $hash{'first_rid'}=$retfrid; + my ($mapid,$resid)=split(/\./,$retfrid); + $hash{'first_mapurl'}=$hash{'map_id_'.$mapid}; + my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,$hash{'src_'.$retfrid}); + $retfurl=&add_get_param($hash{'src_'.$retfrid},{ 'symb' => $symb }); + if ($hash{'encrypted_'.$retfrid}) { + $retfurl=&Apache::lonenc::encrypted($retfurl,(&Apache::lonnet::allowed('adv') ne 'F')); + } $hash{'first_url'}=$retfurl; unless ((untie(%hash)) && (untie(%parmhash))) { &Apache::lonnet::logthis("WARNING: ". @@ -683,8 +717,9 @@ sub evalstate { if (-e $fn) { my @conditions=(); { - my $fh=Apache::File->new($fn); + open(my $fh,"<$fn"); @conditions=<$fh>; + close($fh); } my $safeeval = new Safe; my $safehole = new Safe::Hole; @@ -714,6 +749,43 @@ sub evalstate { return $state; } +{ + my %mapalias_cache; + sub count_mapalias { + my ($value,$resid) = @_; + push(@{ $mapalias_cache{$value} }, $resid); + } + + sub get_mapalias_errors { + my $error_text; + foreach my $mapalias (sort(keys(%mapalias_cache))) { + next if (scalar(@{ $mapalias_cache{$mapalias} } ) == 1); + my $count; + my $which = + join('
  • ', + map { + my $id = $_; + if (exists($hash{'src_'.$id})) { + $count++; + } + my ($mapid) = split(/\./,$id); + &mt('[_1] in [_2]', $hash{'title_'.$id}, + + $hash{'title_'.$hash{'ids_'.$hash{'map_id_'.$mapid}}}); + } (@{ $mapalias_cache{$mapalias} })); + next if ($count < 2); + $error_text .= '
    '. + &mt('Error: Found the mapalias "[_1]" defined multiple times.', + $mapalias). + '
    '; + } + &clear_mapalias_count(); + return $error_text; + } + sub clear_mapalias_count { + undef(%mapalias_cache); + } +} 1; __END__