[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