File:  [LON-CAPA] / rat / lonpageflip.pm
Revision 1.80.8.13.2.3: download - view: text, annotated - select for diffs
Fri Jan 20 23:34:08 2023 UTC (16 months, 2 weeks ago) by raeburn
Branches: version_2_11_4_msu
Diff to branchpoint 1.80.8.13: preferred, colored
- For 2.11.4 (modified)
  Include changes in 1.112, 1.113, 1.114

# The LearningOnline Network with CAPA
#
# Page flip handler
#
# $Id: lonpageflip.pm,v 1.80.8.13.2.3 2023/01/20 23:34:08 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# /home/httpd/html/adm/gpl.txt
#
# 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;

# ========================================================== Module Global Hash
  
my %hash;

sub cleanup {
    if (tied(%hash)){
	&Apache::lonnet::logthis('Cleanup pageflip: hash');
        unless (untie(%hash)) {
	    &Apache::lonnet::logthis('Failed cleanup pageflip: hash');
        }
    }
    return OK;
}

sub addrid {
    my ($current,$new,$condid)=@_;
    unless ($condid) { $condid=0; }

	if ($current) {
	    $current.=','.$new;
        } else {
            $current=''.$new;
        }

    return $current;
}

sub fullmove {
    my ($rid,$mapurl,$direction)=@_;
    if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db',
                        &GDBM_READER(),0640)) {
	($rid,$mapurl)=&move($rid,$mapurl,$direction);
        untie(%hash);
    }
    return($rid,$mapurl);
}

sub hash_src {
    my ($id)=@_;
    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),
                $hash{'encrypted_'.$id},$anchor);
    }
    return ($hash{'src_'.$id},$symb,$hash{'encrypted_'.$id},$anchor);
}

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'));
	}
        $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 get_next_possible_move {
    my ($rid,$mapurl,$direction)=@_;
    my $startoutrid=$rid;

    my $next='';

              my $mincond=1;
              my $posnext='';
              if ($direction eq 'forward') {
# --------------------------------------------------------------------- Forward
                  while ($hash{'type_'.$rid} eq 'finish') {
	             $rid=$hash{'ids_'.$hash{'map_id_'.(split(/\./,$rid))[0]}};
                  }
		  foreach my $id (split(/\,/,$hash{'to_'.$rid})) {
		     my $condition= $hash{'conditions_'.$hash{'goesto_'.$id}};
		     my $rescond  = &Apache::lonnet::docondval($condition);
		     my $linkcond = &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$id}});
		     my $thiscond = ($rescond<$linkcond)?$rescond:$linkcond;
		     if ($thiscond>=$mincond) {
		          if ($posnext) {
		             $posnext.=','.$id.':'.$thiscond;
                          } else {
                             $posnext=$id.':'.$thiscond;
		          }
                          if ($thiscond>$mincond) { $mincond=$thiscond; }
	              }
                  }
		  foreach my $id (split(/\,/,$posnext))  {
                      my ($linkid,$condval)=split(/\:/,$id);
                      if ($condval>=$mincond) {
		          $next=&addrid($next,$hash{'goesto_'.$linkid},
                                $hash{'condid_'.$hash{'undercond_'.$linkid}});
                      }
                  }
                  if ($hash{'is_map_'.$next}) {
# This jumps to the beginning of a new map (going down level)
                      if (
      $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'sequence') {
			  $mapurl=$hash{'src_'.$next};
			  $next=$hash{'map_start_'.$hash{'src_'.$next}};
                     } elsif (
# This jumps back up from an empty sequence, to a page up one level
                         $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'page') {
                         $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]};
                     }
                  } elsif 
                    ((split(/\./,$startoutrid))[0]!=(split(/\./,$next))[0]) {
# This comes up from a map (coming up one level);
		      $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]};
		  }
              } elsif ($direction eq 'back') {
# ------------------------------------------------------------------- Backwards
                 while ($hash{'type_'.$rid} eq 'start') {
	             $rid=$hash{'ids_'.$hash{'map_id_'.(split(/\./,$rid))[0]}};
		 }
		 foreach my $id (split(/\,/,$hash{'from_'.$rid})) {
		     my $condition= $hash{'conditions_'.$hash{'comesfrom_'.$id}};
		     my $rescond  = &Apache::lonnet::docondval($condition);
		     my $linkcond = &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$id}});
		     my $thiscond = ($rescond<$linkcond)?$rescond:$linkcond;
		     if ($thiscond>=$mincond) {
			 if ($posnext) {
		             $posnext.=','.$id.':'.$thiscond;
			 } else {
                             $posnext=$id.':'.$thiscond;
			 }
			 if ($thiscond>$mincond) { $mincond=$thiscond; }
		     }
		 }
		 foreach my $id (split(/\,/,$posnext)) {
		     my ($linkid,$condval)=split(/\:/,$id);
		     if ($condval>=$mincond) {
			 $next=&addrid($next,$hash{'comesfrom_'.$linkid},
				       $hash{'condid_'.$hash{'undercond_'.$linkid}});
		     }
		 }
                  if ($hash{'is_map_'.$next}) {
# This jumps to the end of a new map (going down one level)
                      if (
      $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'sequence') {
			  $mapurl=$hash{'src_'.$next};
			  $next=$hash{'map_finish_'.$hash{'src_'.$next}};
                      } elsif (
      $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'page') {
# This jumps back up from an empty sequence, to a page up one level
                          $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]};
                      }
                  } elsif 
                    ((split(/\./,$startoutrid))[0]!=(split(/\./,$next))[0]) {
# This comes back up from a map (going up one level);
		      $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]};
                  }
	      }
              return ($next,$mapurl);
}

