version 1.2, 2011/09/13 10:27:52
|
version 1.6, 2011/11/29 11:50:53
|
Line 28
|
Line 28
|
# |
# |
### |
### |
|
|
package lonmap; |
package Apache::lonmap; |
use strict; |
use strict; |
|
|
#------------- Required external modules. |
#------------- Required external modules. |
Line 40 use HTML::TokeParser;
|
Line 40 use HTML::TokeParser;
|
|
|
use LONCAPA; |
use LONCAPA; |
use Apache::lonnet; |
use Apache::lonnet; |
|
use Apache::lonlocal; |
|
|
|
use Data::Dumper; |
|
|
|
|
#------------- File scoped variables: |
#------------- File scoped variables: |
|
|
my $map_number = 1; # keep track of maps within the course. |
my $map_number = 0; # keep track of maps within the course. |
my $course_id; # Will be the id of the course being read in. |
my $course_id; # Will be the id of the course being read in. |
|
|
# |
# |
Line 66 my $retfrid;
|
Line 70 my $retfrid;
|
|
|
my $username; # User for whom the map is being read. |
my $username; # User for whom the map is being read. |
my $userdomain; # Domain the user lives in. |
my $userdomain; # Domain the user lives in. |
|
my $short_name; # Course shortname. |
my %mapalias_cache; # Keeps track of map aliases -> resources detects duplicates. |
my %mapalias_cache; # Keeps track of map aliases -> resources detects duplicates. |
|
my %cenv; # Course environment. |
|
|
#------------- Executable code: |
#------------- Executable code: |
|
|
Line 92 my %mapalias_cache; # Keeps track of ma
|
Line 98 my %mapalias_cache; # Keeps track of ma
|
|
|
sub simplify { |
sub simplify { |
my $expression=shift; |
my $expression=shift; |
my $prior = ''; # This is safe as a null expression is pretty optimal. |
|
|
|
while ($prior ne $expression) { |
|
$prior = $expression; # Stop when the substitutions below do nothing. |
|
# (0&1) = 1 |
# (0&1) = 1 |
$expression=~s/\(0\&([_\.\d]+)\)/$1/g; |
$expression=~s/\(0\&([_\.\d]+)\)/$1/g; |
# (8)=8 |
# (8)=8 |
Line 112 sub simplify {
|
Line 115 sub simplify {
|
# ((5&3)|(4&6))|(1&2)=(5&3)|(4&6)|(1&2) |
# ((5&3)|(4&6))|(1&2)=(5&3)|(4&6)|(1&2) |
$expression=~ |
$expression=~ |
s/\((\([_\.\d]+(?:\&[_\.\d]+)*\))((?:\|\([_\.\d]+(?:\&[_\.\d]+)*\))+)\)\|(\([_\.\d]+(?:\&[_\.\d]+)*\))/\($1$2\|$3\)/g; |
s/\((\([_\.\d]+(?:\&[_\.\d]+)*\))((?:\|\([_\.\d]+(?:\&[_\.\d]+)*\))+)\)\|(\([_\.\d]+(?:\&[_\.\d]+)*\))/\($1$2\|$3\)/g; |
} |
|
|
|
return $expression; |
return $expression; |
} |
} |
|
|
Line 149 sub merge_conditions {
|
Line 153 sub merge_conditions {
|
sub merge_hash { |
sub merge_hash { |
my ($parent, $key, $child) = @_; |
my ($parent, $key, $child) = @_; |
|
|
|
if ($key ne '') { |
|
$key .= '.'; # If we are prefixing, prefix then . |
|
} |
|
|
foreach my $childkey (keys (%$child)) { |
foreach my $childkey (keys (%$child)) { |
$parent->{$key . '.' . $childkey} = $child->{$childkey}; |
$parent->{$key . $childkey} = $child->{$childkey}; |
} |
} |
} |
} |
|
|
Line 308 sub versionerror {
|
Line 316 sub versionerror {
|
# Returns: |
# Returns: |
# URI with the version cut out. |
# URI with the version cut out. |
# |
# |
sub vesiontrack { |
sub versiontrack { |
my ($uri, $hash) = @_; |
my ($uri, $hash) = @_; |
|
|
|
|
Line 366 sub append_version {
|
Line 374 sub append_version {
|
return $uri; |
return $uri; |
|
|
} |
} |
|
#------------------------------------------------------------------------------ |
|
# |
|
# Misc. utilities that don't fit into the other classifications. |
|
|
|
# Determine if the specified user has an 'advanced' role in a course. |
|
# Parameters: |
|
# cenv - reference to a course environment. |
|
# username - Name of the user we care about. |
|
# domain - Domain in which the user is defined. |
|
# Returns: |
|
# 0 - User does not have an advanced role in the course. |
|
# 1 - User does have an advanced role in the course. |
|
# |
|
sub has_advanced_role { |
|
my ($username, $domain) = @_; |
|
|
|
my %adv_roles = &Apache::lonnet::get_course_adv_roles($short_name); |
|
my $merged_username = $username . ':' . $domain; |
|
foreach my $user (values %adv_roles) { |
|
if ($merged_username eq $user) { |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
#-------------------------------------------------------------------------------- |
#-------------------------------------------------------------------------------- |
# Post processing subs: |
# Post processing subs: |
sub hiddenurls { |
sub hiddenurls { |
my $hash = shift; |
my $hash = shift; |
|
|
|
my $uname = $hash->{'context.username'}; |
|
my $udom = $hash->{'context.userdom'}; |
|
my $courseid = $hash->{'context.courseid'}; |
|
|
my $randomoutentry=''; |
my $randomoutentry=''; |
foreach my $rid (keys %randompick) { |
foreach my $rid (keys %randompick) { |
my $rndpick=$randompick{$rid}; |
my $rndpick=$randompick{$rid}; |
Line 393 sub hiddenurls {
|
Line 431 sub hiddenurls {
|
# -------------------------------- randomly eliminate the ones that should stay |
# -------------------------------- randomly eliminate the ones that should stay |
my (undef,$id)=split(/\./,$rid); |
my (undef,$id)=split(/\./,$rid); |
if ($randompickseed{$rid}) { $id=$randompickseed{$rid}; } |
if ($randompickseed{$rid}) { $id=$randompickseed{$rid}; } |
my $rndseed=&Apache::lonnet::rndseed($id); # use id instead of symb |
my $rndseed=&Apache::lonnet::rndseed($id, $courseid, $udom, $uname, \%cenv); # use id instead of symb |
&Apache::lonnet::setup_random_from_rndseed($rndseed); |
&Apache::lonnet::setup_random_from_rndseed($rndseed); |
my @whichids=&Math::Random::random_permuted_index($#currentrids+1); |
my @whichids=&Math::Random::random_permuted_index($#currentrids+1); |
for (my $i=1;$i<=$rndpick;$i++) { $currentrids[$whichids[$i]]=''; } |
for (my $i=1;$i<=$rndpick;$i++) { $currentrids[$whichids[$i]]=''; } |
#&Apache::lonnet::logthis("$id,$rndseed,".join(':',@whichids)); |
|
# -------------------------------------------------------- delete the leftovers |
# -------------------------------------------------------- delete the leftovers |
for (my $k=0; $k<=$#currentrids; $k++) { |
for (my $k=0; $k<=$#currentrids; $k++) { |
if ($currentrids[$k]) { |
if ($currentrids[$k]) { |
$hash->{'randomout_'.$currentrids[$k]}=1; |
$hash->{'randomout_'.$currentrids[$k]}='1'; |
my ($mapid,$resid)=split(/\./,$currentrids[$k]); |
my ($mapid,$resid)=split(/\./,$currentrids[$k]); |
$randomoutentry.='&'. |
$randomoutentry.='&'. |
&Apache::lonnet::encode_symb($hash->{'map_id_'.$mapid}, |
&Apache::lonnet::encode_symb($hash->{'map_id_'.$mapid}, |
Line 413 sub hiddenurls {
|
Line 451 sub hiddenurls {
|
} |
} |
# ------------------------------ take care of explicitly hidden urls or folders |
# ------------------------------ take care of explicitly hidden urls or folders |
foreach my $rid (keys %hiddenurl) { |
foreach my $rid (keys %hiddenurl) { |
$hash->{'randomout_'.$rid}=1; |
$hash->{'randomout_'.$rid}='1'; |
my ($mapid,$resid)=split(/\./,$rid); |
my ($mapid,$resid)=split(/\./,$rid); |
$randomoutentry.='&'. |
$randomoutentry.='&'. |
&Apache::lonnet::encode_symb($hash->{'map_id_'.$mapid},$resid, |
&Apache::lonnet::encode_symb($hash->{'map_id_'.$mapid},$resid, |
Line 437 sub hiddenurls {
|
Line 475 sub hiddenurls {
|
# |
# |
|
|
sub accinit { |
sub accinit { |
my ($uri, $short, $fn, $hash)=@_; |
my ($uri, $short, $hash)=@_; |
my %acchash=(); |
my %acchash=(); |
my %captured=(); |
my %captured=(); |
my $condcounter=0; |
my $condcounter=0; |
Line 615 sub traceroute {
|
Line 653 sub traceroute {
|
$hash->{'map_start_'.$hash->{'src_'.$rid}}, |
$hash->{'map_start_'.$hash->{'src_'.$rid}}, |
$beenhere, |
$beenhere, |
$encflag || $encurl{$rid}, |
$encflag || $encurl{$rid}, |
$hdnflag || $hiddenurl{$rid}); |
$hdnflag || $hiddenurl{$rid}, $hash); |
} |
} |
} |
} |
|
|
Line 641 sub traceroute {
|
Line 679 sub traceroute {
|
} |
} |
# Recurse to resoruces that have to's to us. |
# Recurse to resoruces that have to's to us. |
$newsofar=&traceroute($further,$hash->{'goesto_'.$id},$beenhere, |
$newsofar=&traceroute($further,$hash->{'goesto_'.$id},$beenhere, |
$encflag,$hdnflag); |
$encflag,$hdnflag, $hash); |
} |
} |
} |
} |
} |
} |
Line 931 sub parse_resource {
|
Line 969 sub parse_resource {
|
|
|
if (($turi=~/\.sequence$/) || |
if (($turi=~/\.sequence$/) || |
($turi=~/\.page$/)) { |
($turi=~/\.page$/)) { |
$hash->{'is_map_'.$rid}=1; |
$hash->{'is_map_'.$rid}='1'; # String in lonuserstate. |
&read_map($turi,$rid, $hash); |
&read_map($turi,$rid, $hash); |
} |
} |
return $token->[2]->{'id'}; |
return $token->[2]->{'id'}; |
Line 969 sub make_link {
|
Line 1007 sub make_link {
|
my $linkid=$lpc.'.'.$linkpc; |
my $linkid=$lpc.'.'.$linkpc; |
my $goesto=$lpc.'.'.$to; |
my $goesto=$lpc.'.'.$to; |
my $comesfrom=$lpc.'.'.$from; |
my $comesfrom=$lpc.'.'.$from; |
my $undercond=0; |
my $undercond='0'; |
|
|
|
|
# If there is a condition, qualify it with the level counter. |
# If there is a condition, qualify it with the level counter. |
Line 1152 sub parse_mapalias_param {
|
Line 1190 sub parse_mapalias_param {
|
sub read_map { |
sub read_map { |
my ($uri, $parent_rid, $hash) = @_; |
my ($uri, $parent_rid, $hash) = @_; |
|
|
|
|
# Check for duplication: A map may only be included once. |
# Check for duplication: A map may only be included once. |
|
|
if($hash->{'map_pc_' . $uri}) { |
if($hash->{'map_pc_' . $uri}) { |
Line 1167 sub read_map {
|
Line 1206 sub read_map {
|
# map_pc_uri is the map number of the map with that URI. |
# map_pc_uri is the map number of the map with that URI. |
# map_id_$lmap_no is the URI for this map level. |
# map_id_$lmap_no is the URI for this map level. |
# |
# |
$hash->{'map_pc_' . $uri} = $lmap_no; |
$hash->{'map_pc_' . $uri} = "$lmap_no"; # string form in lonuserstate. |
$hash->{'map_id_' . $lmap_no} = $uri; |
$hash->{'map_id_' . $lmap_no} = "$uri"; |
|
|
# Create the path up to the top of the course. |
# Create the path up to the top of the course. |
# this is in 'map_hierarchy_mapno' that's a comma separated path down to us |
# this is in 'map_hierarchy_mapno' that's a comma separated path down to us |
Line 1191 sub read_map {
|
Line 1230 sub read_map {
|
# sorts of files that make sense for this sub |
# sorts of files that make sense for this sub |
|
|
my $filename = &Apache::lonnet::filelocation('', &append_version($uri, $hash)); |
my $filename = &Apache::lonnet::filelocation('', &append_version($uri, $hash)); |
|
|
|
|
my $ispage = ($filename =~/\.page$/); |
my $ispage = ($filename =~/\.page$/); |
unless ($ispage || ($filename =~ /\.sequence$/)) { |
unless ($ispage || ($filename =~ /\.sequence$/)) { |
|
&Apache::lonnet::logthis("invalid: $filename : $uri"); |
throw Error::Simple(&mt("<br />Invalid map: <tt>[_1]</tt>", $filename)); |
throw Error::Simple(&mt("<br />Invalid map: <tt>[_1]</tt>", $filename)); |
} |
} |
|
|
Line 1202 sub read_map {
|
Line 1244 sub read_map {
|
|
|
# Repcopy the file and get its contents...report errors if we can't |
# Repcopy the file and get its contents...report errors if we can't |
|
|
my $contents = &Apache::lonet::getfile($filename); |
my $contents = &Apache::lonnet::getfile($filename); |
if($contents eq -1) { |
if($contents eq -1) { |
throw Error::Simple(&mt('<br />Map not loaded: The file <tt>[_1]</tt> does not exist.', |
throw Error::Simple(&mt('<br />Map not loaded: The file <tt>[_1]</tt> does not exist.', |
$filename)); |
$filename)); |
Line 1271 sub read_map {
|
Line 1313 sub read_map {
|
# |
# |
|
|
if ($randomize) { |
if ($randomize) { |
if (!$env{'request.role.adv'}) { |
if (!&has_advanced_role($username, $userdomain) ) { |
my $seed; |
my $seed; |
|
|
# In the advanced role, the map's random seed |
# In the advanced role, the map's random seed |
Line 1293 sub read_map {
|
Line 1335 sub read_map {
|
} |
} |
|
|
|
|
my $rndseed=&Apache::lonnet::rndseed($seed, $username, $userdomain); |
my $rndseed=&Apache::lonnet::rndseed($seed, '', |
|
$userdomain, $username, |
|
\%cenv); |
|
|
|
|
&Apache::lonnet::setup_random_from_rndseed($rndseed); |
&Apache::lonnet::setup_random_from_rndseed($rndseed); |
|
|
# Take the set of map ids we have decoded and permute them to a |
# Take the set of map ids we have decoded and permute them to a |
Line 1301 sub read_map {
|
Line 1347 sub read_map {
|
# processing the randomorder parameter if it is set, not |
# processing the randomorder parameter if it is set, not |
# randompick. |
# randompick. |
|
|
@map_ids=&math::Random::random_permutation(@map_ids); |
@map_ids=&Math::Random::random_permutation(@map_ids); |
} |
} |
|
|
|
|
my $from = shift(@map_ids); |
my $from = shift(@map_ids); |
my $from_rid = $lmap_no.'.'.$from; |
my $from_rid = $lmap_no.'.'.$from; |
$hash->{'map_start_'.$uri} = $from_rid; |
$hash->{'map_start_'.$uri} = $from_rid; |
Line 1315 sub read_map {
|
Line 1359 sub read_map {
|
# if randomorder was set. This means that for an instructor to choose |
# if randomorder was set. This means that for an instructor to choose |
|
|
while (my $to = shift(@map_ids)) { |
while (my $to = shift(@map_ids)) { |
&make_link(++$linkpc,$lmap_no,$to,$from); |
&make_link(++$linkpc,$lmap_no,$to,$from, 0, $hash); |
my $to_rid = $lmap_no.'.'.$to; |
my $to_rid = $lmap_no.'.'.$to; |
$hash->{'type_'.$to_rid}='normal'; |
$hash->{'type_'.$to_rid}='normal'; |
$from = $to; |
$from = $to; |
Line 1326 sub read_map {
|
Line 1370 sub read_map {
|
$hash->{'type_'.$from_rid}='finish'; |
$hash->{'type_'.$from_rid}='finish'; |
} |
} |
|
|
|
|
# The last parsing pass parses the <mapalias> tags that associate a name |
# The last parsing pass parses the <mapalias> tags that associate a name |
# with resource ids. |
# with resource ids. |
|
|
Line 1360 sub read_map {
|
Line 1405 sub read_map {
|
# |
# |
# |
# |
sub loadmap { |
sub loadmap { |
my ($cnum, $cdom, $uname, $udom, $filepath, $target_hash) = @_; |
my ($cnum, $cdom, $uname, $udom, $target_hash) = @_; |
|
|
|
|
|
|
# Clear the auxillary hashes and the cond array. |
# Clear the auxillary hashes and the cond array. |
|
|
Line 1370 sub loadmap {
|
Line 1417 sub loadmap {
|
%encurl = (); |
%encurl = (); |
%hiddenurl = (); |
%hiddenurl = (); |
%parmhash = (); |
%parmhash = (); |
@cond = (); |
@cond = ('true:normal'); # Initial value for cond 0. |
$retfrid = ''; |
$retfrid = ''; |
|
$username = ''; |
|
$userdomain = ''; |
|
%mapalias_cache = (); |
|
%cenv = (); |
|
|
|
|
# |
# |
Line 1379 sub loadmap {
|
Line 1430 sub loadmap {
|
$username = $uname; |
$username = $uname; |
$userdomain = $udom; |
$userdomain = $udom; |
|
|
my $short_name = $cdom . $cnum; |
$short_name = $cdom .'/' . $cnum; |
|
my $retfurl; |
|
|
try { |
try { |
|
|
|
|
# Get the information we need about the course. |
# Get the information we need about the course. |
# Return without filling in anything if we can't get any info: |
# Return without filling in anything if we can't get any info: |
|
|
my %cenv = &Apache::lonnet::coursedescription($short_name, |
%cenv = &Apache::lonnet::coursedescription($short_name, |
{'freshen_cache' => 1, |
{'freshen_cache' => 1, |
'user' => $uname}); |
'user' => $uname}); |
unless ($cenv{'url'}) { |
|
&Apache::lonnet::logthis("lonmap::loadmap failed: $cnum/$cdom - did not get url"); |
unless ($cenv{'url'}) { |
return; |
&Apache::lonnet::logthis("lonmap::loadmap failed: $cnum/$cdom - did not get url"); |
} |
return; |
$course_id = $cdom . '.' . $cnum; # Long course id. |
} |
|
|
# Load the version information into the hash |
$course_id = $cdom . '_' . $cnum; # Long course id. |
|
|
|
# Load the version information into the hash |
|
|
|
|
&process_versions(\%cenv, $target_hash); |
&process_versions(\%cenv, $target_hash); |
|
|
|
|
Line 1409 sub loadmap {
|
Line 1463 sub loadmap {
|
|
|
$target_hash->{'src_0.0'} = &versiontrack($map_uri, $target_hash); |
$target_hash->{'src_0.0'} = &versiontrack($map_uri, $target_hash); |
$target_hash->{'title_0.0'} = &Apache::lonnet::metadata($course_uri, 'title'); |
$target_hash->{'title_0.0'} = &Apache::lonnet::metadata($course_uri, 'title'); |
|
if(!defined $target_hash->{'title_0.0'}) { |
|
$target_hash->{'title_0.0'} = ''; |
|
} |
$target_hash->{'ids_'.$map_uri} = '0.0'; |
$target_hash->{'ids_'.$map_uri} = '0.0'; |
$target_hash->{'is_map_0.0'} = 1; |
$target_hash->{'is_map_0.0'} = '1'; |
&read_map($course_uri, '0.0', &hash); |
|
|
# In some places we need a username a domain and the courseid...store that |
|
# in the target hash in the context.xxxx keys: |
|
|
|
$target_hash->{'context.username'} = $username; |
|
$target_hash->{'context.userdom'} = $userdomain; |
|
$target_hash->{'context.courseid'} = $course_id; |
|
|
|
|
|
&read_map($course_uri, '0.0', $target_hash); |
|
|
# |
# |
|
|
if (defined($target_hash->{'map_start_'.$map_uri})) { |
if (defined($target_hash->{'map_start_'.$map_uri})) { |
|
|
&traceroute('0',$target_hash->{'map_start_'.$course_uri},'&', $target_hash); |
&traceroute('0',$target_hash->{'map_start_'.$course_uri},'&', 0, 0, $target_hash); |
&accinit($course_uri, $short_name, $filepath, $target_hash); |
&accinit($course_uri, $short_name, $target_hash); |
&hiddenurls($target_hash); |
&hiddenurls($target_hash); |
} |
} |
my $errors = &get_mapalias_errors($target_hash); |
my $errors = &get_mapalias_errors($target_hash); |
Line 1438 sub loadmap {
|
Line 1504 sub loadmap {
|
$target_hash->{$type.&putinversion($url, $target_hash, $short_name)}=$value; |
$target_hash->{$type.&putinversion($url, $target_hash, $short_name)}=$value; |
} |
} |
} |
} |
|
# Mark necrypted URLS. |
|
|
|
foreach my $id (keys(%encurl)) { |
|
$target_hash->{'encrypted_'.$id}=1; |
|
} |
|
|
|
# Store first keys. |
|
|
|
$target_hash->{'first_rid'}=$retfrid; |
|
my ($mapid,$resid)=split(/\./,$retfrid); |
|
$target_hash->{'first_mapurl'}=$target_hash->{'map_id_'.$mapid}; |
|
my $symb=&Apache::lonnet::encode_symb($target_hash->{'map_id_'.$mapid}, |
|
$resid, |
|
$target_hash->{'src_'.$retfrid}); |
|
$retfurl=&add_get_param($target_hash->{'src_'.$retfrid},{ 'symb' => $symb }); |
|
if ($target_hash->{'encrypted_'.$retfrid}) { |
|
$retfurl=&Apache::lonenc::encrypted($retfurl, |
|
(&Apache::lonnet::allowed('adv') ne 'F')); |
|
} |
|
$target_hash->{'first_url'}=$retfurl; |
|
|
# Merge in the child hashes in case the caller wants that information as well. |
# Merge in the child hashes in case the caller wants that information as well. |
|
|
Line 1462 sub loadmap {
|
Line 1548 sub loadmap {
|
|
|
# |
# |
# Module initialization code: |
# Module initialization code: |
# |
# TODO: Fix the pod docs below. |
|
|
1; |
1; |
__END__ |
__END__ |