[LON-CAPA-cvs] cvs: loncom/auth lonacc.pm loncom/interface loncommon.pm lonnavmaps.pm lonquickgrades.pm loncom/lonnet/perl lonnet.pm rat lonpageflip.pm lonsequence.pm lonuserstate.pm

raeburn raeburn at source.lon-capa.org
Mon Jul 19 13:32:06 EDT 2021


raeburn		Mon Jul 19 13:32:06 2021 EDT

  Modified files:              
    /rat	lonuserstate.pm lonpageflip.pm lonsequence.pm 
    /loncom/auth	lonacc.pm 
    /loncom/interface	loncommon.pm lonnavmaps.pm lonquickgrades.pm 
    /loncom/lonnet/perl	lonnet.pm 
  Log:
  - Bug 6907 Content in a course can be set to be deep-link only.
    If initial access is via a deep-link (/tiny/$domain/$uniqueid), and
    target folder/resource is deep-link only, access to resources, menus,
    and items listed in Course Contents controlled by deeplink parameter value.
  
-------------- next part --------------
Index: rat/lonuserstate.pm
diff -u rat/lonuserstate.pm:1.163 rat/lonuserstate.pm:1.164
--- rat/lonuserstate.pm:1.163	Thu Apr 29 10:54:36 2021
+++ rat/lonuserstate.pm	Mon Jul 19 11:48:25 2021
@@ -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.163 2021/04/29 14:54:36 raeburn Exp $
+# $Id: lonuserstate.pm,v 1.164 2021/07/19 15:48:25 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -62,7 +62,7 @@
 my %randomizationcode; # code used to grade folder for bubblesheet exam 
 my %encurl; # URLs in this folder are supposed to be encrypted
 my %hiddenurl; # this URL (or complete folder) is supposed to be hidden
-my %deeplinkonly; # this URL (or complete folder) is deep-link only
+my %deeplinkout; # this URL (or complete folder) unavailable in deep-link session
 my %rescount; # count of unhidden items in each map
 my %mapcount; # count of unhidden maps in each map
 
@@ -905,7 +905,7 @@
 #    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,$cid)=@_;
     my $newsofar=$sofar=simplify($sofar);
 
     unless ($beenhere=~/\&\Q$rid\E\&/) {
@@ -928,13 +928,30 @@
 	    && ($hash{'src_'.$rid}!~/\.sequence$/)) {
 	    $retfrid=$rid;
 	}
-        my @deeplink=&Apache::lonnet::EXT('resource.0.deeplink',$symb);
-        unless ((@deeplink == 0) || ($deeplink[0] eq 'full')) {
-            $deeplinkonly{$rid}=join(':', at deeplink);
-            if ($deeplink[1] eq 'map') {
-                my $parent = (split(/\,/,$hash{'map_hierarchy_'.$mapid}))[-1];
-                $deeplinkonly{"$parent.$mapid"}=$deeplinkonly{$rid};
+
+        my (@deeplink, at recurseup);
+        if ($hash{'is_map_'.$rid}) {
+            my ($cdom,$cnum) = split(/_/,$cid);
+            my $mapsrc = $hash{'src_'.$rid};
+            my $map_pc = $hash{'map_pc_'.$mapsrc};
+            my @pcs = split(/,/,$hash{'map_hierarchy_'.$map_pc});
+            shift(@pcs);
+            @recurseup = map { &Apache::lonnet::declutter($hash{'map_id_'.$_}) } reverse(@pcs);
+            my $mapname = &Apache::lonnet::declutter(&Apache::lonnet::deversion($mapsrc));
+            my $deeplinkval = &get_mapparam($env{'user.name'},$env{'user.domain'},$cnum,$cdom,
+                                            $rid,$mapname,'0.deeplink',\@recurseup);
+            if ($deeplinkval ne '') {
+                @deeplink = ($deeplinkval,'map');
             }
+        } else {
+            my @pcs = split(/,/,$hash{'map_hierarchy_'.$mapid});
+            shift(@pcs);
+            @recurseup = map { &Apache::lonnet::declutter($hash{'map_id_'.$_}) } reverse(@pcs);
+            @deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$symb,'','','','',$cid,\@recurseup);
+        }
+        unless (@deeplink < 2) {
+            my ($listed,$scope,$access) = split(/,/,$deeplink[0]);
+            $hash{'deeplinkonly_'.$rid}=join(':', at deeplink);
         }
 
 	if (defined($hash{'conditions_'.$rid})) {
@@ -958,7 +975,8 @@
 				$hash{'map_start_'.$hash{'src_'.$rid}},
 				$beenhere,
 				$encflag || $encurl{$rid},
-				$hdnflag || $hiddenurl{$rid});
+				$hdnflag || $hiddenurl{$rid},
+                                $cid);
 	    }
 	}
 
@@ -985,7 +1003,7 @@
                 }
 		#  Recurse to resoruces that have to's to us.
                 $newsofar=&traceroute($further,$hash{'goesto_'.$id},$beenhere,
-				      $encflag,$hdnflag);
+				      $encflag,$hdnflag,$cid);
 	    }
 	}
     }
@@ -1182,17 +1200,34 @@
     }
 }
 
