Add LTI launch capability to speedgrader

Closes CNVS-29144

Test Plan:
   - Add an external tool assignment
   - Passback a URL type score which matches the launch URL of the tool
   - Confirm that speedgrading that page launches into the tool

Change-Id: Iff3e00ece10c6b4ff891e4af90053c88a677db6a
Reviewed-on: https://gerrit.instructure.com/79526
Reviewed-by: Davis McClellan <dmcclellan@instructure.com>
Reviewed-by: Cameron Matheson <cameron@instructure.com>
Tested-by: Jenkins
Reviewed-by: Nathan Mills <nathanm@instructure.com>
QA-Review: Michael Hargiss <mhargiss@instructure.com>
Product-Review: Jason Sparks <jsparks@instructure.com>
This commit is contained in:
Ryan Taylor 2016-05-12 21:51:31 -06:00
parent 6f038299f4
commit 167b46924a
9 changed files with 65 additions and 23 deletions

View File

@ -141,6 +141,7 @@ class SubmissionsController < ApplicationController
"online_url" => ["url"].freeze,
"online_upload" => ["file_ids"].freeze,
"media_recording" => ["media_comment_id", "media_comment_type"].freeze,
"basic_lti_launch" => ["url"].freeze
}.freeze
# @API Submit an assignment
@ -158,7 +159,7 @@ class SubmissionsController < ApplicationController
# @argument comment[text_comment] [String]
# Include a textual comment with the submission.
#
# @argument submission[submission_type] [Required, String, "online_text_entry"|"online_url"|"online_upload"|"media_recording"]
# @argument submission[submission_type] [Required, String, "online_text_entry"|"online_url"|"online_upload"|"media_recording"|"basic_lti_launch"]
# The type of submission being made. The assignment submission_types must
# include this submission type as an allowed option, or the submission will be rejected with a 400 error.
#
@ -177,7 +178,7 @@ class SubmissionsController < ApplicationController
# Submit the assignment as a URL. The URL scheme must be "http" or "https",
# no "ftp" or other URL schemes are allowed. If no scheme is given (e.g.
# "www.example.com") then "http" will be assumed. Requires a submission_type
# of "online_url".
# of "online_url" or "basic_lti_launch".
#
# @argument submission[file_ids][] [Integer]
# Submit the assignment as a set of one or more previously uploaded files

View File

@ -1321,7 +1321,7 @@ class Assignment < ActiveRecord::Base
submitted = case opts[:submission_type]
when "online_text_entry"
opts[:body].present?
when "online_url"
when "online_url", "basic_lti_launch"
opts[:url].present?
when "online_upload"
opts[:attachments].size > 0

View File

@ -2,7 +2,6 @@ require_relative '../assignment'
class Assignment
class SpeedGrader
def initialize(assignment, user, avatars: false, grading_role: :grader)
@assignment = assignment
@user = user
@ -117,7 +116,7 @@ class Assignment
res[:submissions] = submissions.map do |sub|
json = sub.as_json(:include_root => false,
:methods => [:submission_history, :late],
:methods => [:submission_history, :late, :external_tool_url],
:only => submission_fields
).merge("from_enrollment_type" => enrollment_types_by_id[sub.user_id])

View File

@ -3,8 +3,9 @@ module Lti
SUBMISSION_TYPES_MAP = {
'online_upload' => 'file',
'online_url' => 'url',
'external_tool' => ['url', 'text']
}
'external_tool' => ['url', 'text'].freeze,
'basic_lti_launch' => 'url'
}.freeze
def initialize(assignment, source_id = nil)
@assignment = assignment

View File

@ -482,6 +482,13 @@ class Submission < ActiveRecord::Base
turnitin_data.select{|_, v| v.is_a?(Hash) && v.key?(:outcome_response)}.any?
end
def external_tool_url
if self.submission_type == 'basic_lti_launch'
base_url = "#{HostUrl.protocol}://#{HostUrl.default_host}"
base_url + "/courses/#{assignment.context.id}/external_tools/retrieve?display=borderless&assignment_id=#{assignment.id}&url=#{URI.encode(url)}"
end
end
def touch_graders
self.class.connection.after_transaction_commit do
if self.assignment && self.user && self.assignment.context.is_a?(Course)

View File

