[LON-CAPA-cvs] cvs: loncom /interface domainprefs.pm lonconfigsettings.pm /lti ltipassback.pm ltiroster.pm ltiutils.pm

raeburn raeburn at source.lon-capa.org
Tue Aug 14 17:42:40 EDT 2018


raeburn		Tue Aug 14 21:42:40 2018 EDT

  Modified files:              
    /loncom/lti	ltipassback.pm ltiroster.pm ltiutils.pm 
    /loncom/interface	domainprefs.pm lonconfigsettings.pm 
  Log:
  - Bug 6754 LON-CAPA as LTI Provider
    - Support requests to /adm/service/passback and /adm/service/roster in
      which OAuth data in request header.
    - Support LTI Basic Outcomes Service (1.1) in which grade (a decimal) is
      included in XML in the request body (with oauth_body_hash in the header).
    - LTI Provider domain configuration to set grade passback using either
      Outcomes Service (1.1) -- the default -- or Outcomes extension (1.0).
  
  
-------------- next part --------------
Index: loncom/lti/ltipassback.pm
diff -u loncom/lti/ltipassback.pm:1.5 loncom/lti/ltipassback.pm:1.6
--- loncom/lti/ltipassback.pm:1.5	Fri Dec 15 17:07:09 2017
+++ loncom/lti/ltipassback.pm	Tue Aug 14 21:42:36 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # LTI Consumer Module to receive grades passed back by Provider 
 #
-# $Id: ltipassback.pm,v 1.5 2017/12/15 17:07:09 raeburn Exp $
+# $Id: ltipassback.pm,v 1.6 2018/08/14 21:42:36 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -29,6 +29,7 @@
 package Apache::ltipassback;
 
 use strict;
+use URI::Escape;
 use Apache::Constants qw(:common :http);
 use Apache::lonnet;
 use Apache::loncommon;