+sub deeplinkouts {
+    my $deeplinkoutentry;
+    foreach my $rid (keys(%deeplinkout)) {
+        $hash{'deeplinkout_'.$rid}=1;
+        my ($mapid,$resid)=split(/\./,$rid);
+        $deeplinkoutentry.='&'.
+            &Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,
+                                         $hash{'src_'.$rid}).'&';
+    }
+# --------------------------------------- append deeplinkout entry to environment
+    if ($deeplinkoutentry) {
+        &Apache::lonnet::appenv({'acc.deeplinkout' => $deeplinkoutentry});
+    }
+}
+
 # -------------------------------------- populate big hash with map breadcrumbs
 
 # Create map_breadcrumbs_$pc from map_hierarchy_$pc by omitting intermediate
 # maps not shown in Course Contents table.
 
 sub mapcrumbs {
+    my ($cid) = @_;
     foreach my $key (keys(%rescount)) {
         if ($hash{'map_hierarchy_'.$key}) {
             my $skipnext = 0;
             foreach my $id (split(/,/,$hash{'map_hierarchy_'.$key}),$key) {
-                unless ($skipnext) {
+                my $rid = $hash{'ids_'.$hash{'map_id_'.$id}};
+                unless (($skipnext) || (!&is_advanced($cid) && $hash{'deeplinkout_'.$rid})) {
                     $hash{'map_breadcrumbs_'.$key} .= "$id,";
                 }
                 unless (($id == 0) || ($id == 1)) {
@@ -1251,7 +1286,7 @@
     undef %randomizationcode;
     undef %hiddenurl;
     undef %encurl;
-    undef %deeplinkonly;
+    undef %deeplinkout;
     undef %rescount;
     undef %mapcount;
     $retfrid='';
@@ -1400,7 +1435,7 @@
         undef %randomizationcode;
         undef %hiddenurl;
         undef %encurl;
-        undef %deeplinkonly;
+        undef %deeplinkout;
         undef %rescount;
         undef %mapcount;
         $errtext='';
@@ -1509,7 +1544,6 @@
     # Load the map.. note that loadmap may implicitly recurse if the map contains 
     # sub-maps.
 
-
     &loadmap($uri,'0.0',$short);
 
     #  The code below only executes if there is a starting point for the map>
@@ -1522,10 +1556,9 @@
                                  "request.course.uri" => $uri,
                                  "request.course.tied" => time});
         $env{'request.course.id'}=$short;
-        &traceroute('0',$hash{'map_start_'.$uri},'&');
+        &traceroute('0',$hash{'map_start_'.$uri},'&','','',$short);
         &accinit($uri,$short,$fn);
         &hiddenurls();
-        &mapcrumbs();
     }
     $errtext .= &get_mapalias_errors();
 # ------------------------------------------------------- Put versions into src
@@ -1543,10 +1576,6 @@
 #           $hash{'src_'.$id}=&Apache::lonenc::encrypted($hash{'src_'.$id});
         $hash{'encrypted_'.$id}=1;
     }
-# ------------------------------------------------------------ Deep-linked URLs
-    foreach my $id (keys(%deeplinkonly)) {
-        $hash{'deeplinkonly_'.$id}=$deeplinkonly{$id};
-    }
 # ----------------------------------------------- Close hashes to finally store
 # --------------------------------- Routine must pass this point, no early outs
     $hash{'first_rid'}=$retfrid;
@@ -1569,6 +1598,70 @@
                                      "Could not write statemap $fn for $uri.</font>");
         }
     }
+
+    # Was initial access via a deep-link?
+    my ($cdom,$cnum) = split(/_/,$short);
+    if (($cdom ne '') && ($env{'request.deeplink.login'} ne '')) {
+        my $deeplink_symb = &Apache::loncommon::deeplink_login_symb($cnum,$cdom);
+        if ($deeplink_symb) {
+            my ($loginrid,$deeplink_login_pc,$login_hierarchy);
+            my ($map,$resid,$url) = &Apache::lonnet::decode_symb($deeplink_symb);
+            $loginrid = $hash{'map_pc_'.&Apache::lonnet::clutter($map)}.'.'.$resid;
+            if ($deeplink_symb =~ /\.(page|sequence)$/) {
+                $deeplink_login_pc = $hash{'map_pc_'.&Apache::lonnet::clutter($url)};
+            } else {
+                $deeplink_login_pc = $hash{'map_pc_'.&Apache::lonnet::clutter($map)};
+            }
+            my $deeplink;
+            if ($hash{'deeplinkonly_'.$loginrid} ne '') {
+                $deeplink = $hash{'deeplinkonly_'.$loginrid};
+            }
+            if ($deeplink) {
+                my ($listed,$scope,$access) = split(/,/,$deeplink);
+                my $exclude = 1;
+                if ($exclude) {
+                    my @recfolders;
+                    if ($scope eq 'rec') {
+                        foreach my $key (keys(%hash)) {
+                            if ($key=~/^map_hierarchy_(\d+)$/) {
+                                my $mpc = $1;
+                                my @ids = split(/,/,$hash{$key});
+                                if (grep(/^$deeplink_login_pc$/, at ids)) {
+                                    my $idx;
+                                    foreach my $mapid (@ids) {
+                                        if ($idx) {
+                                            push(@recfolders,$mapid);
+                                        } elsif ($mapid == $deeplink_login_pc) {
+                                            push(@recfolders,$mapid);
+                                            $idx = $mapid;
+                                        }
+                                    }
+                                    push(@recfolders,$mpc);
+                                }
+                            }
+                        }
+                    }
+                    foreach my $key (keys(%hash)) {
+                        if ($key=~/^src_(.+)$/) {
+                            my $rid = $1;
+                            next if ($rid eq '0.0');
+                            next if ($rid eq $loginrid);
+                            if ($scope ne 'res') {
+                                my $mapid = (split(/\./,$rid))[0];
+                                next if ($mapid eq $deeplink_login_pc);
+                                if ($scope eq 'rec') {
+                                    next if (grep(/^$mapid$/, at recfolders));
+                                }
+                            }
+                            $deeplinkout{$rid} = 1;
+                        }
+                    }
+                }
+            }
+            &deeplinkouts();
+        }
+    }
+    &mapcrumbs();
     return $gotstate;
 }
 
@@ -1630,6 +1723,181 @@
     return $state;
 }
 