@ -124,6 +124,10 @@ module BasicLTI
@lti_request && @lti_request.at_css('imsx_POXBody > replaceResultRequest > resultRecord > result > resultData > url').try(:content)
end
def result_data_launch_url
@lti_request && @lti_request.at_css('imsx_POXBody > replaceResultRequest > resultRecord > result > resultData > ltiLaunchUrl').try(:content)
end
def to_xml
xml = LtiResponse.envelope.dup
xml.at_css('imsx_POXHeader imsx_statusInfo imsx_codeMajor').content = code_major
@ -186,7 +190,7 @@ module BasicLTI
protected
def handle_replaceResult(tool, course, assignment, user)
def handle_replaceResult(_tool, _course, assignment, user)
text_value = self.result_score
new_score = Float(text_value) rescue false
raw_score = Float(self.result_total_score) rescue false
@ -196,9 +200,12 @@ module BasicLTI
if text = result_data_text
submission_hash[:body] = text
submission_hash[:submission_type] = 'online_text_entry'
elsif url = result_data_url
elsif (url = result_data_url)
submission_hash[:url] = url
submission_hash[:submission_type] = 'online_url'
elsif (launch_url = result_data_launch_url)
submission_hash[:url] = launch_url
submission_hash[:submission_type] = 'basic_lti_launch'
end
old_submission = assignment.submissions.where(user_id: user.id).first

View File

@ -1772,13 +1772,11 @@ define([
$iframe_holder.show().loadDocPreview($.extend(previewOptions, {
crocodoc_session_url: (attachment.provisional_crocodoc_url || attachment.crocodoc_url)
}));
}
else if (attachment && attachment.canvadoc_url) {
} else if (attachment && attachment.canvadoc_url) {
$iframe_holder.show().loadDocPreview($.extend(previewOptions, {
canvadoc_session_url: attachment.canvadoc_url
}));
}
else if ( attachment && ($.isPreviewable(attachment.content_type, 'google')) ) {
} else if ( attachment && ($.isPreviewable(attachment.content_type, 'google')) ) {
if (!INST.disableCrocodocPreviews) $no_annotation_warning.show();
var currentStudentIDAsOfAjaxCall = this.currentStudent.id;
@ -1787,16 +1785,20 @@ define([
return(currentStudentIDAsOfAjaxCall == this.currentStudent.id);
},this)});
$iframe_holder.show().loadDocPreview(previewOptions);
}
else if (attachment && browserableCssClasses.test(attachment.mime_class)) {
var src = unescape($submission_file_hidden.find('.display_name').attr('href'))
.replace("{{submissionId}}", this.currentStudent.submission.user_id)
.replace("{{attachmentId}}", attachment.id);
$iframe_holder.html('<iframe src="'+htmlEscape(src)+'" frameborder="0" id="speedgrader_iframe"></iframe>').show();
}
else {
//load in the iframe preview. if we are viewing a past version of the file pass the version to preview in the url
$iframe_holder.html($.raw(
} else if (attachment && browserableCssClasses.test(attachment.mime_class)) {
var src = unescape($submission_file_hidden.find('.display_name').attr('href'))
.replace("{{submissionId}}", this.currentStudent.submission.user_id)
.replace("{{attachmentId}}", attachment.id);
$iframe_holder.html('<iframe src="'+htmlEscape(src)+'" frameborder="0" id="speedgrader_iframe"></iframe>').show();
} else if (this.currentStudent.submission.external_tool_url) {
$iframe_holder.html(
$.raw('<iframe id="speedgrader_iframe" src="' +
htmlEscape(this.currentStudent.submission.external_tool_url) + '" class="tool_launch"></iframe>'
)
).show();
} else {
//load in the iframe preview. if we are viewing a past version of the file pass the version to preview in the url
$iframe_holder.html($.raw(
'<iframe id="speedgrader_iframe" src="' + htmlEscape('/courses/' + jsonData.context_id +
'/assignments/' + this.currentStudent.submission.assignment_id +
'/submissions/' + this.currentStudent.submission.user_id +

View File

@ -253,5 +253,15 @@ describe BasicLTI::BasicOutcomes do
expect(submission.submission_type).to eq 'online_upload'
end
it 'accepts LTI launch URLs as a data format with a specific submission type' do
xml.at_css('text').replace('<ltiLaunchUrl>http://example.com/launch</ltiLaunchUrl>')
request = BasicLTI::BasicOutcomes.process_request(tool, xml)
expect(request.code_major).to eq 'success'
expect(request.handle_request(tool)).to be_truthy
submission = assignment.submissions.where(user_id: @user.id).first
expect(submission.submission_type).to eq 'basic_lti_launch'
end
end
end

View File

@ -749,6 +749,21 @@ describe Submission do
end
end
context '#external_tool_url' do
let(:submission) { Submission.new }
let(:lti_submission) { @assignment.submit_homework @user, submission_type: 'basic_lti_launch', url: 'http://www.example.com' }
context 'submission_type of "basic_lti_launch"' do
it 'returns a url containing the submitted url' do
expect(lti_submission.external_tool_url).to include(lti_submission.url)
end
end
context 'submission_type of anything other than "basic_lti_launch"' do
it 'returns nothing' do
expect(submission.external_tool_url).to be_nil
end
end
end
it "should return the correct quiz_submission_version" do
# see redmine #6048