Add variable substitution capabilities to TCP
Fixes PLAT-2235 Test Plan: - Get the Canvas TCP and verify it contains all capabilities listed in lib/lti/capabilities_helper.rb:3 in its capability_offered section. - Install an LTI2 tool, launch it, and verify none of the following parameters are sent in the launch: * launch_presentation_document_target * launch_presentation_locale * tool_consumer_instance_guid * lis_course_section_sourcedid * roles * lis_person_sourcedid - Each of the above params now have an associated capability offered by Canvas. If a TP wants one of the above parameters sent in their tool launch they must include the associated capability in their enabled_capability section of the tool proxy. Verify adding the associated capability in the tool profile causes the paramter to be sent in the tool launch. See variable_expander.rb docs for a mapping of capabilities to variable names Change-Id: I027d079d9d3cf53715fcf8ca4d9d8759af02cb88 Reviewed-on: https://gerrit.instructure.com/101336 Reviewed-by: Nathan Mills <nathanm@instructure.com> Tested-by: Jenkins QA-Review: August Thornton <august@instructure.com> Product-Review: Weston Dransfield <wdransfield@instructure.com>
This commit is contained in:
parent
fb3966a62d
commit
adff709f9d
|
@ -88,27 +88,32 @@ module Lti
|
|||
oauth_consumer_key: tool_proxy.guid,
|
||||
lti_version: IMS::LTI::Models::LTIModel::LTI_VERSION_2P0,
|
||||
resource_link_id: build_resource_link_id(message_handler),
|
||||
context_id: Lti::Asset.opaque_identifier_for(@context),
|
||||
roles: Lti::SubstitutionsHelper.new(@context, @domain_root_account, @current_user).all_roles('lis2'),
|
||||
context_id: Lti::Asset.opaque_identifier_for(@context)
|
||||
}
|
||||
launch_params.merge! enabled_parameters(tool_proxy)
|
||||
|
||||
if params[:secure_params].present?
|
||||
secure_params = Canvas::Security.decode_jwt(params[:secure_params])
|
||||
launch_params.merge!({ext_lti_assignment_id: secure_params[:lti_assignment_id]}) if secure_params[:lti_assignment_id].present?
|
||||
end
|
||||
|
||||
@lti_launch = Launch.new
|
||||
tag = find_tag
|
||||
custom_param_opts = prep_tool_settings(message_handler.parameters, tool_proxy, launch_params[:resource_link_id])
|
||||
custom_param_opts[:content_tag] = tag if tag
|
||||
|
||||
variable_expander = create_variable_expander(custom_param_opts.merge(tool: tool_proxy))
|
||||
launch_params.merge! enabled_parameters(tool_proxy, message_handler, variable_expander)
|
||||
|
||||
message = IMS::LTI::Models::Messages::BasicLTILaunchRequest.new(launch_params)
|
||||
message.user_id = Lti::Asset.opaque_identifier_for(@current_user) if @current_user
|
||||
@active_tab = message_handler.asset_string
|
||||
@lti_launch = Launch.new
|
||||
@lti_launch.resource_url = message.launch_url
|
||||
@lti_launch.link_text = resource_handler.name
|
||||
@lti_launch.launch_type = message.launch_presentation_document_target
|
||||
|
||||
tag = find_tag
|
||||
module_sequence(tag) if tag
|
||||
custom_param_opts = prep_tool_settings(message_handler.parameters, tool_proxy, message.resource_link_id)
|
||||
custom_param_opts[:content_tag] = tag if tag
|
||||
message.add_custom_params(custom_params(message_handler.parameters, custom_param_opts.merge(tool: tool_proxy)))
|
||||
|
||||
message.add_custom_params(custom_params(message_handler.parameters, variable_expander))
|
||||
message.add_custom_params(ToolSetting.custom_settings(tool_proxy.id, @context, message.resource_link_id))
|
||||
@lti_launch.params = message.signed_post_params(tool_proxy.shared_secret)
|
||||
|
||||
|
@ -133,10 +138,11 @@ module Lti
|
|||
|
||||
private
|
||||
|
||||
def enabled_parameters(tp)
|
||||
param_capabilities_hash = CapabilitiesHelper.new(@context).parameter_capabilities_hash
|
||||
enabled_capabilities = IMS::LTI::Models::ToolProxy.from_json(tp.raw_data).enabled_capabilities
|
||||
param_capabilities_hash.each_with_object({}) { |(k, v), hash| hash[k] = v if enabled_capabilities.include? k }
|
||||
def enabled_parameters(tp, mh, variable_expander)
|
||||
tool_proxy = IMS::LTI::Models::ToolProxy.from_json(tp.raw_data)
|
||||
enabled_capability = tool_proxy.enabled_capabilities
|
||||
enabled_capability = enabled_capability.concat(mh.capabilities).uniq if mh.capabilities.present?
|
||||
CapabilitiesHelper.capability_params_hash(enabled_capability, variable_expander)
|
||||
end
|
||||
|
||||
def module_sequence(tag)
|
||||
|
@ -155,9 +161,9 @@ module Lti
|
|||
end
|
||||
end
|
||||
|
||||
def custom_params(parameters, opts = {})
|
||||
def custom_params(parameters, variable_expander)
|
||||
params = IMS::LTI::Models::Parameter.from_json(parameters || [])
|
||||
IMS::LTI::Models::Parameter.process_params(params, create_variable_expander(opts))
|
||||
IMS::LTI::Models::Parameter.process_params(params, variable_expander)
|
||||
end
|
||||
|
||||
def find_binding(tool_proxy)
|
||||
|
|
|
@ -9,7 +9,6 @@ module Lti
|
|||
|
||||
CAPABILITIES = %w(
|
||||
basic-lti-launch-request
|
||||
User.id
|
||||
Canvas.api.domain
|
||||
LtiLink.custom.url
|
||||
ToolProxyBinding.custom.url
|
||||
|
@ -21,18 +20,11 @@ module Lti
|
|||
Canvas.placements.postGrades
|
||||
Canvas.placements.similarityDetection
|
||||
User.username
|
||||
Person.email.primary
|
||||
vnd.Canvas.Person.email.sis
|
||||
Person.name.given
|
||||
Person.name.family
|
||||
Person.name.full
|
||||
CourseSection.sourcedId
|
||||
Person.sourcedId
|
||||
Membership.role
|
||||
ToolConsumerProfile.url
|
||||
Security.splitSecret
|
||||
Context.id
|
||||
).concat(CapabilitiesHelper.new(@context).parameter_capabilities).freeze
|
||||
).concat(CapabilitiesHelper.supported_capabilities).freeze
|
||||
|
||||
RESTRICTED_CAPABILITIES = %W(
|
||||
#{ORIGINALITY_REPORT_SERVICE}.url
|
||||
|
|
|
@ -26,6 +26,9 @@ masquerading users. Additionally, when we don't provide enough information or c
|
|||
directly through LTI, tools can request everything they need to use the Canvas API for an even
|
||||
richer experience.
|
||||
|
||||
Some substitutions may be used as 'enabled_capabilities' for LTI2 tools. These substitutions have a
|
||||
'Launch Parameter' label indicating the parameter name that will be sent in the tool launch if enabled.
|
||||
|
||||
For more information on variable substitution, see the <a href="https://www.imsglobal.org/specs/ltiv1p1p1/implementation-guide#toc-9" target="_blank">IMS LTI specification.</a>
|
||||
|
||||
# Usage/Configuration
|
||||
|
@ -96,6 +99,33 @@ particular placement:
|
|||
```
|
||||
|
||||
# Supported Substitutions
|
||||
## ToolConsumerInstance.guid
|
||||
returns a unique identifier for the Tool Consumer (Canvas)
|
||||
|
||||
Launch Parameter: *tool_consumer_instance_guid*
|
||||
|
||||
```
|
||||
0dWtgJjjFWRNT41WdQMvrleejGgv7AynCVm3lmZ2:canvas-lms
|
||||
```
|
||||
|
||||
## Message.locale
|
||||
returns the current locale
|
||||
|
||||
Launch Parameter: *launch_presentation_locale*
|
||||
|
||||
```
|
||||
de
|
||||
```
|
||||
|
||||
## Message.documentTarget
|
||||
communicates the kind of browser window/frame where the Canvas has launched a tool
|
||||
|
||||
Launch Parameter: *launch_presentation_document_target*
|
||||
|
||||
```
|
||||
iframe
|
||||
```
|
||||
|
||||
## Canvas.api.domain
|
||||
returns the canvas domain for the current context. Should always be available.
|
||||
|
||||
|
@ -104,7 +134,7 @@ canvas.instructure.com
|
|||
```
|
||||
|
||||
## Canvas.api.collaborationMembers.url
|
||||
returns the api url for the members of the collaboration.
|
||||
returns the api url for the members of the collaboration.
|
||||
|
||||
```
|
||||
https://canvas.instructure.com/api/v1/collaborations/1/members
|
||||
|
@ -118,7 +148,7 @@ https://canvas.instructure.com
|
|||
```
|
||||
|
||||
## ToolProxyBinding.memberships.url
|
||||
returns the URL for the membership service associated with the current context.
|
||||
returns the URL for the membership service associated with the current context.
|
||||
|
||||
```
|
||||
https://canvas.instructure.com/api/lti/courses/1/membership_service
|
||||
|
@ -238,6 +268,8 @@ YYY-MM-DD HH:MM:SS -0700
|
|||
returns the current course sis source id. Only available when launched in a course.
|
||||
to return the section source id use Canvas.course.sectionIds
|
||||
|
||||
Launch Parameter: *lis_course_section_sourcedid*
|
||||
|
||||
```
|
||||
1234
|
||||
```
|
||||
|
@ -280,23 +312,35 @@ Only available when launched in a course that was copied (excludes cartridge imp
|
|||
|
||||
## Person.name.full
|
||||
Returns the full name of the launching user. Only available when launched by a logged in user.
|
||||
|
||||
Launch Parameter: *lis_person_name_full*
|
||||
|
||||
```
|
||||
John Doe
|
||||
```
|
||||
## Person.name.family
|
||||
Returns the last name of the launching user. Only available when launched by a logged in user.
|
||||
|
||||
Launch Parameter: *lis_person_name_family*
|
||||
|
||||
```
|
||||
Doe
|
||||
```
|
||||
|
||||
## Person.name.given
|
||||
Returns the last name of the launching user. Only available when launched by a logged in user.
|
||||
|
||||
Launch Parameter: *lis_person_name_given*
|
||||
|
||||
```
|
||||
John
|
||||
```
|
||||
|
||||
## Person.email.primary
|
||||
Returns the primary email of the launching user. Only available when launched by a logged in user.
|
||||
|
||||
Launch Parameter: *lis_person_contact_email_primary*
|
||||
|
||||
```
|
||||
john.doe@example.com
|
||||
```
|
||||
|
@ -316,12 +360,18 @@ America/Denver
|
|||
|
||||
## User.image
|
||||
Returns the profile picture URL of the launching user. Only available when launched by a logged in user.
|
||||
|
||||
Launch Parameter: *user_image*
|
||||
|
||||
```
|
||||
https://example.com/picture.jpg
|
||||
```
|
||||
|
||||
## User.id [duplicates Canvas.user.id and Canvas.user.loginId]
|
||||
Returns the Canvas user_id of the launching user. Only available when launched by a logged in user.
|
||||
|
||||
Launch Parameter: *user_id*
|
||||
|
||||
```
|
||||
420000000000042
|
||||
```
|
||||
|
@ -339,7 +389,7 @@ false
|
|||
```
|
||||
|
||||
## Canvas.group.contextIds
|
||||
returns the context ids for the groups the user belongs to in the course.
|
||||
returns the context ids for the groups the user belongs to in the course.
|
||||
|
||||
```
|
||||
1c16f0de65a080803785ecb3097da99872616f0d,d4d8d6ae1611e2c7581ce1b2f5c58019d928b79d,...
|
||||
|
@ -347,6 +397,9 @@ returns the context ids for the groups the user belongs to in the course.
|
|||
|
||||
## Membership.role
|
||||
Returns the <a href="https://www.imsglobal.org/specs/ltimemv1p0/specification-3">IMS LTI membership service</a> roles for filtering via query parameters. Only available when launched by a logged in user.
|
||||
|
||||
Launch Parameter: *roles*
|
||||
|
||||
```
|
||||
http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator
|
||||
```
|
||||
|
@ -579,4 +632,3 @@ Only available when an attachment is present and has usage rights defined.
|
|||
|
||||
## Canvas.file.usageRights.copyrightText
|
||||
Only available when an attachment is present and has usage rights defined.
|
||||
|
||||
|
|
|
@ -1,40 +1,29 @@
|
|||
module Lti
|
||||
class CapabilitiesHelper
|
||||
attr_accessor :context
|
||||
def initialize(context)
|
||||
@context = context
|
||||
SUPPORTED_CAPABILITIES = %w(ToolConsumerInstance.guid
|
||||
CourseSection.sourcedId
|
||||
Membership.role
|
||||
Person.email.primary
|
||||
Person.name.given
|
||||
Person.name.family
|
||||
Person.name.full
|
||||
Person.sourcedId
|
||||
User.id
|
||||
User.image
|
||||
Message.documentTarget
|
||||
Message.locale
|
||||
Membership.role).freeze
|
||||
|
||||
def self.supported_capabilities
|
||||
SUPPORTED_CAPABILITIES
|
||||
end
|
||||
|
||||
def parameter_capabilities_hash
|
||||
@_param_capabilities_hash ||= begin
|
||||
recommended_params.merge optional_params
|
||||
end
|
||||
def self.filter_capabilities(enabled_capability)
|
||||
enabled_capability & SUPPORTED_CAPABILITIES
|
||||
end
|
||||
|
||||
def parameter_capabilities
|
||||
parameter_capabilities_hash.keys
|
||||
def self.capability_params_hash(enabled_capability, variable_expander)
|
||||
variable_expander.enabled_capability_params(filter_capabilities(enabled_capability))
|
||||
end
|
||||
|
||||
def recommended_params
|
||||
{
|
||||
'launch_presentation_document_target' => IMS::LTI::Models::Messages::Message::LAUNCH_TARGET_IFRAME,
|
||||
'tool_consumer_instance_guid' => tc_instance_guid
|
||||
}
|
||||
end
|
||||
|
||||
def optional_params
|
||||
{
|
||||
'launch_presentation_locale' => I18n.locale || I18n.default_locale.to_s
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tc_instance_guid
|
||||
if context.respond_to?(:root_account) && context.root_account.present?
|
||||
context.root_account.lti_guid
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -93,6 +93,44 @@ module Lti
|
|||
end
|
||||
end
|
||||
|
||||
def enabled_capability_params(enabled_capabilities)
|
||||
enabled_capabilities.each_with_object({}) do |capability, hash|
|
||||
if (expansion = capability.respond_to?(:to_sym) && self.class.expansions["$#{capability}".to_sym])
|
||||
hash[expansion.default_name] = expansion.expand(self) if expansion.default_name.present?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# communicates the kind of browser window/frame where the Canvas has launched a tool
|
||||
# associated launch param name: launch_presentation_document_target
|
||||
# @example
|
||||
# ```
|
||||
# ifame
|
||||
# ```
|
||||
register_expansion 'Message.documentTarget', [],
|
||||
-> { IMS::LTI::Models::Messages::Message::LAUNCH_TARGET_IFRAME },
|
||||
default_name: 'launch_presentation_document_target'
|
||||
|
||||
# returns the current locale
|
||||
# associated launch param name: launch_presentation_locale
|
||||
# @example
|
||||
# ```
|
||||
# de
|
||||
# ```
|
||||
register_expansion 'Message.locale', [],
|
||||
-> { I18n.locale || I18n.default_locale },
|
||||
default_name: 'launch_presentation_locale'
|
||||
|
||||
# returns a unique identifier for the Tool Consumer (Canvas)
|
||||
# associated launch param name: 'tool_consumer_instance_guid'
|
||||
# @example
|
||||
# ```
|
||||
# 0dWtgJjjFWRNT41WdQMvrleejGgv7AynCVm3lmZ2:canvas-lms
|
||||
# ```
|
||||
register_expansion 'ToolConsumerInstance.guid', [],
|
||||
-> { @root_account.lti_guid },
|
||||
default_name: 'tool_consumer_instance_guid'
|
||||
|
||||
# returns the canvas domain for the current context.
|
||||
# @example
|
||||
# ```
|
||||
|
@ -282,13 +320,15 @@ module Lti
|
|||
|
||||
# returns the current course sis source id
|
||||
# to return the section source id use Canvas.course.sectionIds
|
||||
# associated launch param name: 'lis_course_section_sourcedid'
|
||||
# @example
|
||||
# ```
|
||||
# 1234
|
||||
# ```
|
||||
register_expansion 'CourseSection.sourcedId', [],
|
||||
-> { @context.sis_source_id },
|
||||
COURSE_GUARD
|
||||
COURSE_GUARD,
|
||||
default_name: 'lis_course_section_sourcedid'
|
||||
|
||||
# returns the current course enrollment state
|
||||
# @example
|
||||
|
@ -338,40 +378,48 @@ module Lti
|
|||
COURSE_GUARD
|
||||
|
||||
# Returns the full name of the launching user. Only available when launched by a logged in user.
|
||||
# associated launch param name: lis_person_name_full
|
||||
# @example
|
||||
# ```
|
||||
# John Doe
|
||||
# ```
|
||||
register_expansion 'Person.name.full', [],
|
||||
-> { @current_user.name },
|
||||
USER_GUARD
|
||||
USER_GUARD,
|
||||
default_name: 'lis_person_name_full'
|
||||
|
||||
# Returns the last name of the launching user. Only available when launched by a logged in user.
|
||||
# associated launch param name: 'lis_person_name_family'
|
||||
# @example
|
||||
# ```
|
||||
# Doe
|
||||
# ```
|
||||
register_expansion 'Person.name.family', [],
|
||||
-> { @current_user.last_name },
|
||||
USER_GUARD
|
||||
USER_GUARD,
|
||||
default_name: 'lis_person_name_family'
|
||||
|
||||
# Returns the first name of the launching user. Only available when launched by a logged in user.
|
||||
# associated launch param name: 'lis_person_name_given'
|
||||
# @example
|
||||
# ```
|
||||
# John
|
||||
# ```
|
||||
register_expansion 'Person.name.given', [],
|
||||
-> { @current_user.first_name },
|
||||
USER_GUARD
|
||||
USER_GUARD,
|
||||
default_name: 'lis_person_name_given'
|
||||
|
||||
# Returns the primary email of the launching user. Only available when launched by a logged in user.
|
||||
# associated launch param name: 'lis_person_contact_email_primary'
|
||||
# @example
|
||||
# ```
|
||||
# john.doe@example.com
|
||||
# ```
|
||||
register_expansion 'Person.email.primary', [],
|
||||
-> { @current_user.email },
|
||||
USER_GUARD
|
||||
USER_GUARD,
|
||||
default_name: 'lis_person_contact_email_primary'
|
||||
|
||||
|
||||
# Returns the institution assigned email of the launching user. Only available when launched by a logged in user that was added via SIS.
|
||||
|
@ -395,22 +443,26 @@ module Lti
|
|||
USER_GUARD
|
||||
|
||||
# Returns the profile picture URL of the launching user. Only available when launched by a logged in user.
|
||||
# associated launch param name: 'user_image'
|
||||
# @example
|
||||
# ```
|
||||
# https://example.com/picture.jpg
|
||||
# ```
|
||||
register_expansion 'User.image', [],
|
||||
-> { @current_user.avatar_url },
|
||||
USER_GUARD
|
||||
USER_GUARD,
|
||||
default_name: 'user_image'
|
||||
|
||||
# Returns the Canvas user_id of the launching user. Only available when launched by a logged in user.
|
||||
# associated launch param name: 'user_id'
|
||||
# @example
|
||||
# ```
|
||||
# 420000000000042
|
||||
# ```
|
||||
register_expansion 'User.id', [],
|
||||
-> { @current_user.id },
|
||||
USER_GUARD
|
||||
USER_GUARD,
|
||||
default_name: 'user_id'
|
||||
|
||||
# Returns the Canvas user_id of the launching user. Only available when launched by a logged in user.
|
||||
# @example
|
||||
|
@ -443,13 +495,15 @@ module Lti
|
|||
|
||||
# Returns the <a href="https://www.imsglobal.org/specs/ltimemv1p0/specification-3">IMS LTI membership service</a> roles for filtering via query parameters.
|
||||
# Only available when launched by a logged in user.
|
||||
# associated launch param name: 'roles'
|
||||
# @example
|
||||
# ```
|
||||
# http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator
|
||||
# ```
|
||||
register_expansion 'Membership.role', [],
|
||||
-> { lti_helper.all_roles('lis2') },
|
||||
USER_GUARD
|
||||
USER_GUARD,
|
||||
default_name: 'roles'
|
||||
|
||||
# Returns list of <a href="https://www.imsglobal.org/specs/ltiv1p0/implementation-guide#toc-16" target ="_blank">LIS role full URNs</a>.
|
||||
# Should always be available.
|
||||
|
@ -521,7 +575,8 @@ module Lti
|
|||
# ```
|
||||
register_expansion 'Person.sourcedId', [],
|
||||
-> { sis_pseudonym.sis_user_id },
|
||||
PSEUDONYM_GUARD
|
||||
PSEUDONYM_GUARD,
|
||||
default_name: 'lis_person_sourcedid'
|
||||
|
||||
# Returns the logout service url for the user.
|
||||
# This is the pseudonym the user is actually logged in as.
|
||||
|
|
|
@ -22,14 +22,15 @@
|
|||
module Lti
|
||||
class VariableExpansion
|
||||
|
||||
attr_reader :name, :permission_groups
|
||||
attr_reader :name, :permission_groups, :default_name
|
||||
|
||||
def initialize(name, permission_groups, expansion_proc, *guards)
|
||||
def initialize(name, permission_groups, expansion_proc, *guards, default_name: nil)
|
||||
@name = name
|
||||
@permission_groups = permission_groups
|
||||
@expansion_proc = expansion_proc
|
||||
@guards = guards
|
||||
@guards << -> { true } if @guards.empty?
|
||||
@default_name = default_name
|
||||
end
|
||||
|
||||
def expand(expander)
|
||||
|
|
|
@ -37,9 +37,10 @@ module Lti
|
|||
)
|
||||
end
|
||||
let(:enabled_capability) {
|
||||
%w(tool_consumer_instance_guid
|
||||
launch_presentation_document_target
|
||||
launch_presentation_locale)
|
||||
%w(ToolConsumerInstance.guid
|
||||
Message.documentTarget
|
||||
Message.locale
|
||||
Membership.role)
|
||||
}
|
||||
let(:tool_proxy) do
|
||||
ToolProxy.create(
|
||||
|
@ -267,10 +268,12 @@ module Lti
|
|||
end
|
||||
|
||||
it 'returns the roles' do
|
||||
course_with_student(account: account, active_all: true)
|
||||
user_session(@student)
|
||||
get 'basic_lti_launch_request', account_id: account.id, message_handler_id: message_handler.id,
|
||||
params: {tool_launch_context: 'my_custom_context'}
|
||||
params = assigns[:lti_launch].params.with_indifferent_access
|
||||
expect(params['roles']).to eq ["http://purl.imsglobal.org/vocab/lis/v2/person#None"]
|
||||
expect(params['roles']).to eq "http://purl.imsglobal.org/vocab/lis/v2/system/person#User"
|
||||
end
|
||||
|
||||
it 'adds module item substitutions' do
|
||||
|
|
|
@ -1,64 +1,109 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
||||
require_dependency "lti/capabilities_helper"
|
||||
|
||||
# Get a list of valid capabilities
|
||||
# Validate capabilities array
|
||||
# return capability params hash
|
||||
|
||||
module Lti
|
||||
describe CapabilitiesHelper do
|
||||
let(:test_lti_guid){ 'test-lti-guid-1234' }
|
||||
let(:root_account){ Account.new }
|
||||
let(:account){ Account.new(root_account: root_account) }
|
||||
let(:capabilities_helper){ CapabilitiesHelper.new(account) }
|
||||
let(:recommended_params){ %w(launch_presentation_document_target tool_consumer_instance_guid) }
|
||||
let(:optional_params){ %w(launch_presentation_locale) }
|
||||
let(:root_account) { Account.new(lti_guid: 'test-lti-guid') }
|
||||
let(:account) { Account.new(root_account: root_account) }
|
||||
let(:course) { Course.new(account: account) }
|
||||
let(:group_category) { course.group_categories.new(name: 'Category') }
|
||||
let(:group) { course.groups.new(name: 'Group', group_category: group_category) }
|
||||
let(:user) { User.new }
|
||||
let(:assignment) { Assignment.new }
|
||||
let(:collaboration) do
|
||||
ExternalToolCollaboration.new(
|
||||
title: "my collab",
|
||||
user: user,
|
||||
url: 'http://www.example.com'
|
||||
)
|
||||
end
|
||||
let(:substitution_helper) { stub_everything }
|
||||
let(:right_now) { DateTime.now }
|
||||
let(:tool) do
|
||||
m = mock('tool')
|
||||
m.stubs(:id).returns(1)
|
||||
m.stubs(:context).returns(root_account)
|
||||
shard_mock = mock('shard')
|
||||
shard_mock.stubs(:settings).returns({encription_key: 'abc'})
|
||||
m.stubs(:shard).returns(shard_mock)
|
||||
m.stubs(:opaque_identifier_for).returns("6cd2e0d65bd5aef3b5ee56a64bdcd595e447bc8f")
|
||||
m
|
||||
end
|
||||
let(:controller) do
|
||||
request_mock = mock('request')
|
||||
request_mock.stubs(:url).returns('https://localhost')
|
||||
request_mock.stubs(:host).returns('/my/url')
|
||||
request_mock.stubs(:scheme).returns('https')
|
||||
m = mock('controller')
|
||||
m.stubs(:css_url_for).with(:common).returns('/path/to/common.scss')
|
||||
m.stubs(:request).returns(request_mock)
|
||||
m.stubs(:logged_in_user).returns(user)
|
||||
m.stubs(:named_context_url).returns('url')
|
||||
m.stubs(:polymorphic_url).returns('url')
|
||||
view_context_mock = mock('view_context')
|
||||
view_context_mock.stubs(:stylesheet_path)
|
||||
.returns(URI.parse(request_mock.url).merge(m.css_url_for(:common)).to_s)
|
||||
m.stubs(:view_context).returns(view_context_mock)
|
||||
m
|
||||
end
|
||||
|
||||
describe "#recommended_params" do
|
||||
it "contains all supported recommended params" do
|
||||
expect(capabilities_helper.recommended_params.keys).to match_array(recommended_params)
|
||||
end
|
||||
let(:variable_expander) { Lti::VariableExpander.new(root_account, account, controller, current_user: user, tool: tool) }
|
||||
|
||||
it "gives correct value for launch_presentation_document_target"
|
||||
|
||||
it "gives correct value for tool_consumer_instance_guid" do
|
||||
root_account.update_attributes(lti_guid: test_lti_guid)
|
||||
instance_guid = capabilities_helper.recommended_params['tool_consumer_instance_guid']
|
||||
expect(instance_guid).to eq root_account.lti_guid
|
||||
end
|
||||
|
||||
it "gives nil for tool_consumer_instance_guid if context does not have root_account" do
|
||||
a = Account.new
|
||||
c_helper = CapabilitiesHelper.new(a)
|
||||
instance_guid = c_helper.recommended_params[:tool_consumer_instance_guid]
|
||||
expect(instance_guid).to be_nil
|
||||
let(:invalid_enabled_caps){ %w(InvalidCap.Foo AnotherInvalid.Bar) }
|
||||
let(:valid_enabled_caps){ %w(ToolConsumerInstance.guid Membership.role CourseSection.sourcedId) }
|
||||
let(:supported_capabilities){
|
||||
%w(ToolConsumerInstance.guid
|
||||
CourseSection.sourcedId
|
||||
Membership.role
|
||||
Person.email.primary
|
||||
Person.name.given
|
||||
Person.name.family
|
||||
Person.name.full
|
||||
Person.sourcedId
|
||||
User.id
|
||||
User.image
|
||||
Message.documentTarget
|
||||
Message.locale
|
||||
Membership.role)
|
||||
}
|
||||
describe '#supported_capabilities' do
|
||||
it 'returns all supported capabilities asociated with launch params' do
|
||||
expect(CapabilitiesHelper.supported_capabilities).to match_array(supported_capabilities)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#optional_params" do
|
||||
it "contains all supported optional params" do
|
||||
expect(capabilities_helper.optional_params.keys).to match_array(optional_params)
|
||||
describe '#filter_capabilities' do
|
||||
it 'removes invalid capabilities' do
|
||||
valid_capabilities = CapabilitiesHelper.filter_capabilities(valid_enabled_caps + invalid_enabled_caps)
|
||||
expect(valid_capabilities).not_to include(*invalid_enabled_caps)
|
||||
end
|
||||
|
||||
it "gives correct value for launch_presentation_locale with locale set" do
|
||||
allow_any_instance_of(I18n).to receive(:locale) { :en }
|
||||
launch_locale = capabilities_helper.optional_params['launch_presentation_locale']
|
||||
expect(launch_locale).to eq I18n.locale
|
||||
end
|
||||
|
||||
it "gives correct value for launch_presentation_locale with locale not set" do
|
||||
allow_any_instance_of(I18n).to receive(:locale) { nil }
|
||||
allow_any_instance_of(I18n).to receive(:default_locale) { :da }
|
||||
launch_locale = capabilities_helper.optional_params['launch_presentation_locale']
|
||||
expect(launch_locale).to eq I18n.default_locale
|
||||
it 'does not remove valid capabilities' do
|
||||
valid_capabilities = CapabilitiesHelper.filter_capabilities(valid_enabled_caps + invalid_enabled_caps)
|
||||
expect(valid_capabilities).to match_array valid_enabled_caps
|
||||
end
|
||||
end
|
||||
|
||||
describe "#parameter_capabilities" do
|
||||
it "returns keys of all optional and recommended params" do
|
||||
expect(capabilities_helper.parameter_capabilities).to match_array(recommended_params + optional_params)
|
||||
end
|
||||
end
|
||||
describe '#capability_params_hash' do
|
||||
let(:valid_keys) { %w(tool_consumer_instance_guid roles lis_course_section_sourcedid) }
|
||||
|
||||
describe "#paramter_capabilities_hash" do
|
||||
it "returns all recommended and optional params" do
|
||||
expect(capabilities_helper.parameter_capabilities_hash.keys).to match_array(recommended_params + optional_params)
|
||||
it 'does not include a name (key) for invalid capabilities' do
|
||||
params_hash = CapabilitiesHelper.capability_params_hash(invalid_enabled_caps + valid_enabled_caps, variable_expander)
|
||||
expect(params_hash.keys).not_to include(*invalid_enabled_caps)
|
||||
end
|
||||
|
||||
it 'does include a valid name (key) for valid capabilities' do
|
||||
params_hash = CapabilitiesHelper.capability_params_hash(invalid_enabled_caps + valid_enabled_caps, variable_expander)
|
||||
expect(params_hash.keys).to include(*valid_keys)
|
||||
end
|
||||
|
||||
it 'does include a value for each valid capability' do
|
||||
params_hash = CapabilitiesHelper.capability_params_hash(invalid_enabled_caps + valid_enabled_caps, variable_expander)
|
||||
expect(params_hash.values.length).to eq valid_keys.length
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|||
require_dependency "lti/variable_expander"
|
||||
module Lti
|
||||
describe VariableExpander do
|
||||
let(:root_account) { Account.new }
|
||||
let(:root_account) { Account.new(lti_guid: 'test-lti-guid') }
|
||||
let(:account) { Account.new(root_account: root_account) }
|
||||
let(:course) { Course.new(account: account) }
|
||||
let(:group_category) { course.group_categories.new(name: 'Category') }
|
||||
|
@ -116,6 +116,102 @@ module Lti
|
|||
expect(expanded[:some_name]).to eq "my variable is buried in here ${tests_expan} can you find it?"
|
||||
end
|
||||
|
||||
describe '#enabled_capability_params' do
|
||||
let(:enabled_capability) {
|
||||
%w(TestCapability.Foo
|
||||
ToolConsumerInstance.guid
|
||||
CourseSection.sourcedId
|
||||
Membership.role
|
||||
Person.email.primary
|
||||
Person.name.given
|
||||
Person.name.family
|
||||
Person.name.full
|
||||
Person.sourcedId
|
||||
User.id
|
||||
User.image
|
||||
Message.documentTarget
|
||||
Message.locale)
|
||||
}
|
||||
|
||||
it 'does not use expansions that do not have default names' do
|
||||
described_class.register_expansion('TestCapability.Foo', ['a'], -> {'test'})
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).not_to include 'TestCapability.Foo'
|
||||
end
|
||||
|
||||
it 'does use expansion that have default names' do
|
||||
described_class.register_expansion('TestCapability.Foo', ['a'], -> { 'test' }, default_name: 'test_capability_foo')
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.values).to include('test')
|
||||
end
|
||||
|
||||
it 'does use the default name as the key' do
|
||||
described_class.register_expansion('TestCapability.Foo', ['a'], -> { 'test' }, default_name: 'test_capability_foo')
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded['test_capability_foo']).to eq 'test'
|
||||
end
|
||||
|
||||
it 'includes ToolConsumerInstance.guid when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded['tool_consumer_instance_guid']).to eq 'test-lti-guid'
|
||||
end
|
||||
|
||||
it 'includes CourseSection.sourcedId when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'lis_course_section_sourcedid'
|
||||
end
|
||||
|
||||
it 'includes Membership.role when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'roles'
|
||||
end
|
||||
|
||||
it 'includes Person.email.primary when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'lis_person_contact_email_primary'
|
||||
end
|
||||
|
||||
it 'includes Person.name.given when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'lis_person_name_given'
|
||||
end
|
||||
|
||||
it 'includes Person.name.family when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'lis_person_name_family'
|
||||
end
|
||||
|
||||
it 'includes Person.name.full when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'lis_person_name_full'
|
||||
end
|
||||
|
||||
it 'includes Person.sourcedId when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'lis_person_sourcedid'
|
||||
end
|
||||
|
||||
it 'includes User.id when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'user_id'
|
||||
end
|
||||
|
||||
it 'includes User.image when in enabled capability' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'user_image'
|
||||
end
|
||||
|
||||
it 'includes Message.documentTarget' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'launch_presentation_document_target'
|
||||
end
|
||||
|
||||
it 'includes Message.locale' do
|
||||
expanded = subject.enabled_capability_params(enabled_capability)
|
||||
expect(expanded.keys).to include 'launch_presentation_locale'
|
||||
end
|
||||
end
|
||||
|
||||
context 'lti1' do
|
||||
it 'handles expansion' do
|
||||
described_class.register_expansion('test_expan', ['a'], -> { @context })
|
||||
|
@ -132,7 +228,19 @@ module Lti
|
|||
expect(expanded['some_name']).to eq "my variable is buried in here 42 can you find it?"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#variable expansions" do
|
||||
it 'has substitution for Message.documentTarget' do
|
||||
exp_hash = {test: '$Message.documentTarget'}
|
||||
subject.expand_variables!(exp_hash)
|
||||
expect(exp_hash[:test]).to eq IMS::LTI::Models::Messages::Message::LAUNCH_TARGET_IFRAME
|
||||
end
|
||||
|
||||
it 'has substitution for Message.locale' do
|
||||
exp_hash = {test: '$Message.locale'}
|
||||
subject.expand_variables!(exp_hash)
|
||||
expect(exp_hash[:test]).to eq I18n.locale
|
||||
end
|
||||
|
||||
it 'has substitution for $Canvas.api.domain' do
|
||||
exp_hash = {test: '$Canvas.api.domain'}
|
||||
|
|
|
@ -40,6 +40,11 @@ module Lti
|
|||
expect(var_exp.expand(TestExpander.new)).to eq '$test'
|
||||
end
|
||||
|
||||
it 'accepts and sets default_name' do
|
||||
var_exp = described_class.new('test', [], -> { 'test' }, -> { true }, default_name: 'test_name' )
|
||||
expect(var_exp.default_name).to eq 'test_name'
|
||||
end
|
||||
|
||||
it 'expands variables' do
|
||||
var_exp = described_class.new('test', [], -> { @one + @two + @three } )
|
||||
expect(var_exp.expand(TestExpander.new)).to eq 6
|
||||
|
|
|
@ -149,16 +149,20 @@ module Lti
|
|||
expect(subject.create(true).capability_offered).to include 'vnd.Canvas.OriginalityReport.url'
|
||||
end
|
||||
|
||||
it 'adds the launch_presentation_document_target paramter capability' do
|
||||
expect(subject.create(true).capability_offered).to include 'launch_presentation_document_target'
|
||||
it 'adds the Message.documentTarget capability' do
|
||||
expect(subject.create(true).capability_offered).to include 'Message.documentTarget'
|
||||
end
|
||||
|
||||
it 'adds the tool_consumer_instance_guid paramter capability' do
|
||||
expect(subject.create(true).capability_offered).to include 'tool_consumer_instance_guid'
|
||||
it 'adds the ToolConsumerInstance.guid capability' do
|
||||
expect(subject.create(true).capability_offered).to include 'ToolConsumerInstance.guid'
|
||||
end
|
||||
|
||||
it 'adds the launch_presentation_locale paramter capability' do
|
||||
expect(subject.create(true).capability_offered).to include 'launch_presentation_locale'
|
||||
it 'adds the Message.locale capability' do
|
||||
expect(subject.create(true).capability_offered).to include 'Message.locale'
|
||||
end
|
||||
|
||||
it 'adds the Membership.role capability' do
|
||||
expect(subject.create(true).capability_offered).to include 'Membership.role'
|
||||
end
|
||||
|
||||
it 'does not add the OriginalityReport capability if developer_key is false' do
|
||||
|
|
Loading…
Reference in New Issue