+sub get_mapparam {
+    my ($uname,$udom,$cnum,$cdom,$rid,$mapname,$what,$recurseupref) = @_;
+    unless ($mapname) { return; }
+
+# ------------------------------------------------- Get coursedata (if present)
+    my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
+    if (!ref($courseopt)) {
+        undef($courseopt);
+    }
+
+# --------------------------------------------------- Get userdata (if present)
+    my $useropt=&Apache::lonnet::get_userresdata($uname,$udom);
+    if (!ref($useropt)) {
+        undef($useropt);
+    }
+
+    my @recurseup;
+    if (ref($recurseupref) eq 'ARRAY') {
+        @recurseup = @{$recurseupref};
+    }
+
+    # Get the section if there is one.
+
+    my $cid = $cdom.'_'.$cnum;
+    my $csec=$env{'request.course.sec'};
+    my $cgroup='';
+    my @cgrps=split(/:/,$env{'request.course.groups'});
+    if (@cgrps > 0) {
+        @cgrps = sort(@cgrps);
+        $cgroup = $cgrps[0];
+    }
+
+    my $rwhat=$what;
+    $what=~s/^parameter\_//;
+    $what=~s/\_/\./;
+
+    # Build the hash keys for the lookup:
+
+    my $mapparm=$mapname.'___(all).'.$what;
+    my $recurseparm=$mapname.'___(rec).'.$what;
+    my $usercourseprefix=$cid;
+
+    my $grplevelm    = "$usercourseprefix.[$cgroup].$mapparm";
+    my $seclevelm    = "$usercourseprefix.[$csec].$mapparm";
+    my $courselevelm = "$usercourseprefix.$mapparm";
+
+    my $grpleveli    = "$usercourseprefix.[$cgroup].$recurseparm";
+    my $secleveli    = "$usercourseprefix.[$csec].$recurseparm";
+    my $courseleveli = "$usercourseprefix.$recurseparm";
+
+    # Check per user
+
+    if ($uname and defined($useropt)) {
+        if (defined($$useropt{$courselevelm})) {
+            return $$useropt{$courselevelm};
+        }
+        if (defined($$useropt{$courseleveli})) {
+            return $$useropt{$courseleveli};
+        }
+        foreach my $item (@recurseup) {
+            my $norecursechk=$usercourseprefix.'.'.$item.'___(all).'.$what;
+            if (defined($$useropt{$norecursechk})) {
+                if ($what =~ /\.(encrypturl|hiddenresource)$/) {
+                    return $$useropt{$norecursechk};
+                } else {
+                    last;
+                }
+            }
+            my $recursechk=$usercourseprefix.'.'.$item.'___(rec).'.$what;
+            if (defined($$useropt{$recursechk})) {
+                return $$useropt{$recursechk};
+            }
+        }
+    }
+
+    # Check course -- group
+
+    if ($cgroup ne '' and defined ($courseopt)) {
+        if (defined($$courseopt{$grplevelm})) {
+            return $$courseopt{$grplevelm};
+        }
+        if (defined($$courseopt{$grpleveli})) {
+            return $$courseopt{$grpleveli};
+        }
+        foreach my $item (@recurseup) {
+            my $norecursechk=$usercourseprefix.'.['.$cgroup.'].'.$item.'___(all).'.$what;
+            if (defined($$courseopt{$norecursechk})) {
+                if ($what =~ /\.(encrypturl|hiddenresource)$/) {
+                    return $$courseopt{$norecursechk};
+                } else {
+                    last;
+                }
+            }
+            my $recursechk=$usercourseprefix.'.['.$cgroup.'].'.$item.'___(rec).'.$what;
+            if (defined($$courseopt{$recursechk})) {
+                return $$courseopt{$recursechk};
+            }
+        }
+    }
+
+    # Check course -- section
+
+    if ($csec ne '' and defined($courseopt)) {
+        if (defined($$courseopt{$seclevelm})) {
+            return $$courseopt{$seclevelm};
+        }
+        if (defined($$courseopt{$secleveli})) {
+            return $$courseopt{$secleveli};
+        }
+        foreach my $item (@recurseup) {
+            my $norecursechk=$usercourseprefix.'.['.$csec.'].'.$item.'___(all).'.$what;
+            if (defined($$courseopt{$norecursechk})) {
+                if ($what =~ /\.(encrypturl|hiddenresource)$/) {
+                    return $$courseopt{$norecursechk};
+                } else {
+                    last;
+                }
+            }
+            my $recursechk=$usercourseprefix.'.['.$csec.'].'.$item.'___(rec).'.$what;
+            if (defined($$courseopt{$recursechk})) {
+                return $$courseopt{$recursechk};
+            }
+        }
+    }
+
+    # Check the map parameters themselves:
+
+    if ($hash{'param_'.$rid}) {
+        my @items = split(/\&/,$hash{'param_'.$rid});
+        my $thisparm;
+        foreach my $item (@items) {
+            my ($esctype,$escname,$escvalue) = ($item =~ /^([^:]+):([^=]+)=(.*)$/);
+            my $name = &unescape($escname);
+            my $value = &unescape($escvalue);
+            if ($name eq $what) {
+                $thisparm = $value;
+                last;
+            }
+        }
+        if (defined($thisparm)) {
+            return $thisparm;
+        }
+    }
+
+   # Additional course parameters:
+
+    if (defined($courseopt)) {
+        if (defined($$courseopt{$courselevelm})) {
+            return $$courseopt{$courselevelm};
+        }
+
+        if (defined($$courseopt{$courseleveli})) {
+            return $$courseopt{$courseleveli};
+        }
+
+        if (@recurseup) {
+            foreach my $item (@recurseup) {
+                my $norecursechk=$usercourseprefix.'.'.$item.'___(all).'.$what;
+                if (defined($$courseopt{$norecursechk})) {
+                    if ($what =~ /\.(encrypturl|hiddenresource)$/) {
+                        return $$courseopt{$norecursechk};
+                    } else {
+                        last;
+                    }
+                }
+                my $recursechk=$usercourseprefix.'.'.$item.'___(rec).'.$what;
+                if (defined($$courseopt{$recursechk})) {
+                    return $$courseopt{$recursechk};
+                }
+            }
+        }
+    }
+    return undef;
+}
+
 #  This block seems to have code to manage/detect doubly defined
 #  aliases in maps.
 
Index: rat/lonpageflip.pm
diff -u rat/lonpageflip.pm:1.105 rat/lonpageflip.pm:1.106
--- rat/lonpageflip.pm:1.105	Mon Jul 19 10:26:40 2021
+++ rat/lonpageflip.pm	Mon Jul 19 11:48:25 2021
@@ -2,7 +2,7 @@
 #
 # Page flip handler
 #
-# $Id: lonpageflip.pm,v 1.105 2021/07/19 14:26:40 raeburn Exp $
+# $Id: lonpageflip.pm,v 1.106 2021/07/19 15:48:25 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -103,6 +103,8 @@
     my $safecount=0;
     my $allowed=0;
     my $deeplinkonly=0;
