--- loncom/homework/lonhomework.pm	2023/11/17 17:02:21	1.380
+++ loncom/homework/lonhomework.pm	2024/11/21 07:26:01	1.384
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Homework handler
 #
-# $Id: lonhomework.pm,v 1.380 2023/11/17 17:02:21 raeburn Exp $
+# $Id: lonhomework.pm,v 1.384 2024/11/21 07:26:01 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -949,7 +949,7 @@ STATE
 
 sub analyze_header {
     my ($request) = @_;
-    my $js = &Apache::structuretags::setmode_javascript();
+    my $js = &Apache::lonxml::setmode_javascript();
 
     # Breadcrumbs
     my $text = 'Authoring Space';
@@ -1198,7 +1198,7 @@ sub editxmlmode {
 	my $js =
 	    &Apache::edit::js_change_detection(). 
 	    &Apache::loncommon::resize_textarea_js().
-            &Apache::structuretags::setmode_javascript().
+            &Apache::lonxml::setmode_javascript().
             &Apache::lonhtmlcommon::dragmath_js("EditMathPopup");
 
     # Breadcrumbs
@@ -1978,6 +1978,8 @@ sub convert_for_js {
 
 sub do_ltipassback {
     if (@Apache::lonhomework::ltipassback) {
+        my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
+        my $ip = &Apache::lonnet::get_host_ip($lonhost);
         foreach my $item (@Apache::lonhomework::ltipassback) {
             if (ref($item) eq 'HASH') {
                 if ((ref($item->{'lti'}) eq 'HASH') && ($item->{'cid'} =~ /^($match_domain)_($match_courseid)$/)) {
@@ -1988,25 +1990,94 @@ sub do_ltipassback {
                     my $id = $item->{'pbid'};
                     my $url = $item->{'pburl'};
                     my $type = $item->{'pbtype'};
-                    my $scope = $item->{'scope'};
-                    my $map = $item->{'ltimap'};
-                    my $symb = $item->{'ltisymb'};
+                    my $pbscope = $item->{'pbscope'};
+                    my $map = $item->{'pbmap'};
+                    my $symb = $item->{'pbsymb'};
                     my $uname = $item->{'uname'};
                     my $udom = $item->{'udom'};
+                    my $uhome = $item->{'uhome'};
                     my $keynum = $item->{'lti'}->{'cipher'};
                     my $crsdef = $item->{'crsdef'};
                     my $scoretype = $item->{'format'};
+                    my $scope = $item->{'scope'};
+                    my $clientip = $item->{'clientip'};
                     my ($total,$possible);
-                    if ($scope eq 'resource') {
+                    if ($pbscope eq 'resource') {
                         $total = $item->{'total'};
                         $possible = $item->{'possible'};
-                    } elsif ($scope eq 'map') {
-                        ($total,$possible) = &get_lti_score($uname,$udom,$map);
-                    } elsif ($scope eq 'course') {
-                        ($total,$possible) = &get_lti_score($uname,$udom);
+                    } else {
+                        if (($pbscope eq 'map') || ($pbscope eq 'nonrec')) {
+                            ($total,$possible) = &get_lti_score($uname,$udom,$map,$pbscope);
+                        } elsif ($pbscope eq 'course') {
+                            ($total,$possible) = &get_lti_score($uname,$udom);
+                        }
+                        $item->{'total'} = $total;
+                        $item->{'possible'} = $possible;
                     }
                     if (($id ne '') && ($url ne '') && ($possible)) {
-                        &LONCAPA::ltiutils::send_grade($cdom,$cnum,$crsdef,$type,$ltinum,$keynum,$id,$url,$scoretype,$sigmethod,$msgformat,$total,$possible);
+                        my ($sent,$score,$code,$result) = 
+                            &LONCAPA::ltiutils::send_grade($cdom,$cnum,$crsdef,$type,$ltinum,$keynum,$id,
+                                                           $url,$scoretype,$sigmethod,$msgformat,$total,$possible);
+                        $item->{'score'} = $score;
+                        my ($linkprotector,$linkuri,$no_passback,$appname);
+                        if ($item->{'linkprot'}) {
+                            ($linkprotector,$linkuri) = split(/:/,$item->{'linkprot'});
+                        }
+                        if ($sent) {
+                            if ($code == 200) {
+                                if ($item->{'linkprot'}) {
+                                    my $key = join("\0",($linkuri,$linkprotector,$scope));
+                                    my $namespace = $cdom.'_'.$cnum.'_lp_passback';
+                                    my $store = {
+                                                 'score' => $score,
+                                                 'ip' => $ip,
+                                                 'host' => $Apache::lonnet::perlvar{'lonHostID'},
+                                                 'protector' => $linkprotector,
+                                                 'deeplink' => $linkuri,
+                                                 'scope' => $scope,
+                                                 'url' => $url,
+                                                 'id' => $id,
+                                                 'clientip' => $clientip,
+                                                 'whodoneit' => $env{'user.name'}.':'.$env{'user.domain'},
+                                                };
+                                    my $value='';
+                                    foreach my $key (keys(%{$store})) {
+                                        $value.=&escape($key).'='.&Apache::lonnet::freeze_escape($store->{$key}).'&';
+                                    }
+                                    $value=~s/\&$//;
+                                    &Apache::lonnet::courselog(&escape($linkuri).':'.$uname.':'.$udom.':EXPORT:'.$value);
+                                    &Apache::lonnet::cstore({'score' => $score},$key,$namespace,$udom,$uname,'',$ip,1);
+                                }
+                            } else {
+                                if ($item->{'linkprot'}) {
+                                    $no_passback = "Passback response was $code ($result).";
+                                }
+                            }
+                        } else {
+                            if ($item->{'linkprot'}) {
+                                $no_passback = 'No passback of scores.';
+                            }
+                        }
+                        if ($no_passback) {
+                            if ($item->{'linkprot'}) {
+                                my ($ltinum,$ltitype) = ($linkprotector =~ /^(\d+)(c|d)$/);
+                                if ($ltitype eq 'c') {
+                                    my %lti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider');
+                                    if (ref($lti{$ltinum}) eq 'HASH') {
+                                        $appname = $lti{$ltinum}{'name'};
+                                    }
+                                } elsif ($ltitype eq 'd') {
+                                    my %lti = &Apache::lonnet::get_domain_lti($cdom,'linkprot');
+                                    if (ref($lti{$ltinum}) eq 'HASH') {
+                                        $appname = $lti{$ltinum}{'name'};
+                                    }
+                                }
+                                $no_passback .= " LTI launcher $linkprotector ($appname) for $linkuri (${cdom}_${cnum})";
+                                &Apache::lonnet::logthis($no_passback." for $uname:$udom");
+                                &Apache::lonnet::log($udom,$uname,$uhome,"$no_passback score=$score total=$total poss=$possible");
+                                &Apache::lonnet::put('linkprot_passback_pending',$item,$cdom,$cnum);
+                            }
+                        }
                     }
                 }
             }
@@ -2016,7 +2087,7 @@ sub do_ltipassback {
 }
 
 sub get_lti_score {
-    my ($uname,$udom,$mapurl) = @_;
+    my ($uname,$udom,$mapurl,$pbscope) = @_;
     my $navmap = Apache::lonnavmaps::navmap->new($uname,$udom);
     if (ref($navmap)) {
         my $iterator;
@@ -2024,7 +2095,11 @@ sub get_lti_score {
             my $map = $navmap->getResourceByUrl($mapurl);
             my $firstres = $map->map_start();
             my $finishres = $map->map_finish();
-            $iterator = $navmap->getIterator($firstres,$finishres,undef,1);
+            my $recursive = 1;
+            if ($pbscope eq 'nonrec') {
+                $recursive = 0;
+            }
+            $iterator = $navmap->getIterator($firstres,$finishres,undef,$recursive);
         } else {
             $iterator = $navmap->getIterator(undef,undef,undef,1);
         }