sub first_accessible_resource {
    my $furl;
    if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db',
	    &GDBM_READER(),0640)) {
	$furl=$hash{'first_url'};
	my (%args,$url,$argstr);
	if ($furl =~ m{^/enc/}) {
	    ($url,$argstr) = split(/\?/,&Apache::lonenc::unencrypted($furl));
	} else {
	    ($url,$argstr) = split(/\?/,$furl);
	}
	foreach my $pair (split(/\&/,$argstr)) {
	    my ($name,$value) = split(/=/,$pair);
	    $args{&unescape($name)} = &unescape($value);
	}
        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 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";
<script type="text/javascript">
// <![CDATA[
setTimeout(function() {
    var newurl = '$url';
    if (document.getElementById('LC_update_$cid')) {
        document.getElementById('LC_update_$cid').style.display = 'none';
    }
    if ((newurl !== null) && (newurl !== '') && (newurl !== 'undefined')) {
        window.location.href = "$url";
    }
}, $timeout);
// ]]>
</script>
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 {
   my $r=shift;

# ------------------------------------------- Set document type for header only

  if ($r->header_only) {
      &Apache::loncommon::content_type($r,'text/html');
      $r->send_http_header;
      return OK;
  }

  my %cachehash=(); 
  my $multichoice=0;
  my %multichoicehash=();
  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'})) {
      my ($direction,$currenturl) = ($env{'form.postdata'}=~/(\w+)\:(.*)/);
      if ($currenturl=~m|^/enc/|) {
          $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);
          }
      }
      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 = '<div id="LC_update_'.$env{'request.course.id'}.'" class="LC_info">'.
                             '<br />'.
                             &mt('Your course session is being updated because of recent changes by course personnel.').
                             ' '.&mt('Please be patient').'.<br /></div>'.
                             '<div style="padding:0;clear:both;margin:0;border:0"></div>';
              %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,undef,$preamble);
              &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Updating course'));
              my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum");
              &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Finished!'));
              if ($ferr) {
                  &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
                  my $requrl = $r->uri;
                  $env{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
                  $env{'user.reinit'} = 1;
                  return HTTP_NOT_ACCEPTABLE;
              } else {
                  if ($last) {
                      my ($murl,$id,$fn)=&Apache::lonnet::decode_symb($last);
                      unless (&Apache::lonnet::symbverify($last,$fn)) {
                          undef($last);
                      }
                  }
              }
          }
          if (($reinitcheck eq 'both') || ($reinitcheck eq 'supp')) {
              my $possdel;
              if ($reinitcheck eq 'supp') {
                  $possdel = 1;
              }
              my ($supplemental,$refs_updated) = &Apache::loncommon::get_supplemental($cnum,$cdom,'',$possdel);
              unless ($refs_updated) {
                  &Apache::loncommon::set_supp_httprefs($cnum,$cdom,$supplemental);
              }
          }
      }
      if ($direction eq 'firstres') {
	  my $furl=&first_accessible_resource();
          my $usehttp = &check_http_req(\$furl,$hostname);
          if (($usehttp) && ($hostname ne '')) {
              $furl='http://'.$hostname.$furl;
          } else {
              $furl=&Apache::lonnet::absolute_url().$furl;
          }
          if ($reinitcheck eq 'update') {
              &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
              $r->print(&reinited_js($furl,$env{'request.course.id'},100));
              $r->print(&Apache::loncommon::end_page());
              return OK;
          } else {
	      &Apache::loncommon::content_type($r,'text/html');
	      $r->header_out(Location => $furl);
	      return REDIRECT;
          }
      }
      if ($direction eq 'return') {
# -------------------------------------------------------- Return to last known
         my ($newloc,$usehttp);
         if (($last) && (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db',
                        &GDBM_READER(),0640))) {
            my ($murl,$id,$fn)=&Apache::lonnet::decode_symb($last);
	    $id=$hash{'map_pc_'.&Apache::lonnet::clutter($murl)}.'.'.$id;
	    $newloc=$hash{'src_'.$id};
	    if ($newloc) {
                $usehttp = &check_http_req(\$newloc,$hostname);
                if ($hash{'encrypted_'.$id}) {
                    $newloc=&Apache::lonenc::encrypted($newloc);
                }
                if ($newloc =~ m{^(/adm/wrapper/ext/[^\#]+)(?:|(\#[^\#]+))$}) {
                    my ($url,$anchor) = ($1,$2);
                    if ($anchor) {
                        $newloc = $url.(($url=~/\?/)?'&':'?').'symb='.&escape($last).$anchor;
                    }
                }
	    } else {
		$newloc='/adm/navmaps';
	    }
            untie %hash;
         } else {
	    $newloc='/adm/navmaps';
         }
         if (($usehttp) && ($hostname ne '')) {
             $newloc='http://'.$hostname.$newloc;
         } else {
             $newloc=&Apache::lonnet::absolute_url().$newloc
         }
         if ($reinitcheck eq 'update') {
             $r->print(&reinited_js($newloc,$env{'request.course.id'},100));
             $r->print(&Apache::loncommon::end_page());
             return OK;
         } else {
             &Apache::loncommon::content_type($r,'text/html');
             $r->header_out(Location => $newloc);
             return REDIRECT;
         }
      }
#
# Is the current URL on the map? If not, start with last known URL
#

      unless (&Apache::lonnet::is_on_map($currenturl)) {
         if ($preupdatepos) {
             undef($preupdatepos);
         } elsif (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
                            &GDBM_READER(),0640)) {
             $last=$hash{'last_known'};
             untie(%hash);
         }
         if ($last) {
	     $currenturl=&Apache::lonnet::clutter((&Apache::lonnet::decode_symb($last))[2]);
	 } else {
             my $newloc = &Apache::lonnet::absolute_url().
                          '/adm/navmaps';
             if ($reinitcheck eq 'update') {
                 &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
                 $r->print(&reinited_js($newloc,$env{'request.course.id'},100));
                 $r->print(&Apache::loncommon::end_page());
                 return OK;
             } else {
                 &Apache::loncommon::content_type($r,'text/html');
	         $r->header_out(Location => $newloc);
	         return REDIRECT;
             }
         }
      }
# ------------------------------------------- Do we have any idea where we are?
      my $position;
      if ($preupdatepos) {
          $position = $preupdatepos;
      } else {
          $position=Apache::lonnet::symbread($currenturl);
      }
      if ($position) {
# ------------------------------------------------------------------------- Yes
	  my ($startoutmap,$mapnum,$thisurl)=&Apache::lonnet::decode_symb($position);
          $cachehash{$startoutmap}{$thisurl}=[$thisurl,$mapnum];
          $cachehash{$startoutmap}{'last_known'}=
                             [&Apache::lonnet::declutter($currenturl),$mapnum];

# ============================================================ Tie the big hash
          if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db',
                        &GDBM_READER(),0640)) {
              my $rid=$hash{'map_pc_'.&Apache::lonnet::clutter($startoutmap)}.
                      '.'.$mapnum;

# ------------------------------------------------- Move forward, backward, etc
              my $endupmap;
              ($next,$endupmap)=&move($rid,$startoutmap,$direction);
# -------------------------------------- Do we have one and only one empty URL?
# We are now at at least one non-empty URL
# ----------------------------------------------------- Check out possibilities
              if ($next) {
                  @possibilities=split(/\,/,$next);
                  if ($#possibilities==0) {
# ---------------------------------------------- Only one possibility, redirect
	              ($redirecturl,$redirectsymb,$enc,$anchor)=&hash_src($next);
                      $cachehash{$endupmap}{$redirecturl}=
			  [$redirecturl,(split(/\./,$next))[1]];
                  } else {
# ------------------------ There are multiple possibilities for a next resource
                      $multichoice=1;
		      foreach my $id (@possibilities) {
			  $multichoicehash{'src_'.$id}=$hash{'src_'.$id};
                          $multichoicehash{'title_'.$id}=$hash{'title_'.$id};
                          $multichoicehash{'type_'.$id}=$hash{'type_'.$id};
                          (my $first, my $second) = $id =~ /(\d+).(\d+)/;
                          my $symbSrc = Apache::lonnet::declutter($hash{'src_'.$id});
                          $multichoicehash{'symb_'.$id} = 
                              Apache::lonnet::declutter($hash{'map_id_'.$first}.'___'.
                                                        $second.'___'.$symbSrc);
                                                         
                          my ($choicemap,$choiceres)=split(/\./,$id);
			  my $map=&Apache::lonnet::declutter($hash{'src_'.$choicemap});
			  my $url=$multichoicehash{'src_'.$id};
                          $cachehash{$map}{$url}=[$url,$choiceres];
                      }
                  }
	      } else {
# -------------------------------------------------------------- No place to go
                  $multichoice=-1;
                  if ($position && $env{'request.deeplink.login'}) {
                      my ($map,$resid,$url) = &Apache::lonnet::decode_symb($position);
                      my $mapid = $hash{'map_pc_'.&Apache::lonnet::clutter($map)};
                      my $position_deeplink = $hash{'deeplinkonly_'.$mapid.'.'.$resid};
                      if ($position_deeplink) {
                          (my $value,$deeplinklevel) = map { &unescape($_); }
                                                       split(/:/,$position_deeplink);
                      }
                  }
              }
# ----------------- The program must come past this point to untie the big hash
	      untie(%hash);
# --------------------------------------------------------- Store position info
              $cachehash{$startoutmap}{'last_direction'}=[$direction,'notasymb'];
              foreach my $thismap (keys(%cachehash)) {
		  my $mapnum=$cachehash{$thismap}->{'mapnum'};
		  delete($cachehash{$thismap}->{'mapnum'});
		  &Apache::lonnet::symblist($thismap,
					    %{$cachehash{$thismap}});
	      }
# ============================================== Do not return before this line
              if ($redirecturl) {
# ----------------------------------------------------- There is a URL to go to
		  if ($direction eq 'forward') {
                     &Apache::lonnet::linklog($currenturl,$redirecturl);
		  }
		  if ($direction eq 'back') {
                     &Apache::lonnet::linklog($redirecturl,$currenturl);
		  }
# ------------------------------------- Check for and display critical messages
                  my ($redirect, $url) = &Apache::loncommon::critical_redirect(300,'flip');
                  unless ($redirect) {
                      my $usehttp = &check_http_req(\$redirecturl,$hostname);
                      if (($usehttp) && ($hostname ne '')) {
                          $url='http://'.$hostname.$redirecturl;
                      } else {
                          $url=&Apache::lonnet::absolute_url().$redirecturl;
                      }
                      my $addanchor;
                      if (($anchor ne '') && (!$enc || $env{'request.role.adv'})) {
                          $addanchor = 1;
                          $url =~ s/\#.+$//;
                      }
                      $url = &add_get_param($url, { 'symb' => $redirectsymb});
                      if ($addanchor) {
                          $url .= $anchor;
                      }
                  }
                  if ($reinitcheck eq 'update') {
                      &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
                      $r->print(&reinited_js($url,$env{'request.course.id'},100));
                      $r->print(&Apache::loncommon::end_page());
                      return OK;
                  } else {
                      &Apache::loncommon::content_type($r,'text/html');
                      $r->header_out(Location => $url);
                      return REDIRECT;
                  }
	      } else {
# --------------------------------------------------------- There was a problem
                  &Apache::loncommon::content_type($r,'text/html');
                  $r->send_http_header;
		  my %lt=&Apache::lonlocal::texthash('title' => 'End of Sequence',
                                                     'deeplink' => 'No link available',
                                                     'deeplinkres' =>
                                                     'Navigation to other content is unavailable when accessing content via deep-linking',
                                                     'deeplinkmap' =>
                                                     'You have reached the end of the sequence of available materials for access via deep-linking',
						     'explain' =>
						     'You have reached the end of the sequence of materials.',
						     'back' => 'Go Back',
						     'nav' => 'Course Contents',
						     'wherenext' =>
						     'There are several possibilities of where to go next',
						     'pick' =>
						     'Please click on the the resource you intend to access',
						     'titleheader' => 'Title',
						     'type' => 'Type',
                                                     'update' => 'Content updated',
                                                     'expupdate' => 'As a result of a recent update to the sequence of materials, it is not possible to complete the page flip.',
                                                     'gonav' => 'Go to the Contents page to select a resource to display.');
                  if (&Apache::loncommon::course_type() eq 'Community') {
                      $lt{'nav'} = &mt('Community Contents');
                  }
                  if ($#possibilities>0) {
		      my $start_page=
			  &Apache::loncommon::start_page('Multiple Resources');
                     $r->print(<<ENDSTART);
$start_page
<h3>$lt{'wherenext'}</h3>
<p>
$lt{'pick'}:
<p>
<table border="2">
<tr><th>$lt{'titleheader'}</th><th>$lt{'type'}</th></tr>
ENDSTART
                     foreach my $id (@possibilities) {
                        my $src = $multichoicehash{'src_'.$id};
                        my $usehttp = &check_http_req(\$src,$hostname);
                        if (($usehttp) && ($hostname ne '')) {
                            $src = 'http://'.$hostname.$src;
                        }
                        $r->print(
                              '<tr><td><a href="'.
				  &add_get_param($src,
						 {'symb' =>
						      $multichoicehash{'symb_'.$id},
						  }).'">'.
                              $multichoicehash{'title_'.$id}.
                              '</a></td><td>'.$multichoicehash{'type_'.$id}.
			      '</td></tr>');
                     }
                     $r->print('</table>');
                  } else {
                      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('<h2>'.$lt{'update'}.'</h2>'
                                  .'<p>'.$lt{'expupdate'}.'<br />'
                                  .$lt{'gonav'}.'</p>');
                      } else {
                          $r->print(
                              &Apache::loncommon::start_page('No Resource'));
                          if ($deeplinklevel eq 'resource') {
                              $r->print('<h2>'.$lt{'deeplink'}.'</h2>'
                                       .'<p>'.$lt{'deeplinkres'}.'</p>');
                          } elsif ($deeplinklevel eq 'map') {
                              $r->print('<h2>'.$lt{'title'}.'</h2>'
                                       .'<p>'.$lt{'deeplinkmap'}.'</p>');
                          } else {
                              $r->print('<h2>'.$lt{'title'}.'</h2>'
                                       .'<p>'.$lt{'explain'}.'</p>');
                          }
                      }
		  }
                  if ($deeplinklevel) {
                      $r->print(
                          &Apache::lonhtmlcommon::actionbox(
                              ['<a href="/adm/flip?postdata=return:">'.$lt{'back'}.'</a>']));
                  } elsif ((!@possibilities) && ($reinitcheck))  {
                      $r->print(
                          &Apache::lonhtmlcommon::actionbox(
                              ['<a href="/adm/navmaps">'.$lt{'nav'}.'</a></li>'
                              ]));
                  } else {
                      $r->print(
                          &Apache::lonhtmlcommon::actionbox(
                              ['<a href="/adm/flip?postdata=return:">'.$lt{'back'}.'</a></li>',
                               '<a href="/adm/navmaps">'.$lt{'nav'}.'</a></li>'
                              ]));
                  }
                  $r->print(&Apache::loncommon::end_page());
      
                  return OK;
	      }
	  } else {
# ------------------------------------------------- Problem, could not tie hash
              if ($reinitcheck eq 'update') {
                  &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
                  $r->print(&Apache::loncommon::end_page());
              }
              $env{'user.error.msg'}="/adm/flip:bre:0:1:Course Data Missing";
              return HTTP_NOT_ACCEPTABLE; 
          }
      } else {
# ---------------------------------------- No, could not determine where we are
          my $newloc = '/adm/ambiguous';
          if ($reinitcheck eq 'update') {
              &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
              $r->print(&reinited_js($newloc,$env{'request.course.id'},100));
              $r->print(&Apache::loncommon::end_page());
          } else {
	      $r->internal_redirect($newloc);
          }
          return OK;
      }
  } else {
# -------------------------- Class was not initialized or page fliped strangely
      $env{'user.error.msg'}="/adm/flip:bre:0:0:Choose Course";
      return HTTP_NOT_ACCEPTABLE; 
  } 
}

1;
__END__

=pod

=head1 NAME

Apache::lonpageflip

=head1 SYNOPSIS

Deals with forward, backward, and other page flips.

This is part of the LearningOnline Network with CAPA project
described at http://www.lon-capa.org.

=head1 OVERVIEW

(empty)

=head1 SUBROUTINES

=over cleanup()

=item addrid()

=item fullmove()

=item hash_src()

=item move()

=item get_next_possible_move()

=item first_accessible_resource()

=item handler()

=back

=cut







FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.