@@ -38,14 +39,56 @@
 sub handler {
     my $r = shift;
     my %errors;
+    my $params = {};
+    my ($oauthtype,$authheader,$xmlbody);
+#
+# Retrieve content type from headers
+#
+    my $content_type = $r->headers_in->get('Content-Type');
+    if ($content_type eq 'application/xml') {
+        $oauthtype = 'consumer';
+#
+# Retrieve OAuth data from Authorization header sent by LTI Provider
+#
+        $authheader = $r->headers_in->get('Authorization');
+        my ($authtype,$valuestr) = ($authheader =~ /^(OAuth)\s+(.+)$/i);
+        if (lc($authtype) eq 'oauth') {
+            foreach my $pair (split(/\s*,\s*/,$valuestr)) {
+                my ($key,$value) = split(/=/,$pair);
+                $value =~ s /(^"|"$)//g;
+                $params->{$key} = URI::Escape::uri_unescape($value);
+            }
+        }
+#
+# Retrieve message body
+#
+        my $length = $r->headers_in->get('Content-length');
+        if ($length) {
+            $r->read($xmlbody,$length,0);
+            if ($xmlbody ne '') {
+                my %grades = &LONCAPA::ltiutils::parse_grade_xml($xmlbody);
+                foreach my $num (sort { $a <=> $b } (keys(%grades))) {
+                    if (ref($grades{$num}) eq 'HASH') {
+                        if (($grades{$num}{'sourcedid'} ne '') && ($grades{$num}{'score'} ne '')) {
+                            $params->{'sourcedid'} = $grades{$num}{'sourcedid'};
+                            $params->{'result_resultscore_textstring'} = $grades{$num}{'score'};
+                            $params->{'result_resultscore_language'} = $grades{$num}{'language'};
+                            $params->{'result_resultvaluesourcedid'} = 'decimal'; 
+                        }
+                    } 
+                }
+            }
+        }
+    } else {
+        $oauthtype = 'request token';
 #
 # Retrieve data POSTed by LTI Provider
 #
-    &Apache::lonacc::get_posted_cgi($r);
-    my $params = {};
-    foreach my $key (sort(keys(%env))) {
-        if ($key =~ /^form\.(.+)$/) {
-            $params->{$1} = $env{$key};
+        &Apache::lonacc::get_posted_cgi($r);
+        foreach my $key (sort(keys(%env))) {
+            if ($key =~ /^form\.(.+)$/) {
+                $params->{$1} = $env{$key};
+            }
         }
     }
 
@@ -119,6 +162,11 @@
                                             $marker,$symb,$cdom,$cnum,
                                             \%toolsettings,\%ltitools,\%errors);
 
+    if (keys(%errors) > 0) {
+        &invalid_request($r,$params,\%errors);
+        return OK;
+    }
+
 #
 # Verify the signed request using the consumer_key and 
 # secret for the specific LTI Provider.
@@ -128,9 +176,24 @@
     if ($ENV{'SERVER_PORT'} == 443) {
         $protocol = 'https';
     }
-    unless (LONCAPA::ltiutils::verify_request($params,$protocol,$r->hostname,$r->uri,
-                                              $env{'request.method'},$consumer_secret,
-                                              \%errors)) {
+
+    unless (LONCAPA::ltiutils::verify_request($oauthtype,$protocol,$r->hostname,$r->uri,
+                                              $r->method,$consumer_secret,$params,
+                                              $authheader,\%errors)) {
+        &invalid_request($r,$params,\%errors);
+        return OK;
+    }
+
+#
+# Verify XML in request body has not been tampered with
+#
+
+    my $bodyhash = Digest::SHA::sha1_base64($xmlbody);
+    while (length($bodyhash) % 4) {
+        $bodyhash .= '=';
+    }
+    unless ($bodyhash eq $params->{oauth_body_hash}) {
+        $errors{16} = 1;
         &invalid_request($r,$params,\%errors);
         return OK;
     }
@@ -138,10 +201,11 @@
 #
 # Determine if nonce in POSTed data has expired.
 # If unexpired, confirm it has not already been used.
+#
 
     unless (&LONCAPA::ltiutils::check_nonce($params->{'oauth_nonce'},$params->{'oauth_timestamp'},
                                             $ltitools{'lifetime'},$cdom,$r->dir_config('lonLTIDir'))) {
-        $errors{16} = 1;
+        $errors{17} = 1;
         &invalid_request($r,$params,\%errors);
         return OK;
     }
@@ -168,7 +232,7 @@
             %maproles = %{$ltitools{'roles'}};
         }
         unless (keys(%maproles)) {
-            $errors{21} = 1;
+            $errors{22} = 1;
             &invalid_request($r,$params,\%errors);
             return OK;
         }
@@ -205,12 +269,12 @@
             }
         }
         unless ($hasrole) {
-            $errors{22} = 1;
+            $errors{23} = 1;
             &invalid_request($r,$params,\%errors);
             return OK;
         }
     } else {
-        $errors{23} = 1;
+        $errors{24} = 1;
         &invalid_request($r,$params,\%errors);
         return OK;
     }
@@ -219,7 +283,6 @@
 # Store result if one was sent in a valid format. 
 #
 