+    my $deeplinkchecked;
+    my $deeplink_login_pc;
     my $prev=$next;
     my ($prevmapid)=split(/\./,$next);
     do {
@@ -115,26 +117,81 @@
 	if ($url eq '' || $symb eq '') {
 	    $allowed = 0;
 	} else {
-	    my $priv = &Apache::lonnet::allowed('bre',$url,$symb);
+            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) = split(/:/,$hash{'deeplinkonly_'.$next});
-            if ($level eq 'resource') {
-                $deeplinkonly = 1;
-            } elsif ($level eq 'map') {
-                if ($mapid != $prevmapid) {
+            my ($listed,$scope,$access) = split(/,/,$value);
+            unless (($access eq 'any') || ($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) = split(/:/,$hash{'deeplinkonly_'.$prev});
-            if ($level eq 'resource') {
-                $deeplinkonly = 1;
-            } elsif ($level eq 'map') {
-                if ($mapid != $prevmapid) {
+            my ($listed,$scope,$access) = split(/,/,$value);
+            unless (($access eq 'any') || ($hash{'is_map_'.$prev})) {
+                if ($level eq 'resource') {
                     $deeplinkonly = 1;
+                } elsif ($level eq 'map') {
+                    my ($listed,$scope,$access) = split(/,/,$value);
+                    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;
+                        }
+                    }
                 }
             }
         }
@@ -146,7 +203,8 @@
 		 || (
                         (!$env{'request.role.adv'})
                      && (($hash{'randomout_'.$next})
-                     ||  ($deeplinkonly))
+                     ||  ($deeplinkonly)
+                     ||  ($hash{'deeplinkout_'.$next})
 		    )
 		 || (!$allowed)
 		)
@@ -181,7 +239,7 @@
 		          }
                           if ($thiscond>$mincond) { $mincond=$thiscond; }
 	              }
-                  } 
+                  }
 		  foreach my $id (split(/\,/,$posnext))  {
                       my ($linkid,$condval)=split(/\:/,$id);
                       if ($condval>=$mincond) {
@@ -223,7 +281,7 @@
 			 }
 			 if ($thiscond>$mincond) { $mincond=$thiscond; }
 		     }
-		 } 
+		 }
 		 foreach my $id (split(/\,/,$posnext)) {
 		     my ($linkid,$condval)=split(/\:/,$id);
 		     if ($condval>=$mincond) {
@@ -281,8 +339,8 @@
 	        if ($hash{'encrypted_'.$newrid}) {
 		    $furl=&Apache::lonenc::encrypted($furl);
 	        }
-	    }
-        }
+            {
+	}
 	untie(%hash);
 	return $furl;
     } else {
@@ -363,6 +421,29 @@
 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'};
+        if ($env{'request.deeplink.login'}) {
+            my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+            my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+            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 {
@@ -609,8 +690,13 @@
 	      } else {
 # -------------------------------------------------------------- No place to go
                   $multichoice=-1;
-                  if ($hash{'deeplinkonly_'.$rid}) {
-                      (my $value,$deeplinklevel) = split(/:/,$hash{'deeplinkonly_'.$rid});
+                  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) = split(/:/,$position_deeplink);
+                      }
                   }
               }
 # ----------------- The program must come past this point to untie the big hash
Index: rat/lonsequence.pm
diff -u rat/lonsequence.pm:1.55 rat/lonsequence.pm:1.56
--- rat/lonsequence.pm:1.55	Thu Jun 24 17:19:22 2021
+++ rat/lonsequence.pm	Mon Jul 19 11:48:25 2021
@@ -2,7 +2,7 @@
 #
 # Sequence Handler
 #
-# $Id: lonsequence.pm,v 1.55 2021/06/24 21:19:22 raeburn Exp $
+# $Id: lonsequence.pm,v 1.56 2021/07/19 15:48:25 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -375,8 +375,6 @@
                $dismapid=(split(/\./,$disid))[1];
 	       if (!$env{'request.role.adv'}) {
 		   $randomout = $bighash{'randomout_'.$disid};
-	       }
-               if (!$env{'request.role.adv'}) {
                    $is_encrypted = $bighash{'encrypted_'.$disid};
                }
            } elsif (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
@@ -397,8 +395,6 @@
                    $dismapid=(split(/\./,$disid))[1];
 		   if (!$env{'request.role.adv'}) {
 		       $randomout = $bighash{'randomout_'.$disid};
-		   }
-                   if (!$env{'request.role.adv'}) {
                        $is_encrypted = $bighash{'encrypted_'.$disid};
                    }
                }
Index: loncom/auth/lonacc.pm
diff -u loncom/auth/lonacc.pm:1.191 loncom/auth/lonacc.pm:1.192
--- loncom/auth/lonacc.pm:1.191	Tue Jun 22 12:56:35 2021
+++ loncom/auth/lonacc.pm	Mon Jul 19 11:48:26 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Cookie Based Access Handler
 #
-# $Id: lonacc.pm,v 1.191 2021/06/22 16:56:35 raeburn Exp $
+# $Id: lonacc.pm,v 1.192 2021/07/19 15:48:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -673,6 +673,9 @@
                         if ((!$env{'request.role.adv'}) && ($env{'acc.randomout'}) &&
                             ($env{'acc.randomout'}=~/\&\Q$poss_symb\E\&/)) {
                             undef($poss_symb);
+                        } elsif ((!$env{'request.role.adv'}) && ($env{'acc.deeplinkout'}) &&
+                                 ($env{'acc.deeplinkout'}=~/\&\Q$poss_symb\E\&/)) {
+                            undef($poss_symb);
                         }
                     }
                 }
