--- rat/lonpageflip.pm 2006/03/19 23:06:00 1.67
+++ rat/lonpageflip.pm 2022/10/19 00:03:12 1.112
@@ -2,7 +2,7 @@
#
# Page flip handler
#
-# $Id: lonpageflip.pm,v 1.67 2006/03/19 23:06:00 albertel Exp $
+# $Id: lonpageflip.pm,v 1.112 2022/10/19 00:03:12 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -27,11 +27,18 @@
# http://www.lon-capa.org/
#
+
+
package Apache::lonpageflip;
use strict;
+use LONCAPA;
use Apache::Constants qw(:common :http REDIRECT);
use Apache::lonnet;
+use Apache::loncommon();
+use Apache::lonnavmaps();
+use Apache::lonuserstate;
+use Apache::lonlocal;
use HTML::TokeParser;
use GDBM_File;
@@ -77,36 +84,135 @@ sub hash_src {
my ($mapid,$resid)=split(/\./,$id);
my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},
$resid,$hash{'src_'.$id});
+ my $anchor;
+ if ($hash{'ext_'.$id} eq 'true:') {
+ if ($hash{'src_'.$id} =~ /(\#.+)$/) {
+ $anchor = $1;
+ }
+ }
if ($hash{'encrypted_'.$id}) {
return (&Apache::lonenc::encrypted($hash{'src_'.$id}),
- &Apache::lonenc::encrypted($symb));
+ &Apache::lonenc::encrypted($symb),
+ $hash{'encrypted_'.$id},$anchor);
}
- return ($hash{'src_'.$id},$symb);
+ return ($hash{'src_'.$id},$symb,$hash{'encrypted_'.$id},$anchor);
}
-# Inputs are a url, adn a hash ref of
-# form name => value pairs
-# takes care of properly adding the form name elements and values to the
-# the url doing proper escaping of the values and joining with ? or & as
-# needed
-
-sub add_get_param {
- my ($url,$form_data) = @_;
- my $needs_question_mark = ($url !~ /\?/);
-
- while (my ($name,$value) = each(%$form_data)) {
- if ($needs_question_mark) {
- $url.='?';
- $needs_question_mark = 0;
- } else {
- $url.='&';
+sub move {
+ my ($next,$endupmap,$direction,$firstres) = @_;
+ my $safecount=0;
+ my $allowed=0;
+ my $deeplinkonly=0;
+ my $deeplinkchecked;
+ my $deeplink_login_pc;
+ my $prev=$next;
+ my ($prevmapid)=split(/\./,$next);
+ do {
+ ($next,$endupmap)=&get_next_possible_move($next,$endupmap,$direction);
+
+ my $url = $hash{'src_'.$next};
+ my ($mapid,$resid)=split(/\./,$next);
+ my $symb = &Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},
+ $resid,$url);
+ if ($url eq '' || $symb eq '') {
+ $allowed = 0;
+ } else {
+ my $nodeeplinkcheck = 0;
+ if ($hash{'is_map_'.$next}) {
+ $nodeeplinkcheck = 1;
+ }
+ my $priv = &Apache::lonnet::allowed('bre',$url,$symb,'','','','',$nodeeplinkcheck);
+ $allowed = (($priv eq 'F') || ($priv eq '2') || ($priv eq 'A'));
}
- $url.=$name.'='.&Apache::lonnet::escape($form_data->{$name});
- }
- return $url;
+ $deeplinkonly = 0;
+ if ($hash{'deeplinkonly_'.$next}) {
+ my ($value,$level) = map { &unescape($_); } split(/:/,$hash{'deeplinkonly_'.$next});
+ my ($state,$others,$listed,$scope,$protect) = split(/,/,$value);
+ unless (($state eq 'both') || ($hash{'is_map_'.$next})) {
+ if ($level eq 'resource') {
+ $deeplinkonly = 1;
+ } elsif ($level eq 'map') {
+ if ($scope eq 'rec') {
+ unless ($mapid == $prevmapid) {
+ unless ($deeplinkchecked) {
+ $deeplink_login_pc = &get_deeplink_login_pc();
+ $deeplinkchecked = 1;
+ }
+ if ($deeplink_login_pc) {
+ my $poss_map_pc;
+ if ($hash{'is_map_'.$next}) {
+ $poss_map_pc = $hash{'map_pc_'.$url};
+ } else {
+ $poss_map_pc = $hash{'map_pc_'.$hash{'map_id_'.$mapid}};
+ }
+ unless ($deeplink_login_pc == $poss_map_pc) {
+ unless (grep(/^$deeplink_login_pc$/,split(/,/,$hash{'map_hierarchy_'.$poss_map_pc}))) {
+ $deeplinkonly = 1;
+ }
+ }
+ } else {
+ $deeplinkonly = 1;
+ }
+ }
+ } elsif ($mapid != $prevmapid) {
+ $deeplinkonly = 1;
+ }
+ }
+ }
+ } elsif (($hash{'deeplinkonly_'.$prev}) && (!$firstres)) {
+ my ($value,$level) = map { &unescape($_); } split(/:/,$hash{'deeplinkonly_'.$prev});
+ my ($state,$others,$listed,$scope,$protect) = split(/,/,$value);
+ unless (($state eq 'both') || ($hash{'is_map_'.$prev})) {
+ if ($level eq 'resource') {
+ $deeplinkonly = 1;
+ } elsif ($level eq 'map') {
+ if ($scope eq 'rec') {
+ unless ($mapid == $prevmapid) {
+ unless ($deeplinkchecked) {
+ $deeplink_login_pc = &get_deeplink_login_pc();
+ $deeplinkchecked = 1;
+ }
+ if ($deeplink_login_pc) {
+ my $poss_map_pc;
+ if ($hash{'is_map_'.$prev}) {
+ $poss_map_pc = $hash{'map_pc_'.$url};
+ } else {
+ $poss_map_pc = $hash{'map_pc_'.$hash{'map_id_'.$mapid}};
+ }
+ unless ($deeplink_login_pc == $poss_map_pc) {
+ unless (grep(/^$deeplink_login_pc$/,split(/,/,$hash{'map_hierarchy_'.$poss_map_pc}))) {
+ $deeplinkonly = 1;
+ }
+ }
+ }
+ }
+ } else {
+ if ($mapid != $prevmapid) {
+ $deeplinkonly = 1;
+ }
+ }
+ }
+ }
+ }
+ $safecount++;
+ } while ( ($next)
+ && ($next!~/\,/)
+ && (
+ (!$hash{'src_'.$next})
+ || (
+ (!$env{'request.role.adv'})
+ && (($hash{'randomout_'.$next})
+ || ($deeplinkonly)
+ || ($hash{'deeplinkout_'.$next}))
+ )
+ || (!$allowed)
+ )
+ && ($safecount<10000));
+
+ return ($next,$endupmap);
}
-sub move {
+sub get_next_possible_move {
my ($rid,$mapurl,$direction)=@_;
my $startoutrid=$rid;
@@ -132,7 +238,7 @@ sub move {
}
if ($thiscond>$mincond) { $mincond=$thiscond; }
}
- }
+ }
foreach my $id (split(/\,/,$posnext)) {
my ($linkid,$condval)=split(/\:/,$id);
if ($condval>=$mincond) {
@@ -174,7 +280,7 @@ sub move {
}
if ($thiscond>$mincond) { $mincond=$thiscond; }
}
- }
+ }
foreach my $id (split(/\,/,$posnext)) {
my ($linkid,$condval)=split(/\:/,$id);
if ($condval>=$mincond) {
@@ -202,25 +308,137 @@ sub move {
return ($next,$mapurl);
}
-sub navlaunch {
- my ($r)=@_;
- &Apache::loncommon::content_type($r,'text/html');
- &Apache::loncommon::no_cache($r);
- $r->send_http_header;
- $r->print(&Apache::loncommon::start_page('Launched'));
- $r->print(<
Collapse external navigation window
-ENDNAV - $r->print(&Apache::loncommon::end_page()); + my $priv = &Apache::lonnet::allowed('bre',$url,$args{'symb'}); + my $allowed = (($priv eq 'F') || ($priv eq '2') || ($priv eq 'A')); + if (!$allowed) { +# Wow, we cannot see this ... move forward to the next one that we can see + my ($newrid,$newmap)=&move($hash{'first_rid'},$hash{'first_mapurl'},'forward',1); +# Build the new URL + if ($newrid eq '') { + $furl = '/adm/navmaps'; + } else { + my ($newmapid,$newresid)=split(/\./,$newrid); + my $symb=&Apache::lonnet::encode_symb($newmap,$newresid,$hash{'src_'.$newrid}); + $furl=&add_get_param($hash{'src_'.$newrid},{ 'symb' => $symb }); + if ($hash{'encrypted_'.$newrid}) { + $furl=&Apache::lonenc::encrypted($furl); + } + } + } + untie(%hash); + return $furl; + } else { + return '/adm/navmaps'; + } +} + +sub first_answerable_ressymb { + my $navmap = Apache::lonnavmaps::navmap->new; + return unless (ref($navmap)); + my $iterator = $navmap->getIterator(undef,undef,undef,1); + return unless (ref($iterator)); + my ($curRes,$result); + while ($curRes = $iterator->next()) { + if (ref($curRes) && $curRes->is_problem()) { + foreach my $part (@{$curRes->parts()}) { + if ($curRes->tries($part) < $curRes->maxtries($part)) { + $result = $curRes->link().'?symb='.$curRes->shown_symb(); + last; + } + } + } + } + if ($result) { + return $result; + } else { + return &first_accessible_resource(); + } +} + +sub check_http_req { + my ($srcref,$hostname) = @_; + return unless (ref($srcref) eq 'SCALAR'); + my $usehttp; + if ($env{'request.course.id'}) { + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + if (($$srcref =~ m{^\Q/public/$cdom/$cnum/syllabus\E($|\?)}) && + ($ENV{'SERVER_PORT'} == 443) && + ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://})) { + unless ((&Apache::lonnet::uses_sts()) || + (&Apache::lonnet::waf_allssl($hostname))) { + $$srcref .= (($$srcref =~/\?/)? '&':'?') . 'usehttp=1'; + $usehttp = 1; + } + } elsif (($$srcref =~ m{^\Q/adm/wrapper/ext/\E(?!https:)}) && + ($ENV{'SERVER_PORT'} == 443)) { + unless ((&Apache::lonnet::uses_sts()) || + (&Apache::lonnet::waf_allssl($hostname))) { + my ($url,$anchor) = ($$srcref =~ /^([^\#]+)(?:|(\#[^\#]+))$/); + $$srcref = $url . (($$srcref =~/\?/)? '&':'?') . 'usehttp=1' .$anchor; + $usehttp = 1; + } + } + } + return $usehttp; +} + +sub reinited_js { + my ($url,$cid,$timeout) = @_; + if (!$timeout) { + $timeout = 0; + } + return <<"END"; + +END +} + +sub get_deeplink_login_pc { + my $deeplink_login_pc; + if (($env{'request.deeplink.login'}) && ($env{'request.course.id'})) { + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $deeplink_symb = &Apache::loncommon::deeplink_login_symb($cnum,$cdom); + if ($deeplink_symb) { + my $loginmap; + if ($deeplink_symb =~ /\.(page|sequence)$/) { + $loginmap = &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($deeplink_symb))[2]); + } else { + $loginmap = &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($deeplink_symb))[0]); + } + $deeplink_login_pc = $hash{'map_pc_'.$loginmap}; + } + } + return $deeplink_login_pc; } + # ================================================================ Main Handler sub handler { @@ -237,95 +455,199 @@ sub handler { my %cachehash=(); my $multichoice=0; my %multichoicehash=(); - my ($redirecturl,$redirectsymb); + my %prog_state=(); + my ($redirecturl,$redirectsymb,$enc,$anchor,$deeplinklevel); my $next=''; + my $hostname = $r->hostname(); my @possibilities=(); &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['postdata']); if (($env{'form.postdata'})&&($env{'request.course.fn'})) { - $env{'form.postdata'}=~/(\w+)\:(.*)/; - my $direction=$1; - my $currenturl=$2; + my ($direction,$currenturl) = ($env{'form.postdata'}=~/(\w+)\:(.*)/); if ($currenturl=~m|^/enc/|) { - $currenturl=&Apache::lonenc::unencrypted($currenturl); + $currenturl=&Apache::lonenc::unencrypted($currenturl); } $currenturl=~s/\.\d+\.(\w+)$/\.$1/; + $currenturl=~s/^https?\:\/\///; + $currenturl=~s/^[^\/]+//; + my ($preupdatepos,$last,$reinitcheck); + if ($direction eq 'return') { + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', + &GDBM_READER(),0640)) { + $last=$hash{'last_known'}; + untie(%hash); + } + } elsif ($direction eq 'firstanswerable') { + my $furl = &first_answerable_ressymb(); + my $usehttp = &check_http_req(\$furl,$hostname); + if (($usehttp) && ($hostname ne '')) { + $furl='http://'.$hostname.$furl; + } else { + $furl=&Apache::lonnet::absolute_url().$furl; + } + &Apache::loncommon::content_type($r,'text/html'); + $r->header_out(Location => $furl); + return REDIRECT; + } elsif ($direction eq 'endplacement') { + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + $r->print(&Apache::lonplacementtest::showresult()); + return OK; + } + if ($env{'request.course.id'}) { + # Check if course needs to be re-initialized + my $loncaparev = $r->dir_config('lonVersion'); + ($reinitcheck,my @reinit) = &Apache::loncommon::needs_coursereinit($loncaparev); + if ($reinitcheck eq 'switch') { + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + $r->print(&Apache::loncommon::check_release_result(@reinit)); + return OK; + } + my ($cnum,$cdom); + if ($reinitcheck) { + $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + } + if (($reinitcheck eq 'main') || ($reinitcheck eq 'both')) { + $preupdatepos = &Apache::lonnet::symbread($currenturl); + unless ($direction eq 'return') { + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', + &GDBM_READER(),0640)) { + $last=$hash{'last_known'}; + untie(%hash); + } + } + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + $r->print(&Apache::loncommon::start_page('Content Changed')); + my $preamble = '$lt{'pick'}:
-
$lt{'titleheader'} | $lt{'type'} |
---|---|
'. @@ -461,31 +810,86 @@ ENDSTART } $r->print(' |
$lt{'explain'}
-ENDNONE + if ($reinitcheck) { + if (&Apache::loncommon::course_type() eq 'Community') { + $r->print( + &Apache::loncommon::start_page('Community Contents Updated')); + } else { + $r->print( + &Apache::loncommon::start_page('Course Contents Updated')); + } + $r->print(''.$lt{'expupdate'}.'
'
+ .$lt{'gonav'}.'
'.$lt{'deeplinkres'}.'
'); + } elsif ($deeplinklevel eq 'map') { + $r->print(''.$lt{'deeplinkmap'}.'
'); + } else { + $r->print(''.$lt{'explain'}.'
'); + } + } + } } - $r->print(<