--- loncom/interface/lontiny.pm 2023/06/04 00:36:18 1.20 +++ loncom/interface/lontiny.pm 2025/02/07 20:23:42 1.24 @@ -2,7 +2,7 @@ # Extract domain, courseID, and symb from a shortened URL, # and switch role to a role in designated course. # -# $Id: lontiny.pm,v 1.20 2023/06/04 00:36:18 raeburn Exp $ +# $Id: lontiny.pm,v 1.24 2025/02/07 20:23:42 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -99,14 +99,19 @@ sub handler { } if ($env{'request.course.id'} eq $cdom.'_'.$cnum) { # Check for ttoken - my $newlauncher = &launch_check($r->uri,$symb); + my $newlauncher = &launch_check($r->uri,$symb,$cdom,$cnum); my ($map,$resid,$url) = &Apache::lonnet::decode_symb($symb); if (&Apache::lonnet::is_on_map($url)) { - my $realuri; + my ($realuri,$reinitresult,$reinitchecked); if ((&Apache::lonnet::EXT('resource.0.hiddenresource',$symb) =~ /^yes$/i) && (!$env{'request.role.adv'})) { - $env{'user.error.msg'}=$r->uri.':bre:1:1:Access to resource denied'; - return HTTP_NOT_ACCEPTABLE; + my $loncaparev = $r->dir_config('lonVersion'); + ($reinitresult,my @reinit) = &Apache::loncommon::needs_coursereinit($loncaparev); + $reinitchecked = 1; + unless (($reinitresult eq 'main') || ($reinitresult eq 'both')) { + $env{'user.error.msg'}=$r->uri.':bre:1:1:Access to resource denied'; + return HTTP_NOT_ACCEPTABLE; + } } if ((&Apache::lonnet::EXT('resource.0.encrypturl',$symb) =~ /^yes$/i) && (!$env{'request.role.adv'})) { @@ -126,13 +131,17 @@ sub handler { $realuri .= '?symb='.$symb; } } - my ($update,$reinitresult); + my $update; # Check if course needs to be re-initialized if ($newlauncher) { $update = 1; + } elsif (($reinitresult eq 'main') || ($reinitresult eq 'both')) { + $update = 1; } else { - my $loncaparev = $r->dir_config('lonVersion'); - ($reinitresult,my @reinit) = &Apache::loncommon::needs_coursereinit($loncaparev); + if (!$reinitchecked) { + my $loncaparev = $r->dir_config('lonVersion'); + ($reinitresult,my @reinit) = &Apache::loncommon::needs_coursereinit($loncaparev); + } if (($reinitresult eq 'main') || ($reinitresult eq 'both')) { $update = 1; } elsif (!-e $env{'request.course.fn'}.'.db') { @@ -161,6 +170,10 @@ sub handler { $env{'user.error.msg'}=$r->uri.':bre:0:0:Course not initialized'; $env{'user.reinit'} = 1; return HTTP_NOT_ACCEPTABLE; + } elsif ((&Apache::lonnet::EXT('resource.0.hiddenresource',$symb) =~ /^yes$/i) && + (!$env{'request.role.adv'})) { + $env{'user.error.msg'}=$r->uri.':bre:1:1:Access to resource denied'; + return HTTP_NOT_ACCEPTABLE; } } if (($reinitresult eq 'both') || ($reinitresult eq 'supp')) { @@ -307,8 +320,9 @@ sub handler { } sub launch_check { - my ($linkuri,$symb) = @_; - my ($linkprotector,$linkproturi,$linkprotexit,$linkprotpbid,$linkprotpburl,$linkkey,$newlauncher); + my ($linkuri,$symb,$cdom,$cnum) = @_; + my ($linkprotector,$linkproturi,$linkprotexit,$linkprotpbid,$linkprotpburl, + $linkkey,$newlauncher,$prevlaunch); if ($env{'form.ttoken'}) { my %link_info = &Apache::lonnet::tmpget($env{'form.ttoken'}); &Apache::lonnet::tmpdel($env{'form.ttoken'}); @@ -380,6 +394,9 @@ sub launch_check { if ($link_info{'checklaunch'}) { $newlauncher = 1; } + if ($link_info{'prevlaunch'} ne '') { + $prevlaunch = $link_info{'prevlaunch'}; + } } my $currdeeplinklogin = $env{'request.deeplink.login'}; my $deeplink; @@ -438,32 +455,51 @@ sub launch_check { } else { unless ($currdeeplinklogin eq $linkuri) { if (($linkprotector) || ($linkkey ne '')) { - if ($linkprotector) { - &Apache::lonnet::appenv({'request.linkprot' => $linkprotector.':'.$linkproturi}); - } elsif ($env{'request.linkprot'}) { - &Apache::lonnet::delenv('request.linkprot'); - } + $newlauncher = 1; + } + } + if ($linkprotector) { + &Apache::lonnet::appenv({'request.linkprot' => $linkprotector.':'.$linkproturi}); + if ($linkprotpburl && $linkprotpbid) { + my ($res,$error) = &store_passback_info($cdom,$cnum,$linkuri,$linkprotector, + $scope,$symb,$linkprotpbid,$linkprotpburl, + $currdeeplinklogin); + } + } elsif ($env{'request.linkprot'}) { + &Apache::lonnet::delenv('request.linkprot'); + } + if ($linkkey ne '') { + &Apache::lonnet::appenv({'request.linkkey' => $linkkey}); + } elsif ($env{'request.linkkey'} ne '') { + &Apache::lonnet::delenv('request.linkkey'); + } + if (($linkprotector) || ($linkkey ne '')) { + if ($linkprotexit ne $env{'request.linkprotexit'}) { if ($linkprotexit) { &Apache::lonnet::appenv({'request.linkprotexit' => $linkprotexit}); } elsif ($env{'request.linkprotexit'}) { &Apache::lonnet::delenv('request.linkprotexit'); } + } + if ($linkprotpbid ne $env{'request.linkprotpbid'}) { if ($linkprotpbid) { &Apache::lonnet::appenv({'request.linkprotpbid' => $linkprotpbid}); } elsif ($env{'request.linkprotpbid'}) { &Apache::lonnet::delenv('request.linkprotpbid'); } + } + if ($linkprotpburl ne $env{'request.linkprotpburl'}) { if ($linkprotpburl) { &Apache::lonnet::appenv({'request.linkprotpburl' => $linkprotpburl}); } elsif ($env{'request.linkprotpburl'}) { &Apache::lonnet::delenv('request.linkprotpburl'); } - if ($linkkey ne '') { - &Apache::lonnet::appenv({'request.linkkey' => $linkkey}); - } elsif ($env{'request.linkkey'} ne '') { - &Apache::lonnet::delenv('request.linkkey'); + } + } elsif ($prevlaunch) { + foreach my $requestkey ('linkprotpbid','linkprotpburl','linkprotexit') { + if ($env{"request.$requestkey"}) { + &Apache::lonnet::delenv("request.$requestkey"); } - $newlauncher = 1; } } &Apache::lonnet::appenv({'request.deeplink.login' => $linkuri}); @@ -507,6 +543,68 @@ sub launch_check { return $newlauncher; } +# +# Store linkprotpburl and linkprotpbid in user's nohist_$cid_linkprot_pb.db +# $linkuri\0$linkprotector\0$scope = [$linkprotpbid,$linkprotpburl] +# Separately store $symb in course's nohist_linkprot_passback.db +# which should trigger passback: +# $symb => {$linkuri\0$linkprotector\0$scope => 1}; +# + +sub store_passback_info { + my ($cdom,$cnum,$linkuri,$linkprotector,$scope,$symb, + $linkprotpbid,$linkprotpburl,$currdeeplinklogin) = @_; + my $key = join("\0",($linkuri,$linkprotector,$scope)); + my $namespace = 'nohist_'.$cdom.'_'.$cnum.'_linkprot_pb'; + if ($linkuri eq $currdeeplinklogin) { + my %pbinfo = &Apache::lonnet::get($namespace,[$key]); + if (ref($pbinfo{$key}) eq 'ARRAY') { + if (($pbinfo{$key}[0] eq $linkprotpbid) && + ($pbinfo{$key}[1] eq $linkprotpburl)) { + return ('ok'); + } + } + } + my $now = time; + my $result = &Apache::lonnet::cput($namespace,{$key => [$linkprotpbid,$linkprotpburl]}); + my $error; + if (($result eq 'ok') || ($result eq 'con_delayed')) { + $namespace = 'nohist_linkprot_passback'; + my %triggers = &Apache::lonnet::get($namespace,[$symb],$cdom,$cnum); + my $newtrigger; + if ((exists($triggers{$symb})) && (ref($triggers{$symb}) eq 'HASH')) { + unless (exists($triggers{$symb}{$key})) { + $newtrigger = 1; + } + } else { + $newtrigger = 1; + } + if ($newtrigger) { + my ($lockhash,$tries,$gotlock); + $lockhash = { + lock => $env{'user.name'}. + ':'.$env{'user.domain'}, + }; + $tries = 0; + $gotlock = &Apache::lonnet::newput($namespace,$lockhash,$cdom,$cnum); + while (($gotlock ne 'ok') && ($tries<10)) { + $tries ++; + sleep (0.1); + $gotlock = &Apache::lonnet::newput($namespace,$lockhash,$cdom,$cnum); + } + if ($gotlock eq 'ok') { + %triggers = &Apache::lonnet::get($namespace,[$symb],$cdom,$cnum); + $triggers{$symb}{$key} = 1; + $result = &Apache::lonnet::cput($namespace,{$symb => $triggers{$symb}},$cdom,$cnum); + my $dellockoutcome = &Apache::lonnet::del($namespace,['lock'],$cdom,$cnum); + } else { + $error = 'nolock'; + } + } + } + return ($result,$error); +} + sub do_redirect { my ($r,$destination,$linkprot) = @_; my $windowname = 'loncapaclient';