@@ -682,7 +685,18 @@
                     $access=&Apache::lonnet::allowed('bre',$requrl,'','','','',1);
                 }
             } else {
-                $access=&Apache::lonnet::allowed('bre',$requrl);
+                my $nodeeplinkcheck;
+                if (($check_access) && ($requrl =~ /\.(sequence|page)$/)) {
+                    unless ($env{'form.navmap'}) {
+                        if ($r->args ne '') {
+                            &Apache::loncommon::get_unprocessed_cgi($r->args,['navmap']);
+                            unless ($env{'form.navmap'}) {
+                                $nodeeplinkcheck = 1;
+                            }
+                        }
+                    }
+                }
+                $access=&Apache::lonnet::allowed('bre',$requrl,'','','','','',$nodeeplinkcheck)
             }
         }
         if ($check_block) {
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1361 loncom/interface/loncommon.pm:1.1362
--- loncom/interface/loncommon.pm:1.1361	Tue Jun 15 16:52:26 2021
+++ loncom/interface/loncommon.pm	Mon Jul 19 11:48:26 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1361 2021/06/15 20:52:26 raeburn Exp $
+# $Id: loncommon.pm,v 1.1362 2021/07/19 15:48:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -9142,9 +9142,33 @@
     my ($menucoll,$deeplinkmenu,%menu);
     if ($env{'request.course.id'}) {
         $menucoll = $env{'course.'.$env{'request.course.id'}.'.menudefault'};
-        if (($env{'request.deeplink.login'}) &&
-            ($env{'request.noversionuri'} =~ m{^/(res|uploaded)/})) {
-            my $deeplink = &Apache::lonnet::EXT('resource.0.deeplink');
+        if ($env{'request.deeplink.login'}) {
+            my ($deeplink_symb,$deeplink);
+            my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+            my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+            if ($env{'request.noversionuri'} =~ m{^/(res|uploaded)/}) {
+                if ($env{'request.noversionuri'} =~ /\.(page|sequence)$/) {
+                    my $navmap = Apache::lonnavmaps::navmap->new();
+                    if (ref($navmap)) {
+                        $deeplink = $navmap->get_mapparam(undef,
+                                                          &Apache::lonnet::declutter($env{'request.noversionuri'}),
+                                                          '0.deeplink');
+                    }
+                } else {
+                    $deeplink = &Apache::lonnet::EXT('resource.0.deeplink');
+                }
+            } else {
+                $deeplink_symb = &deeplink_login_symb($cnum,$cdom);
+                if ($deeplink_symb =~ /\.(page|sequence)$/) {
+                    my $mapname = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($deeplink_symb))[2]);
+                    my $navmap = Apache::lonnavmaps::navmap->new();
+                    if (ref($navmap)) {
+                        $deeplink = $navmap->get_mapparam(undef,$mapname,'0.deeplink');
+                    }
+                } else {
+                    $deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$deeplink_symb);
+                }
+            }
             if ($deeplink ne '') {
                 my ($listed,$scope,$access,$display) = split(/,/,$deeplink);
                 if ($display =~ /^\d+$/) {
@@ -9160,6 +9184,35 @@
     return ($menucoll,$deeplinkmenu,\%menu);
 }
 
+sub deeplink_login_symb {
+    my ($cnum,$cdom) = @_;
+    my $login_symb;
+    if ($env{'request.deeplink.login'}) {
+        if ($env{'request.deeplink.login'} =~ m{^\Q/tiny/$cdom/\E(\w+)$}) {
+            my $key = $1;
+            my ($tinyurl,$login);
+            my ($result,$cached)=&Apache::lonnet::is_cached_new('tiny',$cdom."\0".$key);
+            if (defined($cached)) {
+                $tinyurl = $result;
+            } else {
+                my $configuname = &Apache::lonnet::get_domainconfiguser($cdom);
+                my %currtiny = &Apache::lonnet::get('tiny',[$key],$cdom,$configuname);
+                if ($currtiny{$key} ne '') {
+                    $tinyurl = $currtiny{$key};
+                    &Apache::lonnet::do_cache_new('tiny',$cdom."\0".$key,$currtiny{$key},600);
+                }
+            }
+            if ($tinyurl ne '') {
+                my ($cnumreq,$posslogin) = split(/\&/,$tinyurl);
+                if ($cnumreq eq $cnum) {
+                    $login_symb = $posslogin;
+                }
+            }
+        }
+    }
+    return $login_symb;
+}
+
 sub wishlist_window {
     return(<<'ENDWISHLIST');
 <script type="text/javascript">
Index: loncom/interface/lonnavmaps.pm
diff -u loncom/interface/lonnavmaps.pm:1.552 loncom/interface/lonnavmaps.pm:1.553
--- loncom/interface/lonnavmaps.pm:1.552	Tue Jul 13 23:58:17 2021
+++ loncom/interface/lonnavmaps.pm	Mon Jul 19 11:48:26 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Navigate Maps Handler
 #
-# $Id: lonnavmaps.pm,v 1.552 2021/07/14 03:58:17 raeburn Exp $
+# $Id: lonnavmaps.pm,v 1.553 2021/07/19 15:48:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1068,13 +1068,28 @@
             $nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> ';
         } elsif ($params->{'mapUnlisted'}) {
             $nonLinkedText .= ' <span class="LC_warning">('.&mt('unlisted').')</span> ';
+        } elsif ($params->{'mapHiddenDeepLink'} || $resource->deeplinkout()) {
+            $nonLinkedText .= ' <span class="LC_warning">('.&mt('not shown').')</span> ';
         }
     } else {
         if ($resource->randomout()) {
             $nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> ';
-        } elsif (($resource->deeplink($params->{caller}) eq 'absent') ||
-                 ($resource->deeplink($params->{caller}) eq 'grades')) {
-            $nonLinkedText .= ' <span class="LC_warning">('.&mt('unlisted').')</span> ';
+        } elsif ($resource->deeplinkout()) {
+            $nonLinkedText .= ' <span class="LC_warning">('.&mt('not shown').')</span> ';
+        } else {
+            my $deeplink = $resource->deeplink($params->{caller});
+            if ((($deeplink eq 'absent') || ($deeplink eq 'grades')) &&
+                  &advancedUser()) {
+                $nonLinkedText .= ' <span class="LC_warning">('.&mt('unlisted').')</span> ';
+            } elsif (($deeplink) && ($deeplink) ne 'full') {
+                if (&advancedUser()) {
+                    $nonLinkedText .= ' <span class="LC_warning">('.&mt('deep-link access').
+                                      ')</span> ';
+                } else {
+                    $nonLinkedText .= ' <span class="LC_warning">('.&mt('access via external site').
+                                      ')</span> ';
+                }
+            }
         }
     }
     if (!$resource->condval()) {
@@ -1401,6 +1416,7 @@
         $filterFunc = sub { my $res = shift; return !$res->randomout() &&
                                 ($res->deeplink($args->{'caller'}) ne 'absent') &&
                                 ($res->deeplink($args->{'caller'}) ne 'grades') &&
+                                !$res->deeplinkout() &&
                                 &$oldFilterFunc($res);};
     }
 
@@ -1821,6 +1837,7 @@
         # If this is an empty sequence and we're filtering them, continue on
         $args->{'mapHidden'} = 0;
         $args->{'mapUnlisted'} = 0;
+        $args->{'mapHiddenDeepLink'} = 0;
         if (($curRes->is_map()) && (!$curRes->{DATA}->{HAS_VISIBLE_CHILDREN})) {
             if ($args->{'suppressEmptySequences'}) {
                 next;
@@ -1833,6 +1850,12 @@
                     } else {
                         next;
                     }
+                } elsif ($curRes->deeplinkout) {
+                    if ($userCanSeeHidden) {
+                        $args->{'mapHiddenDeepLink'} = 1;
+                    } else {
+                        next;
+                    }
                 } else {
                     my $deeplink = $navmap->get_mapparam(undef,$mapname,"0.deeplink");
                     if ($deeplink =~ /^(absent|grades),/) {
@@ -1906,10 +1929,10 @@
             }
         }
         # If deep-link parameter is set (and is not set to full) suppress link
-        # unless privileged user, or calling context is sequence, and parameter
-        # set at map level
+        # unless privileged user, tinyurl used for login resolved to a map, and
+        # the resource is within the map.
         if ((!$curRes->deeplink($args->{'caller'})) ||
-            ($curRes->deeplink($args->{'caller'}) =~ /^full,/) || &advancedUser()) {
+            ($curRes->deeplink($args->{'caller'}) eq 'full') || &advancedUser()) {
             $args->{'resource_nolink'} = 0;
         } else {
             $args->{'resource_nolink'} = 1;
@@ -2479,7 +2502,7 @@
     my $self = shift;
     my $iterator = Apache::lonnavmaps::iterator->new($self, shift, shift,
                                                      shift, undef, shift,
-						     shift, shift);
+						     shift, shift, shift);
     return $iterator;
 }
 