-
     my ($result,$resulttype,$lang,$pcf);
     if (exists($params->{'result_resultvaluesourcedid'})) {
         $resulttype = $params->{'result_resultvaluesourcedid'};
Index: loncom/lti/ltiroster.pm
diff -u loncom/lti/ltiroster.pm:1.3 loncom/lti/ltiroster.pm:1.4
--- loncom/lti/ltiroster.pm:1.3	Mon Dec 18 23:59:31 2017
+++ loncom/lti/ltiroster.pm	Tue Aug 14 21:42:36 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # LTI Consumer Module to respond to a course roster request.
 #
-# $Id: ltiroster.pm,v 1.3 2017/12/18 23:59:31 raeburn Exp $
+# $Id: ltiroster.pm,v 1.4 2018/08/14 21:42:36 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -32,6 +32,7 @@
 use Apache::Constants qw(:common :http);
 use Encode;
 use Digest::SHA;
+use URI::Escape;
 use Apache::lonnet;
 use Apache::loncommon;
 use Apache::lonacc;
@@ -41,14 +42,36 @@
 sub handler {
     my $r = shift;
     my %errors;
+    my $params = {};
+    my ($oauthtype,$authheader);
+#
+# Retrieve content type from headers
+#
+    my $content_type = $r->headers_in->get('Content-Type');
+    if ($content_type eq 'application/xml') {
+        $oauthtype = 'consumer';
+#
+# Retrieve OAuth data sent by LTI Provider from Authorization header
+#
+        $authheader = $r->headers_in->get('Authorization');
+        my ($authtype,$valuestr) = ($authheader =~ /^(OAuth)\s+(.+)$/i);
+        if (lc($authtype) eq 'oauth') {
+            foreach my $pair (split(/\s*,\s*/,$valuestr)) {
+                my ($key,$value) = split(/=/,$pair);
+                $value =~ s /(^"|"$)//g;
+                $params->{$key} = URI::Escape::uri_unescape($value);
+            }
+        }
+    } else {
+        $oauthtype = 'request token';
 #
 # Retrieve data POSTed by LTI Provider
 #
-    &Apache::lonacc::get_posted_cgi($r);
-    my $params = {};
-    foreach my $key (sort(keys(%env))) {
-        if ($key =~ /^form\.(.+)$/) {
-            $params->{$1} = $env{$key};
+        &Apache::lonacc::get_posted_cgi($r);
+        foreach my $key (sort(keys(%env))) {
+            if ($key =~ /^form\.(.+)$/) {
+                $params->{$1} = $env{$key};
+            }
         }
     }
 
@@ -124,7 +147,7 @@
     }
     unless (LONCAPA::ltiutils::verify_request($params,$protocol,$r->hostname,$r->uri,
                                               $env{'request.method'},$consumer_secret,
-                                              \%errors)) {
+                                              $params,$authheader,\%errors)) {
         &invalid_request($r,\%errors);
         return OK;
     }
Index: loncom/lti/ltiutils.pm
diff -u loncom/lti/ltiutils.pm:1.14 loncom/lti/ltiutils.pm:1.15
--- loncom/lti/ltiutils.pm:1.14	Tue Aug 14 17:24:21 2018
+++ loncom/lti/ltiutils.pm	Tue Aug 14 21:42:36 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA LTI interactions 
 #
-# $Id: ltiutils.pm,v 1.14 2018/08/14 17:24:21 raeburn Exp $
+# $Id: ltiutils.pm,v 1.15 2018/08/14 21:42:36 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -241,12 +241,26 @@
 #
 
 sub verify_request {
-    my ($params,$protocol,$hostname,$requri,$reqmethod,$consumer_secret,$errors) = @_;
-    return unless (ref($errors) eq 'HASH');
-    my $request = Net::OAuth->request('request token')->from_hash($params,
-                                       request_url => $protocol.'://'.$hostname.$requri,
-                                       request_method => $reqmethod,
-                                       consumer_secret => $consumer_secret,);
+    my ($oauthtype,$protocol,$hostname,$requri,$reqmethod,$consumer_secret,$params,
+        $authheaders,$errors) = @_;
+    unless (ref($errors) eq 'HASH') {
+        $errors->{15} = 1;
+        return;
+    }
+    my $request;
+    if ($oauthtype eq 'consumer') {
+        my $oauthreq = Net::OAuth->request('consumer');
+        $oauthreq->add_required_message_params('body_hash');
+        $request = $oauthreq->from_authorization_header($authheaders,
+                                  request_url => $protocol.'://'.$hostname.$requri,
+                                  request_method => $reqmethod,
+                                  consumer_secret => $consumer_secret,);
+    } else {
+        $request = Net::OAuth->request('request token')->from_hash($params,
+                                  request_url => $protocol.'://'.$hostname.$requri,
+                                  request_method => $reqmethod,
+                                  consumer_secret => $consumer_secret,);
+    }
     unless ($request->verify()) {
         $errors->{15} = 1;
         return;
@@ -296,7 +310,7 @@
                 if ($expected_sig eq $sigrec) {
                     return 1;
                 } else {
-                    $errors->{17} = 1;
+                    $errors->{18} = 1;
                 }
             } elsif ($context eq 'roster') {
                 my $uniqid = $digsymb.':::'.$cdom.'_'.$cnum;
@@ -304,14 +318,14 @@
                 if ($expected_sig eq $sigrec) {
                     return 1;
                 } else {
-                    $errors->{18} = 1;
+                    $errors->{19} = 1;
                 }
             }
         } else {
-            $errors->{19} = 1;
+            $errors->{20} = 1;
         }
     } else {
-        $errors->{20} = 1;
+        $errors->{21} = 1;
     }
     return;
 }
