--- loncom/interface/lonnavmaps.pm 2021/07/14 03:58:17 1.552 +++ loncom/interface/lonnavmaps.pm 2021/07/19 15:48:26 1.553 @@ -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 @@ sub render_resource { $nonLinkedText .= ' ('.&mt('hidden').') '; } elsif ($params->{'mapUnlisted'}) { $nonLinkedText .= ' ('.&mt('unlisted').') '; + } elsif ($params->{'mapHiddenDeepLink'} || $resource->deeplinkout()) { + $nonLinkedText .= ' ('.&mt('not shown').') '; } } else { if ($resource->randomout()) { $nonLinkedText .= ' ('.&mt('hidden').') '; - } elsif (($resource->deeplink($params->{caller}) eq 'absent') || - ($resource->deeplink($params->{caller}) eq 'grades')) { - $nonLinkedText .= ' ('.&mt('unlisted').') '; + } elsif ($resource->deeplinkout()) { + $nonLinkedText .= ' ('.&mt('not shown').') '; + } else { + my $deeplink = $resource->deeplink($params->{caller}); + if ((($deeplink eq 'absent') || ($deeplink eq 'grades')) && + &advancedUser()) { + $nonLinkedText .= ' ('.&mt('unlisted').') '; + } elsif (($deeplink) && ($deeplink) ne 'full') { + if (&advancedUser()) { + $nonLinkedText .= ' ('.&mt('deep-link access'). + ') '; + } else { + $nonLinkedText .= ' ('.&mt('access via external site'). + ') '; + } + } } } if (!$resource->condval()) { @@ -1401,6 +1416,7 @@ sub render { $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 @@ END # 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 @@ END } 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 @@ END } } # 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 @@ sub getIterator { 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 @@ getIterator behaves as follows: =over 4 -=item * B(firstResource, finishResource, filterHash, condition, forceTop, returnTopMap): +=item * B(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 @@ that is not just a single, 'redirecting' 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 @@ sub new { # 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 @@ sub new { $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 @@ sub next { $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 from { my $self=shift; return $self- 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 @@ sub slot_control { 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$/,@recurseup)); + } } } - return $deeplink[0]; + unless (($caller eq 'sequence') || ($access eq 'any')) { + return $listed; + } } return; } @@ -6360,13 +6419,23 @@ sub getPrevious { 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