@@ -3619,7 +3642,7 @@
 
 =over 4
 
-=item * B<getIterator>(firstResource, finishResource, filterHash, condition, forceTop, returnTopMap):
+=item * B<getIterator>(firstResource, finishResource, filterHash, condition, forceTop, returnTopMap, $deeplinklisted):
 
 All parameters are optional. firstResource is a resource reference
 corresponding to where the iterator should start. It defaults to
@@ -3636,7 +3659,10 @@
 will return all information, starting with the top-level map,
 regardless of content. returnTopMap, if true (default false), will
 cause the iterator to return the top-level map object (resource 0.0)
-before anything else.
+before anything else. deeplinklisted if true (default false), will
+check "listed" status of a resource with a deeplink, and unless "absent"
+will exclude deeplink checking when retrieving the browsePriv from
+lonnet::allowed(). 
 
 Thus, by default, only top-level resources will be shown. Change the
 condition to a 1 without changing the hash, and all resources will be
@@ -3773,6 +3799,10 @@
     # have we done that yet?
     $self->{HAVE_RETURNED_0} = 0;
 
+    # Do we want to check the "listed" status for a resource for which
+    # deeplinking applies.
+    $self->{DEEPLINKLISTED} = shift;
+
     # Now, we need to pre-process the map, by walking forward and backward
     # over the parts of the map we're going to look at.
 
@@ -3864,7 +3894,8 @@
 						 $finishResource, $self->{FILTER},
 						 $self->{ALREADY_SEEN}, 
 						 $self->{CONDITION},
-						 $self->{FORCE_TOP});
+						 $self->{FORCE_TOP},
+                                                 undef,$self->{DEEPLINKLISTED});
     }
 
     # Set up some bookkeeping information.
@@ -4034,13 +4065,14 @@
                                               $finishResource, $self->{FILTER},
                                               $self->{ALREADY_SEEN},
 					      $self->{CONDITION},
-					      $self->{FORCE_TOP});
+					      $self->{FORCE_TOP},
+                                              undef,$self->{DEEPLINKLISTED});
     }
 
     # If this is a blank resource, don't actually return it.
     # Should you ever find you need it, make sure to add an option to the code
     #  that you can use; other things depend on this behavior.
-    my $browsePriv = $self->{HERE}->browsePriv($noblockcheck);
+    my $browsePriv = $self->{HERE}->browsePriv($noblockcheck,$self->{DEEPLINKLISTED});
     if (!$self->{HERE}->src() || 
         (!($browsePriv eq 'F') && !($browsePriv eq '2')) ) {
         return $self->next($closeAllPages);
@@ -4468,6 +4500,7 @@
 sub goesto { my $self=shift; return $self->navHash("goesto_", 1); }
 sub kind { my $self=shift; return $self->navHash("kind_", 1); }
 sub randomout { my $self=shift; return $self->navHash("randomout_", 1); }
+sub deeplinkout { my $self=shift; return $self->navHash("deeplinkout_", 1); }
 sub randompick { 
     my $self = shift;
     my $randompick = $self->parmval('randompick');
@@ -5156,16 +5189,42 @@
     return ($useslots,$availablestudent,$available);
 }
 sub deeplink {
-    my ($self,$caller) = @_;
-    my $value = $self->parmval("deeplink");
-    if ($value) {
-        my @deeplink = split(/,/,$value);
-        if ($caller eq 'sequence') {
-            if ($deeplink[1] ne 'res') {
-                return;
+    my ($self,$caller,$action) = @_;
+    my $deeplink = $self->parmval("deeplink");
+    if ($deeplink) {
+        my ($listed,$scope,$access) = split(/,/,$deeplink);
+        if ($action eq 'getlisted') {
+            return $listed;
+        }
+        if ($env{'request.deeplink.login'}) {
+            my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+            my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+            my $deeplink_symb = &Apache::loncommon::deeplink_login_symb($cnum,$cdom);
+            if ($deeplink_symb) {
+                my ($loginmap,$mapname);
+                if ($deeplink_symb =~ /\.(page|sequence)$/) {
+                    $mapname = $self->enclosing_map_src();
+                    $loginmap = &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($deeplink_symb))[2]);
+                    return if ($mapname eq $loginmap);
+                } else {
+                    return if ($deeplink_symb eq $self->symb());
+                    if (($scope eq 'map') || ($scope eq 'rec')) {
+                        $mapname = $self->enclosing_map_src();
+                        $loginmap = &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($deeplink_symb))[0]);
+                        return if ($mapname eq $loginmap);
+                    }
+                }
+                if ($scope eq 'rec') {
+                    my $map_pc = $self->navHash('map_pc_'.$mapname);
+                    my @recurseup = split(/,/,$self->navHash('map_hierarchy_'.$map_pc));
+                    my $login_pc = $self->navHash('map_pc_'.$loginmap);
+                    return if (grep(/^\Q$login_pc\E$/, at recurseup));
+                }
             }
         }
-        return $deeplink[0];
+        unless (($caller eq 'sequence') || ($access eq 'any')) {
+            return $listed;
+        }
     }
     return;
 }