@@ -344,7 +358,7 @@
             extra_params => $paramsref,
             version      => '1.0',
             );
-    $request->sign;
+    $request->sign();
     return $request->to_hash();
 }
 
@@ -466,6 +480,47 @@
 }
 
 #
+# LON-CAPA as LTI Consumer
+#
+# Parse XML containing grade data sent by an LTI Provider
+#
+
+sub parse_grade_xml {
+    my ($xml) = @_;
+    my %data = ();
+    my $count = 0;
+    my @state = ();
+    my $p = HTML::Parser->new(
+        xml_mode => 1,
+        start_h =>
+            [sub {
+                my ($tagname, $attr) = @_;
+                push(@state,$tagname);
+                if ("@state" eq "imsx_POXEnvelopeRequest imsx_POXBody replaceResultRequest resultRecord") {
+                    $count ++;
+                }
+            }, "tagname, attr"],
+        text_h =>
+            [sub {
+                my ($text) = @_;
+                if ("@state" eq "imsx_POXEnvelopeRequest imsx_POXBody replaceResultRequest resultRecord sourcedGUID sourcedId") {
+                    $data{$count}{sourcedid} = $text;
+                } elsif ("@state" eq "imsx_POXEnvelopeRequest imsx_POXBody replaceResultRequest resultRecord result resultScore textString") {                               
+                    $data{$count}{score} = $text;
+                }
+            }, "dtext"],
+        end_h =>
+            [sub {
+                 my ($tagname) = @_;
+                 pop @state;
+                }, "tagname"],
+    );
+    $p->parse($xml);
+    $p->eof;
+    return %data;
+}
+
+#
 # LON-CAPA as LTI Provider
 #
 # Use the part of the launch URL after /adm/lti to determine
