--- loncom/lonmap.pm 2011/09/07 10:58:36 1.1 +++ loncom/lonmap.pm 2011/09/13 10:27:52 1.2 @@ -2,7 +2,7 @@ # # Read maps into a 'big hash'. # -# $Id: lonmap.pm,v 1.1 2011/09/07 10:58:36 foxr Exp $ +# $Id: lonmap.pm,v 1.2 2011/09/13 10:27:52 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -38,7 +38,7 @@ use Error qw(:try); use HTML::TokeParser; -use Apache::LONCAPA; +use LONCAPA; use Apache::lonnet; #------------- File scoped variables: @@ -56,8 +56,9 @@ my %randompickseed; my %randomorder; my %encurl; my %hiddenurl; +my %parmhash; my @cond; # Array of conditions. - +my $retfrid; # # Other stuff we make global (sigh) so that it does not need # to be passed around all the time: @@ -128,7 +129,7 @@ sub simplify { sub merge_conditions { my $hash = shift; - for (my $i = 0; i < scalar(@cond); i++) { + for (my $i = 0; $i < scalar(@cond); $i++) { $hash->{'condition' . '.' . $i} = $cond[$i]; } } @@ -181,7 +182,7 @@ sub count_mapalias { # result string.' # # Parameters: -# none +# hash - Reference to the hash we are trying t build up. # Implicit inputs # %mapalias - a hash that is indexed by map aliases and contains for each key # an array of the resource id's the alias 'points to'. @@ -191,6 +192,7 @@ sub count_mapalias { # # sub get_mapalias_errors { + my $hash = shift; my $error_text; foreach my $mapalias (sort(keys(%mapalias_cache))) { next if (scalar(@{ $mapalias_cache{$mapalias} } ) == 1); @@ -199,13 +201,13 @@ sub get_mapalias_errors { join('
  • ', map { my $id = $_; - if (exists($hash{'src_'.$id})) { + if (exists($hash->{'src_'.$id})) { $count++; } my ($mapid) = split(/\./,$id); &mt('Resource "[_1]"
    in Map "[_2]"', - $hash{'title_'.$id}, - $hash{'title_'.$hash{'ids_'.$hash{'map_id_'.$mapid}}}); + $hash->{'title_'.$id}, + $hash->{'title_'.$hash->{'ids_'.$hash->{'map_id_'.$mapid}}}); } (@{ $mapalias_cache{$mapalias} })); next if ($count < 2); $error_text .= '
    '. @@ -229,6 +231,31 @@ sub clear_mapalias_count { # # +# Put a version into a src element of a hash or url: +# +# Parameters: +# uri - URI into which the version must be added. +# hash - Reference to the hash being built up. +# short- Short coursename. +# + +sub putinversion { + my ($uri, $hash, $short) = @_; + my $key=$short.'_'.&Apache::lonnet::clutter($uri); + if ($hash->{'version_'.$uri}) { + my $version=$hash->{'version_'.$uri}; + if ($version eq 'mostrecent') { return $uri; } + if ($version eq &Apache::lonnet::getversion( + &Apache::lonnet::filelocation('',$uri))) + { return $uri; } + $uri=~s/\.(\w+)$/\.$version\.$1/; + } + &Apache::lonnet::do_cache_new('courseresversion',$key,&Apache::lonnet::declutter($uri),600); + return $uri; +} + + +# # Create hash entries for each version of the course. # Parameters: # $cenv - Reference to a course environment from lonnet::coursedescription. @@ -291,7 +318,7 @@ sub vesiontrack { unless ($hash->{'version_'.$uri}) { $hash->{'version_'.$uri}=$version; } elsif ($version!=$hash->{'version_'.$uri}) { - throw Error::Simple(&versionerror($uri,$hash{'version_'.$uri},$version)); + throw Error::Simple(&versionerror($uri, $hash->{'version_'.$uri}, $version)); } } return $uri; @@ -410,7 +437,7 @@ sub hiddenurls { # sub accinit { - my ($uri,$short,$fn)=@_; + my ($uri, $short, $fn, $hash)=@_; my %acchash=(); my %captured=(); my $condcounter=0; @@ -542,7 +569,7 @@ sub accinit { # new value indicating how far the map has been traversed (the sofar). # sub traceroute { - my ($sofar,$rid,$beenhere,$encflag,$hdnflag)=@_; + my ($sofar, $rid, $beenhere, $encflag, $hdnflag, $hash)=@_; my $newsofar=$sofar=simplify($sofar); unless ($beenhere=~/\&\Q$rid\E\&/) { @@ -608,7 +635,7 @@ sub traceroute { $further=simplify('('.'_'.$rid.')&('. $hash->{'condid_'.$hash->{'undercond_'.$id}}.')'); } else { - $errtext.=&mt('
    Undefined condition ID: [_1]',$hash->{'undercond_'.$id}); + my $errtext.=&mt('
    Undefined condition ID: [_1]',$hash->{'undercond_'.$id}); throw Error::Simple($errtext); } } @@ -1128,7 +1155,7 @@ sub read_map { # Check for duplication: A map may only be included once. if($hash->{'map_pc_' . $uri}) { - throw Error::Simple('Duplicate map: ' $uri); + throw Error::Simple('Duplicate map: ', $uri); } # count the map number and save it locally so that we don't lose it # when we recurse. @@ -1151,7 +1178,7 @@ sub read_map { my $parent_no = $1; # Parent's map number. if (defined($hash->{'map_hierarchy_' . $parent_no})) { $hash->{'map_hierarchy_' . $lmap_no} = - $hash->{'map_hierarchy_' . $parent_no} . ',' $parent_no; + $hash->{'map_hierarchy_' . $parent_no} . ',' . $parent_no; } else { # Only 1 level deep ..nothing to append to: @@ -1165,13 +1192,13 @@ sub read_map { my $filename = &Apache::lonnet::filelocation('', &append_version($uri, $hash)); my $ispage = ($filename =~/\.page$/); - unless ($ispage || ($filname =~ /\.sequence$/)) { + unless ($ispage || ($filename =~ /\.sequence$/)) { throw Error::Simple(&mt("
    Invalid map: [_1]", $filename)); } $filename =~ /\.(\w+)$/; - $hash->{'map_type_'.$lpc}=$1; + $hash->{'map_type_'.$lmap_no}=$1; # Repcopy the file and get its contents...report errors if we can't @@ -1192,7 +1219,7 @@ sub read_map { # tags.. this is because there is no body to a tag. # - my $parser = HTML::TokeParser->new($\contents); + my $parser = HTML::TokeParser->new(\$contents); $parser->attr_encoded(1); # Don't interpret entities in attributes (leave &xyz; alone). while (my $token = $parser->get_token()) { @@ -1207,7 +1234,7 @@ sub read_map { # resources, they are also not processed if random order is turned on. # - $parser = HTML::TokeParser->new($\contents); # no way to reset the existing parser + $parser = HTML::TokeParser->new(\$contents); # no way to reset the existing parser $parser->attr_encoded(1); my $linkpc=0; @@ -1220,7 +1247,7 @@ sub read_map { # Resource if ($token->[1] eq 'resource') { - my $resource_id = &parse_resource($token,$lpc,$ispage,$uri, $hash); + my $resource_id = &parse_resource($token,$lmap_no,$ispage,$uri, $hash); if (defined $resource_id) { push(@map_ids, $resource_id); } @@ -1228,14 +1255,14 @@ sub read_map { # Link } elsif ($token->[1] eq 'link' && !$randomize) { - &make_link(++$linkpc,$lpc,$token->[2]->{'to'}, + &make_link(++$linkpc,$lmap_no,$token->[2]->{'to'}, $token->[2]->{'from'}, $token->[2]->{'condition'}, $hash); # note ..condition may be undefined. # condition } elsif ($token->[1] eq 'condition' && !$randomize) { - &parse_condition($token,$lpc, $hash); + &parse_condition($token,$lmap_no, $hash); } } @@ -1279,7 +1306,7 @@ sub read_map { my $from = shift(@map_ids); - my $from_rid = $lpc.'.'.$from; + my $from_rid = $lmap_no.'.'.$from; $hash->{'map_start_'.$uri} = $from_rid; $hash->{'type_'.$from_rid}='start'; @@ -1288,8 +1315,8 @@ sub read_map { # if randomorder was set. This means that for an instructor to choose while (my $to = shift(@map_ids)) { - &make_link(++$linkpc,$lpc,$to,$from); - my $to_rid = $lpc.'.'.$to; + &make_link(++$linkpc,$lmap_no,$to,$from); + my $to_rid = $lmap_no.'.'.$to; $hash->{'type_'.$to_rid}='normal'; $from = $to; $from_rid = $to_rid; @@ -1308,7 +1335,7 @@ sub read_map { while (my $token = $parser->get_token) { next if ($token->[0] ne 'S'); if ($token->[1] eq 'param') { - &parse_mapalias_param($token,$lpc, $hash); + &parse_mapalias_param($token,$lmap_no, $hash); } } @@ -1342,8 +1369,11 @@ sub loadmap { %randompickseed = (); %encurl = (); %hiddenurl = (); + %parmhash = (); @cond = (); + $retfrid = ''; + # $username = $uname; @@ -1357,7 +1387,7 @@ sub loadmap { # Get the information we need about the course. # Return without filling in anything if we can't get any info: - my %cenv = &Apache::lonnet::coursedesription($short_name, + my %cenv = &Apache::lonnet::coursedescription($short_name, {'freshen_cache' => 1, 'user' => $uname}); unless ($cenv{'url'}) { @@ -1374,33 +1404,51 @@ sub loadmap { # Figure out the map filename's URI, and set up some starting points for the map. - $course_uri = $cenv->{'url'}; - $map_uri = &Apache::lonnet::clutter($course_uri); + my $course_uri = $cenv{'url'}; + my $map_uri = &Apache::lonnet::clutter($course_uri); $target_hash->{'src_0.0'} = &versiontrack($map_uri, $target_hash); $target_hash->{'title_0.0'} = &Apache::lonnet::metadata($course_uri, 'title'); - $target_hash->{'ids_'.$file_map_uri} = '0.0'; + $target_hash->{'ids_'.$map_uri} = '0.0'; $target_hash->{'is_map_0.0'} = 1; &read_map($course_uri, '0.0', &hash); # - if (defined($hash->{'map_start_'.$uri})) { + if (defined($target_hash->{'map_start_'.$map_uri})) { - &traceroute('0',$hash->{'map_start_'.$course_uri},'&', $hash); - &accinit($course_uri, $short_name, $fn, $hash); - &hiddenurls($hash); + &traceroute('0',$target_hash->{'map_start_'.$course_uri},'&', $target_hash); + &accinit($course_uri, $short_name, $filepath, $target_hash); + &hiddenurls($target_hash); + } + my $errors = &get_mapalias_errors($target_hash); + if ($errors ne "") { + throw Error::Simple("Map alias errors: ", $errors); + } + + # Put the versions in to src: + + foreach my $key (keys(%$target_hash)) { + if ($key =~ /^src_/) { + $target_hash->{$key} = + &putinversion($target_hash->{$key}, $target_hash, $short_name); + } elsif ($key =~ /^(map_(?:start|finish|pc)_)(.*)/) { + my ($type, $url) = ($1,$2); + my $value = $target_hash->{$key}; + $target_hash->{$type.&putinversion($url, $target_hash, $short_name)}=$value; + } } # Merge in the child hashes in case the caller wants that information as well. - &merge_hash($hash, 'randompick', \%randompick); - &merge_hash($hash, 'randompickseed', \%randompick); - &merge_hash($hash, 'randomorder', \%randomorder); - &merge_hash($hash, 'encurl', \%encurl); - &merge_hash($hash, 'hiddenurl', \%hiddenurl); - &merge_conditions($hash); + &merge_hash($target_hash, 'randompick', \%randompick); + &merge_hash($target_hash, 'randompickseed', \%randompick); + &merge_hash($target_hash, 'randomorder', \%randomorder); + &merge_hash($target_hash, 'encurl', \%encurl); + &merge_hash($target_hash, 'hiddenurl', \%hiddenurl); + &merge_hash($target_hash, 'param', \%parmhash); + &merge_conditions($target_hash); } otherwise { my $e = shift;