@@ -6360,13 +6419,23 @@
 sub browsePriv {
     my $self = shift;
     my $noblockcheck = shift;
+    my $deeplinklisted = shift;
     if (defined($self->{BROWSE_PRIV})) {
         return $self->{BROWSE_PRIV};
     }
-
+    my ($nodeeplinkcheck,$nodeeplinkout);
+    if ($deeplinklisted) {
+        my $deeplink = $self->deeplink(undef,'getlisted');
+        if (($deeplink) && ($deeplink ne 'absent')) {
+            $nodeeplinkcheck = 1;
+        }
+        $nodeeplinkout = 1;
+    }
     $self->{BROWSE_PRIV} = &Apache::lonnet::allowed('bre',$self->src(),
 						    $self->{SYMB},undef,
-                                                    undef,$noblockcheck);
+                                                    undef,$noblockcheck,
+                                                    undef,$nodeeplinkcheck,
+                                                    $nodeeplinkout);  
 }
 
 =pod
Index: loncom/interface/lonquickgrades.pm
diff -u loncom/interface/lonquickgrades.pm:1.120 loncom/interface/lonquickgrades.pm:1.121
--- loncom/interface/lonquickgrades.pm:1.120	Thu Feb 18 09:48:02 2021
+++ loncom/interface/lonquickgrades.pm	Mon Jul 19 11:48:26 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Quick Student Grades Display
 #
-# $Id: lonquickgrades.pm,v 1.120 2021/02/18 14:48:02 raeburn Exp $
+# $Id: lonquickgrades.pm,v 1.121 2021/07/19 15:48:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -484,7 +484,8 @@
 
     my $res = $navmap->firstResource(); # temp resource to access constants
 
-    my $iterator = $navmap->getIterator(undef, undef, undef, 1);
+    my $deeplinkcond = 1;
+    my $iterator = $navmap->getIterator(undef, undef, undef, 1, undef, undef, $deeplinkcond);
     my $depth = 1;
     $iterator->next(); # ignore first BEGIN_MAP
     my $curRes = $iterator->next();