@@ -651,7 +706,7 @@
 #
 
 sub send_grade {
-    my ($id,$url,$ckey,$secret,$scoretype,$total,$possible) = @_;
+    my ($id,$url,$ckey,$secret,$scoretype,$sigmethod,$msgformat,$total,$possible) = @_;
     my $score;
     if ($possible > 0) {
         if ($scoretype eq 'ratio') {
@@ -664,30 +719,91 @@
             $score = sprintf("%.2f",$score);
         }
     }
-    my $date = &Apache::loncommon::utc_string(time);
-    my %ltiparams = (
-        lti_version                   => 'LTI-1p0',
-        lti_message_type              => 'basic-lis-updateresult',
-        sourcedid                     => $id,
-        result_resultscore_textstring => $score,
-        result_resultscore_language   => 'en-US',
-        result_resultvaluesourcedid   => $scoretype,
-        result_statusofresult         => 'final',
-        result_date                   => $date,
-    );
-    my $hashref = &sign_params($url,$ckey,$secret,'',\%ltiparams);
-    if (ref($hashref) eq 'HASH') {
-        my $request=new HTTP::Request('POST',$url);
-        $request->content(join('&',map {
-                          my $name = escape($_);
-                          "$name=" . ( ref($hashref->{$_}) eq 'ARRAY'
-                          ? join("&$name=", map {escape($_) } @{$hashref->{$_}})
-                          : &escape($hashref->{$_}) );
-        } keys(%{$hashref})));
-        my $response = &LONCAPA::LWPReq::makerequest('',$request,'','',10);
-        my $message=$response->status_line;
-#FIXME Handle case where pass back of score to LTI Consumer failed.
+    if ($sigmethod eq '') {
+        $sigmethod = 'HMAC-SHA1';
     }
+    my $request;
+    if ($msgformat eq '1.0') {
+        my $date = &Apache::loncommon::utc_string(time);
+        my %ltiparams = (
+            lti_version                   => 'LTI-1p0',
+            lti_message_type              => 'basic-lis-updateresult',
+            sourcedid                     => $id,
+            result_resultscore_textstring => $score,
+            result_resultscore_language   => 'en-US',
+            result_resultvaluesourcedid   => $scoretype,
+            result_statusofresult         => 'final',
+            result_date                   => $date,
+        );
+        my $hashref = &sign_params($url,$ckey,$secret,$sigmethod,\%ltiparams);
+        if (ref($hashref) eq 'HASH') {
+            $request=new HTTP::Request('POST',$url);
+            $request->content(join('&',map {
+                              my $name = escape($_);
+                              "$name=" . ( ref($hashref->{$_}) eq 'ARRAY'
+                              ? join("&$name=", map {escape($_) } @{$hashref->{$_}})
+                              : &escape($hashref->{$_}) );
+                              } keys(%{$hashref})));
+        }
+    } else {
+        srand( time() ^ ($$ + ($$ << 15))  ); # Seed rand.
+        my $nonce = Digest::SHA::sha1_hex(sprintf("%06x%06x",rand(0xfffff0),rand(0xfffff0)));
+        my $uniqmsgid = int(rand(2**32));
+        my $gradexml = <<END;
+<?xml version = "1.0" encoding = "UTF-8"?>
+<imsx_POXEnvelopeRequest xmlns = "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">
+  <imsx_POXHeader>
+    <imsx_POXRequestHeaderInfo>
+      <imsx_version>V1.0</imsx_version>
+      <imsx_messageIdentifier>$uniqmsgid</imsx_messageIdentifier>
+    </imsx_POXRequestHeaderInfo>
+  </imsx_POXHeader>
+  <imsx_POXBody>
+    <replaceResultRequest>
+      <resultRecord>
+	<sourcedGUID>
+	  <sourcedId>$id</sourcedId>
+	</sourcedGUID>
+	<result>
+	  <resultScore>
+	    <language>en</language>
+	    <textString>$score</textString>
+	  </resultScore>
+	</result>
+      </resultRecord>
+    </replaceResultRequest>
+  </imsx_POXBody>
+</imsx_POXEnvelopeRequest>
+END
+        chomp($gradexml);
+        my $bodyhash = Digest::SHA::sha1_base64($gradexml);
+        while (length($bodyhash) % 4) {
+            $bodyhash .= '=';
+        }
+        my $gradereq = Net::OAuth->request('consumer')->new(
+                           consumer_key => $ckey,
+                           consumer_secret => $secret,
+                           request_url => $url,
+                           request_method => 'POST',
+                           signature_method => $sigmethod,
+                           timestamp => time(),
+                           nonce => $nonce,
+                           body_hash => $bodyhash,
+        );
+        $gradereq->sign();
+        $request = HTTP::Request->new(
+	               $gradereq->request_method,
+	               $gradereq->request_url,
+	               [
+		           'Authorization' => $gradereq->to_authorization_header,
+		           'Content-Type'  => 'application/xml',
+	               ],
+	               $gradexml,
+        );
+    }
+    my $response = &LONCAPA::LWPReq::makerequest('',$request,'','',10);
+    my $message=$response->status_line;
+#FIXME Handle case where pass back of score to LTI Consumer failed.
 }
 
 #
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.336 loncom/interface/domainprefs.pm:1.337
--- loncom/interface/domainprefs.pm:1.336	Thu Jul 26 14:59:48 2018
+++ loncom/interface/domainprefs.pm	Tue Aug 14 21:42:39 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.336 2018/07/26 14:59:48 raeburn Exp $
+# $Id: domainprefs.pm,v 1.337 2018/08/14 21:42:39 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -2817,27 +2817,40 @@
 // <![CDATA[
 
 function toggleLTI(form,setting,item) {
-    if ((setting == 'user') || (setting == 'crs')) {
+    if ((setting == 'user') || (setting == 'crs') || (setting == 'passback')) {
         var radioname = '';
         var divid = '';
         if (setting == 'user') {
             radioname = 'lti_mapuser_'+item;
             divid = 'lti_userfield_'+item;
-        } else {
+        } else if (settings == 'crs') {
             radioname = 'lti_mapcrs_'+item;
             divid = 'lti_crsfield_'+item;
+        } else {
+            radioname = 'lti_passbackformat_'+item;
+            divid =  'lti_passback_'+item;
         }
         var num = form.elements[radioname].length;
         if (num) {
             var setvis = '';
             for (var i=0; i<num; i++) {
                if (form.elements[radioname][i].checked) {
-                   if (form.elements[radioname][i].value == 'other') {
-                       if (document.getElementById(divid)) {
-                           document.getElementById(divid).style.display = 'inline-block';
+                   if (setting == 'passback') {
+                       if (form.elements[radioname][i].value == '1') {
+                           if (document.getElementById(divid)) {
+                               document.getElementById(divid).style.display = 'inline-block';
+                           }
+                           setvis = 1;
+                           break;
+                       }
+                   } else {
+                       if (form.elements[radioname][i].value == 'other') {
+                           if (document.getElementById(divid)) {
+                               document.getElementById(divid).style.display = 'inline-block';
+                           }
+                           setvis = 1;
+                           break;
                        }
-                       setvis = 1;
-                       break;
                    }
                } 
             }
@@ -4751,6 +4764,7 @@
     my $crsfieldsty = 'none';
     my $crssecfieldsty = 'none';
     my $secsrcfieldsty = 'none';
+    my $passbacksty = 'none';
     my $lcauthparm;
     my $lcauthparmstyle = 'display:none';
     my $lcauthparmtext;
@@ -4991,23 +5005,43 @@
                $checked{'crssecsrc'}{'other'}.$onclicksecsrc.' />'.&mt('Other').
                '</label></span></div><div class="LC_floatleft" style="display:'.$secsrcfieldsty.';" id="lti_secsrcfield_'.$num.'">'.
                '<input type="text" name="lti_customsection_'.$num.'" value="'.$crssecsrc.'" />'.
-               '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'; 
-    foreach my $extra ('passback','roster') {
+               '</div><div style="padding:0;clear:both;margin:0;border:0"></div>';
+    my ($pb1p1chk,$pb1p0chk,$onclickpb);
+    foreach my $extra ('roster','passback') {
         my $checkedon = '';
         my $checkedoff = ' checked="checked"';
+        if ($extra eq 'passback') {
+            $pb1p1chk = ' checked="checked"';
+            $pb1p0chk = '';
+            $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"'; 
+        } else {
+            $onclickpb = ''; 
+        }
         if (ref($current) eq 'HASH') {
             if (($current->{$extra})) {
                 $checkedon = $checkedoff;
                 $checkedoff = '';
+                if ($extra eq 'passback') {
+                    $passbacksty = 'inline-block';
+                }
+                if ($current->{'passbackformat'} eq '1.0') {
+                    $pb1p0chk =  ' checked="checked"';
+                    $pb1p1chk = '';
+                }
             }
         }
         $output .= $lt{$extra}.' '.
-                   '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="0"'.$checkedoff.' />'.
+                   '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="0"'.$checkedoff.$onclickpb.' />'.
                    &mt('No').'</label>'.(' 'x2).
-                   '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="1"'.$checkedon.' />'.
+                   '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="1"'.$checkedon.$onclickpb' />'.
                    &mt('Yes').'</label><br />';
     }
-    $output .= '</fieldset>'.
+    $output .= '<div class="LC_floatleft" style="display:'.$passbacksty.';" id="lti_passback_'.$num.'">'.
+               '<span class="LC_nobreak">'.&mt('Grade format').
+               '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.1"'.$pb1p1chk.' />'.
+               &mt('Outcomes Service (1.1)').'</label>'.(' 'x2).
+               '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'.
+               &mt('Outcomes Extension (1.0)').'</label></span></div></fieldset>'.
                '<fieldset><legend>'.&mt('Course defaults (Course Coordinator can override)').'</legend>'.
                '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.': '.
                '<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'.
@@ -11714,7 +11748,13 @@
                 $confhash{$itemid}{$field} = 1;
             }
         }
-
+        if ($env{'form.lti_passback_'.$idx}) {
+            if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') {
+                $confhash{$itemid}{'passbackformat'} = '1.0';
+            } else {
+                $confhash{$itemid}{'passbackformat'} = '1.1';
+            }
+        }
         if ($env{'form.lti_topmenu_'.$idx} || $env{'form.lti_inlinemenu_'.$idx}) {
             $confhash{$itemid}{lcmenu} = [];
             my @possmenu = &Apache::loncommon::get_env_multiple('form.lti_menuitem_'.$idx);
@@ -11733,6 +11773,13 @@
                     $changes{$itemid} = 1;
                 }
             }
+            unless ($changes{$itemid}) {
+                if ($domconfig{$action}{$itemid}{'passback'} eq $confhash{$itemid}{'passback'}) {
+                    if ($domconfig{$action}{$itemid}{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {
+                        $changes{$itemid} = 1;
+                    }
+                }
+            }
             foreach my $field ('makeuser','mapcrstype','selfenroll','instdata','lcmenu') {
                 unless ($changes{$itemid}) {
                     if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') {
@@ -11949,6 +11996,13 @@
                         $resulttext .= '<li>'.$lt{$item}.': ';
                         if ($confhash{$itemid}{$item}) {
                             $resulttext .= &mt('Yes');
+                            if ($item eq 'passback') {
+                                if ($confhash{$itemid}{'passbackformat'} eq '1.0') {
+                                    $resulttext .= ' ('.&mt('Outcomes Extension (1.0)').')';
+                                } elsif ($confhash{$itemid}{'passbackformat'} eq '1.1') {
+                                    $resulttext .= ' ('.&mt('Outcomes Service (1.1)').')';
+                                }
+                            }
                         } else {
                             $resulttext .= &mt('No');
                         }
Index: loncom/interface/lonconfigsettings.pm
diff -u loncom/interface/lonconfigsettings.pm:1.43 loncom/interface/lonconfigsettings.pm:1.44
--- loncom/interface/lonconfigsettings.pm:1.43	Tue May  8 01:48:18 2018
+++ loncom/interface/lonconfigsettings.pm	Tue Aug 14 21:42:40 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: lonconfigsettings.pm,v 1.43 2018/05/08 01:48:18 raeburn Exp $
+# $Id: lonconfigsettings.pm,v 1.44 2018/08/14 21:42:40 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -220,7 +220,8 @@
                            "toggleLTI(document.display,'crs','add');".
                            "toggleLTI(document.display,'sec','add');".
                            "toggleLTI(document.display,'lcauth','add');".
-                           "toggleLTI(document.display,'lcmenu','add');";
+                           "toggleLTI(document.display,'lcmenu','add');".
+                           "toggleLTI(document.display,'passback','add');";
                 if (ref($values) eq 'HASH') {
                     if (ref($values->{'lti'}) eq 'HASH') {
                         my $numlti = scalar(keys(%{$values->{'lti'}}));
@@ -229,7 +230,8 @@
                                        "toggleLTI(document.display,'crs','$i');".
                                        "toggleLTI(document.display,'sec','$i');".
                                        "toggleLTI(document.display,'lcauth','$i');".
-                                       "toggleLTI(document.display,'lcmenu','$i');";
+                                       "toggleLTI(document.display,'lcmenu','$i');".
+                                       "toggleLTI(document.display,'passback','$i');";
                         }
                     }
                 }


More information about the LON-CAPA-cvs mailing list