@@ -510,9 +511,17 @@
     while ( $depth > 0 ) {
         if ($curRes == $iterator->BEGIN_MAP()) {$depth++;}
         if ($curRes == $iterator->END_MAP()) { $depth--; }
-
-        if (ref($curRes) && $curRes->is_gradable() && !$curRes->randomout && 
-            ($curRes->deeplink ne 'absent'))
+        my ($deeplink,$nodeeplinkcheck,$symb);
+        $nodeeplinkcheck = 1;
+        if (ref($curRes)) {
+            $symb = $curRes->symb();
+            $deeplink = $curRes->deeplink('quickgrades');
+            if ($deeplink eq 'absent') {
+                $nodeeplinkcheck = 0;
+            }
+        }
+        if (ref($curRes) && $curRes->is_gradable() && !$curRes->randomout &&
+            ($nodeeplinkcheck))
         {
             # Get number of correct, incorrect parts
             my $parts = $curRes->parts();
@@ -634,7 +643,8 @@
 # Output of folder scores
 #
 
-    my $iterator = $navmap->getIterator(undef, undef, undef, 1);
+    my $deeplinkcond = 1;
+    my $iterator = $navmap->getIterator(undef, undef, undef, 1, undef, undef, $deeplinkcond);
     my $depth = 1;
     $iterator->next(); # ignore first BEGIN_MAP
     my $curRes = $iterator->next();
@@ -765,7 +775,8 @@
 
 # Run through the map and get all data
 
-    my $iterator = $navmap->getIterator(undef, undef, undef, 1);
+    my $deeplinkcond = 1;
+    my $iterator = $navmap->getIterator(undef, undef, undef, 1, undef, undef, $deeplinkcond);
     my $depth = 1;
     $iterator->next(); # ignore first BEGIN_MAP
     my $curRes = $iterator->next();
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1460 loncom/lonnet/perl/lonnet.pm:1.1461
--- loncom/lonnet/perl/lonnet.pm:1.1460	Tue Jun 15 16:52:28 2021
+++ loncom/lonnet/perl/lonnet.pm	Mon Jul 19 11:48:27 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1460 2021/06/15 20:52:28 raeburn Exp $
+# $Id: lonnet.pm,v 1.1461 2021/07/19 15:48:27 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -8117,7 +8117,7 @@
 # ------------------------------------------------- Check for a user privilege
 
 sub allowed {
-    my ($priv,$uri,$symb,$role,$clientip,$noblockcheck,$ignorecache)=@_;
+    my ($priv,$uri,$symb,$role,$clientip,$noblockcheck,$ignorecache,$nodeeplinkcheck,$nodeeplinkout)=@_;
     my $ver_orguri=$uri;
     $uri=&deversion($uri);
     my $orguri=$uri;
@@ -8342,7 +8342,10 @@
             if ($env{'user.priv.'.$env{'request.role'}.'./'}
                   =~/\Q$priv\E\&([^\:]*)/) {
                 my $value = $1;
-                my $deeplinkblock = &deeplink_check($priv,$symb,$uri);
+                my $deeplinkblock;
+                unless ($nodeeplinkcheck) {
+                    $deeplinkblock = &deeplink_check($priv,$symb,$uri);
+                }
                 if ($deeplinkblock) {
                     $thisallowed='D';
                 } elsif ($noblockcheck) {
@@ -8365,7 +8368,10 @@
                     $refuri=&declutter($refuri);
                     my ($match) = &is_on_map($refuri);
                     if ($match) {
-                        my $deeplinkblock = &deeplink_check($priv,$symb,$refuri);
+                        my $deeplinkblock;
+                        unless ($nodeeplinkcheck) {
+                            $deeplinkblock = &deeplink_check($priv,$symb,$refuri);
+                        }
                         if ($deeplinkblock) {
                             $thisallowed='D';
                         } elsif ($noblockcheck) {
@@ -8441,7 +8447,10 @@
                =~/\Q$priv\E\&([^\:]*)/) {
                my $value = $1;
                if ($priv eq 'bre') {
-                   my $deeplinkblock = &deeplink_check($priv,$symb,$uri);
+                   my $deeplinkblock;
+                   unless ($nodeeplinkcheck) {
+                       $deeplinkblock = &deeplink_check($priv,$symb,$uri);
+                   }
                    if ($deeplinkblock) {
                        $thisallowed = 'D';
                    } elsif ($noblockcheck) {
@@ -8486,7 +8495,10 @@
                   =~/\Q$priv\E\&([^\:]*)/) {
                   my $value = $1;
                   if ($priv eq 'bre') {
-                      my $deeplinkblock = &deeplink_check($priv,$symb,$refuri);
+                      my $deeplinkblock;
+                      unless ($nodeeplinkcheck) {
+                          $deeplinkblock = &deeplink_check($priv,$symb,$refuri);
+                      }
                       if ($deeplinkblock) {
                           $thisallowed = 'D';
                       } elsif ($noblockcheck) {
@@ -8669,6 +8681,17 @@
        }
    }
 
+# Restricted for deeplinked session?
+
+    if ($env{'request.deeplink.login'}) {
+        if ($env{'acc.deeplinkout'} && !$nodeeplinkout) {
+            if (!$symb) { $symb=&symbread($uri,1); }
+            if (($symb) && ($env{'acc.deeplinkout'}=~/\&\Q$symb\E\&/)) {
+                return '';
+            }
+        }
+    }
+
 # Restricted by state or randomout?
 
    if ($thisallowed=~/X/) {
@@ -9026,29 +9049,9 @@
         @symbs = keys(%possibles);
     }
 
-    my ($login,$switchrole,$allow);
-    if ($env{'request.deeplink.login'} =~ m{^\Q/tiny/$cdom/\E(\w+)$}) {
-        my $key = $1;
-        my $tinyurl;
-        my ($result,$cached)=&Apache::lonnet::is_cached_new('tiny',$cdom."\0".$key);
-        if (defined($cached)) {
-             $tinyurl = $result;
-        } else {
-             my $configuname = &Apache::lonnet::get_domainconfiguser($cdom);
-             my %currtiny = &Apache::lonnet::get('tiny',[$key],$cdom,$configuname);
-             if ($currtiny{$key} ne '') {
-                 $tinyurl = $currtiny{$key};
-                 &Apache::lonnet::do_cache_new('tiny',$cdom."\0".$key,$currtiny{$key},600);
-             }
-        }
-        if ($tinyurl ne '') {
-            my ($cnumreq,$posslogin) = split(/\&/,$tinyurl);
-            if ($cnumreq eq $cnum) {
-                $login = $posslogin;
-            } else {
-                $switchrole = 1;
-            }
-        }
+    my ($deeplink_symb,$allow);
+    if ($env{'request.deeplink.login'}) {
+        $deeplink_symb = &Apache::loncommon::deeplink_login_symb($cnum,$cdom);
     }
     foreach my $symb (@symbs) {
         last if ($allow);
@@ -9059,15 +9062,20 @@
             my ($listed,$scope,$access) = split(/,/,$deeplink);
             if ($access eq 'any') {
                 $allow = 1;
-            } elsif ($login) {
+            } elsif ($deeplink_symb) {
                 if ($access eq 'only') {
                     if ($scope eq 'res') {
-                        if ($symb eq $login) {
+                        if ($symb eq $deeplink_symb) {
                             $allow = 1;
                         }
                     } elsif (($scope eq 'map') || ($scope eq 'rec')) {
-                        my ($map_from_symb) = &deversion((&decode_symb($symb))[0]);
-                        my ($map_from_login) = &deversion((&decode_symb($login))[0]);
+                        my ($map_from_symb,$map_from_login); 
+                        $map_from_symb = &deversion((&decode_symb($symb))[0]);
+                        if ($deeplink_symb =~ /\.(page|sequence)$/) {
+                            $map_from_login = &deversion((&decode_symb($deeplink_symb))[2]);
+                        } else {
+                            $map_from_login = &deversion((&decode_symb($deeplink_symb))[0]);
+                        }
                         if (($map_from_symb) && ($map_from_login)) {
                             if ($map_from_symb eq $map_from_login) {
                                 $allow = 1;
@@ -12260,7 +12268,7 @@
 # --------------------------------------------------------- Value of a Variable
 sub EXT {
 
-    my ($varname,$symbparm,$udom,$uname,$usection,$recurse,$cid)=@_;
+    my ($varname,$symbparm,$udom,$uname,$usection,$recurse,$cid,$recurseupref)=@_;
     unless ($varname) { return ''; }
     #get real user name/domain, courseid and symb
     my $courseid;
@@ -12414,6 +12422,10 @@
         }
 
 	my ($section, $group, @groups, @recurseup, $recursed);
+        if (ref($recurseupref) eq 'ARRAY') {
+            @recurseup = @{$recurseupref};
+            $recursed = 1;
+        }
 	my ($courselevelm,$courseleveli,$courselevel,$mapp);
         if (($courseid eq '') && ($cid)) {
             $courseid = $cid;


More information about the LON-CAPA-cvs mailing list