add tool setting service
fixes PLAT-608 PLAT-613 PLAT-615 PLAT-616 PLAT-620 test-plan *spec should pass Change-Id: Idf2a7d89973231a070a8d368bd60554e3501cdf6 Reviewed-on: https://gerrit.instructure.com/40227 Reviewed-by: Brad Humphrey <brad@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> Product-Review: Nathan Mills <nathanm@instructure.com> QA-Review: Nathan Mills <nathanm@instructure.com>
This commit is contained in:
parent
ea232fd3f1
commit
63945c4d35
|
@ -46,7 +46,7 @@ gem 'hoe', '3.8.1'
|
|||
gem 'i18n', '0.6.9'
|
||||
gem 'i18nema', RUBY_VERSION >= '2.2' ? '0.0.8' : '0.0.7'
|
||||
gem 'icalendar', '1.5.4'
|
||||
gem 'ims-lti', '2.0.0.beta.6'
|
||||
gem 'ims-lti', '2.0.0.beta.7'
|
||||
gem 'jammit', '0.6.6'
|
||||
gem 'cssmin', '1.0.3'
|
||||
gem 'jsmin', '1.0.1'
|
||||
|
|
|
@ -27,50 +27,49 @@ module Lti
|
|||
@lti_launch.params = message.post_params
|
||||
@lti_launch.link_text = I18n.t('lti2.register_tool', 'Register Tool')
|
||||
@lti_launch.launch_type = message.launch_presentation_document_target
|
||||
|
||||
|
||||
render template: 'lti/framed_launch'
|
||||
end
|
||||
|
||||
|
||||
def basic_lti_launch_request
|
||||
if message_handler = MessageHandler.where(id: params[:lti_message_handler_id]).first
|
||||
resource_handler = message_handler.resource
|
||||
if message_handler = MessageHandler.find(params[:message_handler_id])
|
||||
resource_handler = message_handler.resource_handler
|
||||
tool_proxy = resource_handler.tool_proxy
|
||||
#TODO create scoped method for query
|
||||
if ToolProxyBinding.where(tool_proxy_id: tool_proxy.id, context_id: @context.id, context_type: @context.class).count(:all) > 0
|
||||
if tool_proxy.workflow_state == 'active'
|
||||
message = IMS::LTI::Models::Messages::BasicLTILaunchRequest.new(
|
||||
launch_url: message_handler.launch_path,
|
||||
oauth_consumer_key: tool_proxy.guid,
|
||||
lti_version: IMS::LTI::Models::LTIModel::LTI_VERSION_2P0,
|
||||
resource_link_id: Lti::Asset.opaque_identifier_for(@context),
|
||||
resource_link_id: build_resource_link_id(tool_proxy),
|
||||
context_id: Lti::Asset.opaque_identifier_for(@context),
|
||||
tool_consumer_instance_guid: @context.root_account.lti_guid,
|
||||
launch_presentation_document_target: IMS::LTI::Models::Messages::Message::LAUNCH_TARGET_IFRAME
|
||||
)
|
||||
message.add_custom_params(custom_params(message_handler.parameters))
|
||||
message.add_custom_params(custom_params(message_handler.parameters, tool_proxy, message.resource_link_id))
|
||||
@lti_launch = Launch.new
|
||||
@lti_launch.resource_url = message.launch_url
|
||||
@lti_launch.params = message.signed_post_params(tool_proxy.shared_secret)
|
||||
@lti_launch.link_text = message_handler.resource.name
|
||||
@lti_launch.link_text = resource_handler.name
|
||||
@lti_launch.launch_type = message.launch_presentation_document_target
|
||||
|
||||
render template: 'lti/framed_launch' and return
|
||||
end
|
||||
end
|
||||
not_found and return
|
||||
not_found
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def custom_params(parameters)
|
||||
lookup_hash = common_variable_substitutions.inject({}) { |hash, (k,v)| hash[k.gsub(/\A\$/, '')] = v ; hash}
|
||||
def custom_params(parameters, tool_proxy, resource_link_id)
|
||||
params = IMS::LTI::Models::Parameter.from_json(parameters || [])
|
||||
IMS::LTI::Models::Parameter.process_params(params, lookup_hash)
|
||||
IMS::LTI::Models::Parameter.process_params(params, lti2_variable_substitutions(parameters, tool_proxy, resource_link_id))
|
||||
end
|
||||
|
||||
def tool_consumer_profile_url
|
||||
tp_id = SecureRandom.uuid
|
||||
tp_id = "339b6700-e4cb-47c5-a54f-3ee0064921a9" #Hard coded until we start persisting the tcp
|
||||
case context
|
||||
when Course
|
||||
course_tool_consumer_profile_url(context, tp_id)
|
||||
|
@ -92,5 +91,44 @@ module Lti
|
|||
end
|
||||
end
|
||||
|
||||
def find_binding(tool_proxy)
|
||||
if @context.is_a?(Course)
|
||||
binding = ToolProxyBinding.where(context_type: 'Course', context: @context.id, tool_proxy_id: tool_proxy.id)
|
||||
return binding if binding
|
||||
end
|
||||
account_ids = @context.account_chain.map{ |a| a.id }
|
||||
bindings = ToolProxyBinding.where(context_type: 'Account', context_id: account_ids, tool_proxy_id: tool_proxy.id)
|
||||
binding_lookup = bindings.each_with_object({}) {|binding, hash| hash[binding.context_id] = binding }
|
||||
sorted_bindings = account_ids.map { |account_id| binding_lookup[account_id] }
|
||||
sorted_bindings.first
|
||||
end
|
||||
|
||||
def build_resource_link_id(message_handler, postfix = nil)
|
||||
resource_link_id = "#{params[:tool_launch_context]}_#{message_handler.id}"
|
||||
resource_link_id += "_#{params[:postfix_id]}" if params[:postfix_id]
|
||||
Base64.urlsafe_encode64("#{resource_link_id}")
|
||||
end
|
||||
|
||||
def lti2_variable_substitutions(parameters, tool_proxy, resource_link_id)
|
||||
substitutions = common_variable_substitutions.inject({}) { |hash, (k,v)| hash[k.gsub(/\A\$/, '')] = v ; hash}
|
||||
substitutions.merge!(prep_tool_settings(parameters, tool_proxy, resource_link_id))
|
||||
substitutions
|
||||
end
|
||||
|
||||
def prep_tool_settings(parameters, tool_proxy, resource_link_id)
|
||||
if parameters && (parameters.map {|p| p['variable']}.compact & (%w( LtiLink.custom.url ToolProxyBinding.custom.url ToolProxy.custom.url ))).any?
|
||||
link = ToolSetting.first_or_create(tool_proxy: tool_proxy, context: @context, resource_link_id: resource_link_id)
|
||||
binding = ToolSetting.first_or_create(tool_proxy: tool_proxy, context: @context, resource_link_id: nil)
|
||||
proxy = ToolSetting.first_or_create(tool_proxy: tool_proxy, context: nil, resource_link_id: nil)
|
||||
{
|
||||
'LtiLink.custom.url' => show_lti_tool_settings_url(link.id),
|
||||
'ToolProxyBinding.custom.url' => show_lti_tool_settings_url(binding.id),
|
||||
'ToolProxy.custom.url' => show_lti_tool_settings_url(proxy.id)
|
||||
}
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -24,23 +24,12 @@ module Lti
|
|||
|
||||
def show
|
||||
uuid = "339b6700-e4cb-47c5-a54f-3ee0064921a9" #Hard coded until we start persisting the tcp
|
||||
profile = Lti::ToolConsumerProfileCreator.new(@account, tool_consumer_profile_url(uuid), tool_proxy_url).create
|
||||
profile = Lti::ToolConsumerProfileCreator.new(@account, tool_consumer_profile_url(uuid), request.domain, context.class.name.downcase).create
|
||||
render json: profile.to_json, :content_type => 'application/json'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tool_proxy_url
|
||||
case context
|
||||
when Course
|
||||
create_course_lti_tool_proxy_url(context)
|
||||
when Account
|
||||
create_account_lti_tool_proxy_url(context)
|
||||
else
|
||||
raise "Unsupported context"
|
||||
end
|
||||
end
|
||||
|
||||
def tool_consumer_profile_url(uuid)
|
||||
case context
|
||||
when Course
|
||||
|
|
|
@ -17,13 +17,15 @@
|
|||
|
||||
module Lti
|
||||
class ToolProxyController < ApplicationController
|
||||
include Lti::ApiServiceHelper
|
||||
|
||||
before_filter :require_context, :except => [:show]
|
||||
skip_before_filter :require_user, only: [:create, :show]
|
||||
skip_before_filter :load_user, only: [:create, :show]
|
||||
|
||||
def show
|
||||
tool_proxy = ToolProxy.where(guid: params['tool_proxy_guid']).first
|
||||
if tool_proxy && authorized_request?(tool_proxy.shared_secret)
|
||||
if tool_proxy && oauth_authenticated_request?(tool_proxy.shared_secret)
|
||||
render json: tool_proxy.raw_data
|
||||
else
|
||||
render json: {error: 'unauthorized'}, status: :unauthorized
|
||||
|
@ -32,7 +34,7 @@ module Lti
|
|||
|
||||
def create
|
||||
secret = RegistrationRequestService.retrieve_registration_password(oauth_consumer_key)
|
||||
if authorized_request?(secret)
|
||||
if oauth_authenticated_request?(secret)
|
||||
tool_proxy = ToolProxyService.new.process_tool_proxy_json(request.body.read, context, oauth_consumer_key)
|
||||
json = {
|
||||
"@context" => "http://purl.imsglobal.org/ctx/lti/v2/ToolProxyId",
|
||||
|
@ -47,14 +49,5 @@ module Lti
|
|||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authorized_request?(secret)
|
||||
OAuth::Signature.build(request, :consumer_secret => secret).verify()
|
||||
end
|
||||
|
||||
def oauth_consumer_key
|
||||
@oauth_consumer_key ||= OAuth::Helper.parse_header(request.authorization)['oauth_consumer_key']
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,93 @@
|
|||
# Copyright (C) 2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module Lti
|
||||
class ToolSettingController < ApplicationController
|
||||
include Lti::ApiServiceHelper
|
||||
|
||||
skip_before_filter :require_context
|
||||
skip_before_filter :require_user
|
||||
skip_before_filter :load_user
|
||||
|
||||
def show
|
||||
tool_setting = ToolSetting.includes(:tool_proxy).find(params[:tool_setting_id])
|
||||
if tool_setting && oauth_authenticated_request?(tool_setting.tool_proxy.shared_secret)
|
||||
render json: tool_setting_json(tool_setting, value_to_boolean(params[:bubble]))
|
||||
else
|
||||
render json: {error: 'unauthorized'}, status: :unauthorized
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
tool_setting = ToolSetting.includes(:tool_proxy).find(params[:tool_setting_id])
|
||||
if tool_setting && oauth_authenticated_request?(tool_setting.tool_proxy.shared_secret)
|
||||
tool_setting.update_attribute(:custom, custom_settings(tool_setting_type(tool_setting), JSON.parse(request.body.read)))
|
||||
else
|
||||
render json: {error: 'unauthorized'}, status: :unauthorized
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tool_setting_json(tool_setting, bubble)
|
||||
if bubble
|
||||
graph = []
|
||||
while tool_setting do
|
||||
graph << collect_tool_settings(tool_setting)
|
||||
case tool_setting_type(tool_setting)
|
||||
when 'LtiLink'
|
||||
tool_setting = ToolSetting.where(tool_proxy_id: tool_setting.tool_proxy_id, context_type: tool_setting.context_type, context_id: tool_setting.context_id, resource_link_id: nil).first
|
||||
when 'ToolProxyBinding'
|
||||
tool_setting = ToolSetting.where(tool_proxy_id: tool_setting.tool_proxy_id, context_type: nil, context_id: nil, resource_link_id: nil).first
|
||||
when 'ToolProxy'
|
||||
tool_setting = nil
|
||||
end
|
||||
end
|
||||
IMS::LTI::Models::ToolSettingContainer.new(graph: graph)
|
||||
else
|
||||
tool_setting.custom
|
||||
end
|
||||
end
|
||||
|
||||
def collect_tool_settings(tool_setting)
|
||||
type = tool_setting_type(tool_setting)
|
||||
url = show_lti_tool_settings_url(tool_setting.id)
|
||||
custom = tool_setting.custom || {}
|
||||
IMS::LTI::Models::ToolSetting.new(custom: custom, type: type, id: url)
|
||||
end
|
||||
|
||||
def custom_settings(type, json)
|
||||
if request.content_type == 'application/vnd.ims.lti.v2.toolsettings+json'
|
||||
setting = json['@graph'].find { |setting| setting['type'] == type }
|
||||
setting['custom']
|
||||
else
|
||||
json
|
||||
end
|
||||
end
|
||||
|
||||
def tool_setting_type(tool_setting)
|
||||
if tool_setting.resource_link_id.present?
|
||||
'LtiLink'
|
||||
elsif tool_setting.context.present?
|
||||
'ToolProxyBinding'
|
||||
else
|
||||
'ToolProxy'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -18,15 +18,15 @@
|
|||
|
||||
module Lti
|
||||
class MessageHandler< ActiveRecord::Base
|
||||
attr_accessible :message_type, :launch_path, :capabilities, :parameters, :resource_handler, :links
|
||||
|
||||
attr_accessible :message_type, :launch_path, :capabilities, :parameters, :resource
|
||||
|
||||
belongs_to :resource, class_name: "Lti::ResourceHandler", :foreign_key => :resource_handler_id
|
||||
belongs_to :resource_handler, class_name: "Lti::ResourceHandler", :foreign_key => :resource_handler_id
|
||||
has_many :links, :class_name => 'Lti::LtiLink'
|
||||
|
||||
serialize :capabilities
|
||||
serialize :parameters
|
||||
|
||||
validates_presence_of :message_type, :resource, :launch_path
|
||||
validates_presence_of :message_type, :resource_handler, :launch_path
|
||||
|
||||
end
|
||||
end
|
|
@ -24,7 +24,6 @@ module Lti
|
|||
belongs_to :tool_proxy, class_name: 'Lti::ToolProxy'
|
||||
has_many :message_handlers, class_name: 'Lti::MessageHandler', :foreign_key => :resource_handler_id
|
||||
has_many :placements, class_name: 'Lti::ResourcePlacement'
|
||||
has_many :tool_links, :class_name => 'Lti::ToolLink'
|
||||
|
||||
serialize :icon_info
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
module Lti
|
||||
class ToolConsumerProfileCreator
|
||||
|
||||
def initialize(account, tcp_url, tp_registration_url)
|
||||
@root_account = account.root_account
|
||||
def initialize(account, tcp_url, domain, context_type)
|
||||
@tcp_url = tcp_url
|
||||
@tp_registration_url = tp_registration_url
|
||||
@context_type = context_type
|
||||
@root_account = account.root_account
|
||||
@domain = domain
|
||||
end
|
||||
|
||||
def create
|
||||
|
@ -12,7 +13,7 @@ module Lti
|
|||
profile.id = @tcp_url
|
||||
profile.lti_version = IMS::LTI::Models::ToolConsumerProfile::LTI_VERSION_2P0
|
||||
profile.product_instance = create_product_instance
|
||||
profile.service_offered = [create_tp_registration_service]
|
||||
profile.service_offered = [ create_tp_registration_service, create_tp_item_service, create_tp_settings_service, create_binding_settings_service, create_link_settings_service ]
|
||||
profile.capability_offered = capabilities
|
||||
|
||||
profile
|
||||
|
@ -53,16 +54,55 @@ module Lti
|
|||
def create_tp_registration_service
|
||||
reg_srv = IMS::LTI::Models::RestService.new
|
||||
reg_srv.id = "#{@tcp_url}#ToolProxy.collection"
|
||||
reg_srv.endpoint = @tp_registration_url
|
||||
reg_srv.endpoint = "https://#{@domain}/api/lti/#{@context_type}s/{#{@context_type}_id}/tool_proxy"
|
||||
reg_srv.type = 'RestService'
|
||||
reg_srv.format = ['application/vnd.ims.lti.v2.toolproxy+json']
|
||||
reg_srv.action = 'POST'
|
||||
reg_srv
|
||||
end
|
||||
|
||||
def capabilities
|
||||
def create_tp_item_service
|
||||
reg_srv = IMS::LTI::Models::RestService.new
|
||||
reg_srv.id = "#{@tcp_url}#ToolProxy.item"
|
||||
reg_srv.endpoint = "https://#{@domain}/api/lti/tool_settings/tool_proxy/{tool_proxy_id}"
|
||||
reg_srv.type = 'RestService'
|
||||
reg_srv.format = ["application/vnd.ims.lti.v2.toolproxy+json"]
|
||||
reg_srv.action = ['GET']
|
||||
reg_srv
|
||||
end
|
||||
|
||||
%w( basic-lti-launch-request Canvas.api.domain)
|
||||
def create_tp_settings_service
|
||||
reg_srv = IMS::LTI::Models::RestService.new
|
||||
reg_srv.id = "#{@tcp_url}#ToolProxySettings"
|
||||
reg_srv.endpoint = "https://#{@domain}/api/lti/tool_settings/tool_proxy/{tool_proxy_id}"
|
||||
reg_srv.type = 'RestService'
|
||||
reg_srv.format = ['application/vnd.ims.lti.v2.toolsettings+json', 'application/vnd.ims.lti.v2.toolsettings.simple+json']
|
||||
reg_srv.action = ['GET', 'PUT']
|
||||
reg_srv
|
||||
end
|
||||
|
||||
def create_binding_settings_service
|
||||
reg_srv = IMS::LTI::Models::RestService.new
|
||||
reg_srv.id = "#{@tcp_url}#ToolProxyBindingSettings"
|
||||
reg_srv.endpoint = "https://#{@domain}/api/lti/tool_settings/bindings/{binding_id}"
|
||||
reg_srv.type = 'RestService'
|
||||
reg_srv.format = ['application/vnd.ims.lti.v2.toolsettings+json', 'application/vnd.ims.lti.v2.toolsettings.simple+json']
|
||||
reg_srv.action = ['GET', 'PUT']
|
||||
reg_srv
|
||||
end
|
||||
|
||||
def create_link_settings_service
|
||||
reg_srv = IMS::LTI::Models::RestService.new
|
||||
reg_srv.id = "#{@tcp_url}#LtiLinkSettings"
|
||||
reg_srv.endpoint = "https://#{@domain}/api/lti/tool_settings/links/{tool_proxy_id}"
|
||||
reg_srv.type = 'RestService'
|
||||
reg_srv.format = ['application/vnd.ims.lti.v2.toolsettings+json', 'application/vnd.ims.lti.v2.toolsettings.simple+json']
|
||||
reg_srv.action = ['GET', 'PUT']
|
||||
reg_srv
|
||||
end
|
||||
|
||||
def capabilities
|
||||
%w( basic-lti-launch-request Canvas.api.domain LtiLink.custom.url ToolProxyBinding.custom.url ToolProxy.custom.url)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -27,13 +27,12 @@ module Lti
|
|||
belongs_to :context, :polymorphic => true
|
||||
|
||||
belongs_to :product_family, class_name: 'Lti::ProductFamily'
|
||||
has_one :tool_setting, :class_name => 'Lti::ToolSetting', as: :settable
|
||||
|
||||
serialize :raw_data
|
||||
|
||||
validates_presence_of :shared_secret, :guid, :product_version, :lti_version, :product_family_id, :workflow_state, :raw_data, :context
|
||||
validates_uniqueness_of :guid
|
||||
validates_inclusion_of :context_type, :allow_nil => true, :in => ['Course', 'Account']
|
||||
validates_inclusion_of :workflow_state, in: ['active', 'deleted', 'disabled']
|
||||
|
||||
end
|
||||
end
|
|
@ -18,16 +18,15 @@
|
|||
module Lti
|
||||
class ToolProxyBinding < ActiveRecord::Base
|
||||
|
||||
attr_accessible :context, :tool_proxy
|
||||
attr_accessible :context, :tool_proxy, :enabled
|
||||
|
||||
belongs_to :tool_proxy, class_name: 'Lti::ToolProxy'
|
||||
validates_inclusion_of :context_type, :allow_nil => true, :in => ['Course', 'Account']
|
||||
|
||||
belongs_to :context, :polymorphic => true
|
||||
has_one :tool_setting, :class_name => 'Lti::ToolSetting', as: :settable
|
||||
has_many :links, :class_name => 'Lti::LtiLink', foreign_key: 'tool_proxy_binding_id'
|
||||
|
||||
validates_presence_of :tool_proxy, :context
|
||||
|
||||
after_save :touch_context
|
||||
validates_presence_of :tool_proxy, :context, :enabled
|
||||
validates_inclusion_of :context_type, :allow_nil => true, :in => ['Course', 'Account']
|
||||
|
||||
end
|
||||
end
|
|
@ -73,7 +73,7 @@ module Lti
|
|||
message_handler.launch_path = "#{base_path}#{mh.path}"
|
||||
message_handler.capabilities = create_json(mh.enabled_capability)
|
||||
message_handler.parameters = create_json(mh.parameter.as_json)
|
||||
message_handler.resource = resource
|
||||
message_handler.resource_handler = resource
|
||||
message_handler.save!
|
||||
message_handler
|
||||
end
|
||||
|
|
|
@ -17,8 +17,22 @@
|
|||
|
||||
module Lti
|
||||
class ToolSetting < ActiveRecord::Base
|
||||
belongs_to :settable, polymorphic: true
|
||||
attr_accessible :tool_proxy, :context, :resource_link_id, :custom
|
||||
|
||||
belongs_to :tool_proxy
|
||||
belongs_to :context, polymorphic: true
|
||||
|
||||
validates_presence_of :tool_proxy
|
||||
validates_presence_of :context, if: :has_resource_link_id?
|
||||
validates_inclusion_of :context_type, :allow_nil => true, :in => ['Course', 'Account']
|
||||
|
||||
serialize :custom
|
||||
|
||||
|
||||
private
|
||||
def has_resource_link_id?
|
||||
resource_link_id.present?
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -285,7 +285,7 @@ CanvasRails::Application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
get 'lti/basic_lti_launch_request/:lti_message_handler_id', controller: 'lti/message', action: 'basic_lti_launch_request', as: :basic_lti_launch_request
|
||||
get 'lti/basic_lti_launch_request/:message_handler_id', controller: 'lti/message', action: 'basic_lti_launch_request', as: :basic_lti_launch_request
|
||||
get 'lti/tool_proxy_registration', controller: 'lti/message', action: 'registration', :as => :tool_proxy_registration
|
||||
|
||||
|
||||
|
@ -548,7 +548,7 @@ CanvasRails::Application.routes.draw do
|
|||
end
|
||||
|
||||
|
||||
get 'lti/basic_lti_launch_request/:lti_message_handler_id', controller: 'lti/message', action: 'basic_lti_launch_request', as: :basic_lti_launch_request
|
||||
get 'lti/basic_lti_launch_request/:message_handler_id', controller: 'lti/message', action: 'basic_lti_launch_request', as: :basic_lti_launch_request
|
||||
get 'lti/tool_proxy_registration', controller: 'lti/message', action: 'registration', :as => :tool_proxy_registration
|
||||
|
||||
|
||||
|
@ -1595,7 +1595,13 @@ CanvasRails::Application.routes.draw do
|
|||
get "#{prefix}/tool_consumer_profile/:tool_consumer_profile_id", controller: 'lti/tool_consumer_profile', action: 'show', :as => "#{context}_tool_consumer_profile"
|
||||
post "#{prefix}/tool_proxy", :controller => 'lti/tool_proxy', :action => :create, :path_name => "create_#{context}_lti_tool_proxy"
|
||||
end
|
||||
#Tool Setting Services
|
||||
get "tool_settings/:tool_setting_id", controller: 'lti/tool_setting', action: :show, as: 'show_lti_tool_settings'
|
||||
put "tool_settings/:tool_setting_id", controller: 'lti/tool_setting', action: :update, as: 'update_lti_tool_settings'
|
||||
|
||||
#Tool Proxy Services
|
||||
get "tool_proxy/:tool_proxy_guid", :controller => 'lti/tool_proxy', :action => :show, :path_name => "show_lti_tool_proxy"
|
||||
|
||||
end
|
||||
|
||||
match '/assets/:package.:extension' => 'jammit#package', :as => :jammit if defined?(Jammit)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
class AddLtiLinkBindingAssociation < ActiveRecord::Migration
|
||||
tag :predeploy
|
||||
|
||||
def self.up
|
||||
drop_table :lti_tool_links
|
||||
drop_table :lti_tool_settings
|
||||
|
||||
add_column :lti_tool_proxy_bindings, :enabled, :boolean, null: false, default: true
|
||||
|
||||
create_table :lti_tool_settings do |t|
|
||||
t.integer :tool_proxy_id, limit:8, null: false
|
||||
t.integer :context_id, limit: 8
|
||||
t.string :context_type
|
||||
t.text :resource_link_id
|
||||
t.text :custom
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :lti_tool_settings, [:resource_link_id, :context_type, :context_id, :tool_proxy_id],name: 'index_lti_tool_settings_on_link_context_and_tool_proxy', unique: true
|
||||
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :lti_tool_proxy_bindings, :enabled
|
||||
drop_table :lti_tool_settings
|
||||
create_table :lti_tool_settings do |t|
|
||||
t.integer :settable_id, limit: 8, null: false
|
||||
t.string :settable_type, null: false
|
||||
t.text :custom
|
||||
end
|
||||
|
||||
create_table :lti_tool_links do |t|
|
||||
t.integer :resource_handler_id, limit: 8, null: false
|
||||
t.string :uuid, null: false
|
||||
end
|
||||
|
||||
|
||||
add_index :lti_tool_settings, [:settable_id, :settable_type], unique: true
|
||||
add_index :lti_tool_links, :uuid, unique: true
|
||||
end
|
||||
|
||||
end
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright (C) 2014 Instructure, Inc.
|
||||
#
|
||||
# Copyright (C) 2011 - 2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
|
@ -15,14 +16,19 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# Filters added to this controller apply to all controllers in the application.
|
||||
# Likewise, all the methods added will be available for all controllers.
|
||||
|
||||
module Lti
|
||||
class ToolLink < ActiveRecord::Base
|
||||
belongs_to :resource_handler, class_name: 'Lti::ResourceHandler'
|
||||
has_one :tool_setting, :class_name => 'Lti::ToolSetting', as: :settable
|
||||
module ApiServiceHelper
|
||||
|
||||
attr_accessible :uuid
|
||||
def oauth_authenticated_request?(secret)
|
||||
!!OAuth::Signature.build(request, :consumer_secret => secret).verify()
|
||||
end
|
||||
|
||||
after_initialize { self.uuid = SecureRandom::uuid}
|
||||
def oauth_consumer_key
|
||||
@oauth_consumer_key ||= OAuth::Helper.parse_header(request.authorization)['oauth_consumer_key']
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -45,14 +45,14 @@ module Lti
|
|||
|
||||
if @context.is_a? Course
|
||||
substitutions.merge!(
|
||||
{
|
||||
'$Canvas.course.id' => @context.id,
|
||||
'$Canvas.course.sisSourceId' => @context.sis_source_id,
|
||||
'$Canvas.enrollment.enrollmentState' => -> { lti_helper.enrollment_state },
|
||||
'$Canvas.membership.roles' => -> { lti_helper.current_canvas_roles },
|
||||
#This is a list of IMS LIS roles should have a different key
|
||||
'$Canvas.membership.concludedRoles' => -> { lti_helper.concluded_lis_roles },
|
||||
}
|
||||
{
|
||||
'$Canvas.course.id' => @context.id,
|
||||
'$Canvas.course.sisSourceId' => @context.sis_source_id,
|
||||
'$Canvas.enrollment.enrollmentState' => -> { lti_helper.enrollment_state },
|
||||
'$Canvas.membership.roles' => -> { lti_helper.current_canvas_roles },
|
||||
#This is a list of IMS LIS roles should have a different key
|
||||
'$Canvas.membership.concludedRoles' => -> { lti_helper.concluded_lis_roles },
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
#
|
||||
# Copyright (C) 2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../api_spec_helper')
|
||||
|
||||
module Lti
|
||||
describe ToolSettingController, type: :request do
|
||||
|
||||
let(:account) { Account.new }
|
||||
let (:product_family) { ProductFamily.create(vendor_code: '123', product_code: 'abc', vendor_name: 'acme', root_account: account) }
|
||||
let(:tool_proxy) do
|
||||
ToolProxy.create!(
|
||||
context: account,
|
||||
guid: SecureRandom.uuid,
|
||||
shared_secret: 'abc',
|
||||
product_family: product_family,
|
||||
root_account: account,
|
||||
product_version: '1',
|
||||
workflow_state: 'disabled',
|
||||
raw_data: {'proxy' => 'value'},
|
||||
lti_version: '1'
|
||||
)
|
||||
end
|
||||
let(:resource_handler) { ResourceHandler.create!(resource_type_code: 'code', name: 'name', tool_proxy: tool_proxy) }
|
||||
let(:message_handler) { MessageHandler.create(message_type: 'basic-lti-launch-request', launch_path: 'https://samplelaunch/blti', resource_handler: resource_handler) }
|
||||
|
||||
before do
|
||||
OAuth::Signature.stubs(:build).returns(mock(verify: true))
|
||||
@link_setting = ToolSetting.create(tool_proxy: tool_proxy, context: account, resource_link_id: 'abc', custom: {link: :setting})
|
||||
@binding_setting = ToolSetting.create(tool_proxy: tool_proxy, context: account, custom: {binding: :setting})
|
||||
@proxy_setting = ToolSetting.create(tool_proxy: tool_proxy, custom: {proxy: :setting})
|
||||
end
|
||||
|
||||
describe '#lti_link_show', type: :request do
|
||||
|
||||
it 'returns the lti link simple json' do
|
||||
get "/api/lti/tool_settings/#{@link_setting.id}.json", tool_setting_id: @link_setting, bubble: false
|
||||
JSON.parse(body).should == {"link" => "setting"}
|
||||
end
|
||||
|
||||
it 'returns the lti link tool settings json with bubble' do
|
||||
get "/api/lti/tool_settings/#{@link_setting.id}.json", tool_setting_id: @link_setting, bubble: true
|
||||
json = JSON.parse(body)
|
||||
setting = json['@graph'].find { |setting| setting['@type'] == "LtiLink" }
|
||||
setting['custom'].should == {"link" => "setting"}
|
||||
end
|
||||
|
||||
it 'creates a new lti link tool setting' do
|
||||
tool_setting = ToolSetting.create(tool_proxy: tool_proxy, context: account, resource_link_id: 'resource_link')
|
||||
params = {'link' => 'settings'}
|
||||
put "/api/lti/tool_settings/#{tool_setting.id}.json", params.to_json, {'CONTENT_TYPE' => 'application/vnd.ims.lti.v2.toolsettings.simple+json', 'ACCEPT' => 'application/vnd.ims.lti.v2.toolsettings.simple+json'}
|
||||
tool_setting.reload.custom.should == {'link' => 'settings'}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe '#tool_proxy_binding_show' do
|
||||
|
||||
it 'returns the lti link simple json' do
|
||||
get "/api/lti/tool_settings/#{@binding_setting.id}.json", tool_setting_id: @binding_setting.id, bubble: false
|
||||
JSON.parse(body).should == {"binding" => "setting"}
|
||||
end
|
||||
|
||||
it 'returns the lti link tool settings json with bubble' do
|
||||
get "/api/lti/tool_settings/#{@binding_setting.id}.json", tool_setting_id: @binding_setting.id, bubble: true
|
||||
json = JSON.parse(body)
|
||||
setting = json['@graph'].find { |setting| setting['@type'] == "ToolProxyBinding" }
|
||||
setting['custom'].should == {"binding" => "setting"}
|
||||
end
|
||||
|
||||
it 'creates a new binding tool setting' do
|
||||
tool_setting = ToolSetting.create(tool_proxy: tool_proxy, context: account)
|
||||
params = {'binding' => 'settings'}
|
||||
put "/api/lti/tool_settings/#{tool_setting.id}.json", params.to_json, {'CONTENT_TYPE' => 'application/vnd.ims.lti.v2.toolsettings.simple+json', 'ACCEPT' => 'application/vnd.ims.lti.v2.toolsettings.simple+json'}
|
||||
tool_setting.reload.custom.should == {'binding' => 'settings'}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe '#tool_proxy_show' do
|
||||
|
||||
it 'returns the lti link simple json' do
|
||||
get "/api/lti/tool_settings/#{@proxy_setting.id}.json", link_id: @proxy_setting.id, bubble: false
|
||||
JSON.parse(body).should == {"proxy" => "setting"}
|
||||
end
|
||||
|
||||
it 'returns the lti link tool settings json with bubble' do
|
||||
get "/api/lti/tool_settings/#{@proxy_setting.id}.json", link_id: @proxy_setting.id, bubble: true
|
||||
json = JSON.parse(body)
|
||||
setting = json['@graph'].find { |setting| setting['@type'] == "ToolProxy" }
|
||||
setting['custom'].should == {"proxy" => "setting"}
|
||||
end
|
||||
|
||||
it 'creates a new tool_proxy tool setting' do
|
||||
tool_setting = ToolSetting.create(tool_proxy: tool_proxy)
|
||||
params = {'tool_proxy' => 'settings'}
|
||||
put "/api/lti/tool_settings/#{tool_setting.id}.json", params.to_json, {'CONTENT_TYPE' => 'application/vnd.ims.lti.v2.toolsettings.simple+json', 'ACCEPT' => 'application/vnd.ims.lti.v2.toolsettings.simple+json'}
|
||||
tool_setting.reload.custom.should == {'tool_proxy' => 'settings'}
|
||||
end
|
||||
|
||||
context 'bubble' do
|
||||
|
||||
it 'bubbles up all levels' do
|
||||
get "/api/lti/tool_settings/#{@link_setting.id}.json", tool_setting_id: @link_setting.id, bubble: true
|
||||
json = JSON.parse(body)
|
||||
link_setting = json['@graph'].find { |setting| setting['@type'] == "LtiLink" }
|
||||
link_setting['custom'].should == {"link" => "setting"}
|
||||
binding_setting = json['@graph'].find { |setting| setting['@type'] == "ToolProxyBinding" }
|
||||
binding_setting['custom'].should == {"binding" => "setting"}
|
||||
proxy_setting = json['@graph'].find { |setting| setting['@type'] == "ToolProxy" }
|
||||
proxy_setting['custom'].should == {"proxy" => "setting"}
|
||||
end
|
||||
|
||||
it 'bubbles up from binding' do
|
||||
get "/api/lti/tool_settings/#{@binding_setting.id}.json", tool_setting_id: @binding_setting.id, bubble: true
|
||||
json = JSON.parse(body)
|
||||
link_setting = json['@graph'].find { |setting| setting['@type'] == "LtiLink" }
|
||||
link_setting.should be_nil
|
||||
binding_setting = json['@graph'].find { |setting| setting['@type'] == "ToolProxyBinding" }
|
||||
binding_setting['custom'].should == {"binding" => "setting"}
|
||||
proxy_setting = json['@graph'].find { |setting| setting['@type'] == "ToolProxy" }
|
||||
proxy_setting['custom'].should == {"proxy" => "setting"}
|
||||
end
|
||||
|
||||
it 'bubbles up from tool proxy' do
|
||||
get "/api/lti/tool_settings/#{@proxy_setting.id}.json", tool_setting_id: @proxy_setting.id, bubble: true
|
||||
json = JSON.parse(body)
|
||||
link_setting = json['@graph'].find { |setting| setting['@type'] == "LtiLink" }
|
||||
link_setting.should be_nil
|
||||
binding_setting = json['@graph'].find { |setting| setting['@type'] == "ToolProxyBinding" }
|
||||
binding_setting.should be_nil
|
||||
proxy_setting = json['@graph'].find { |setting| setting['@type'] == "ToolProxy" }
|
||||
proxy_setting['custom'].should == {"proxy" => "setting"}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -64,7 +64,7 @@ module Lti
|
|||
let (:account) { Account.create }
|
||||
let (:product_family) { ProductFamily.create(vendor_code: '123', product_code: 'abc', vendor_name: 'acme', root_account: account) }
|
||||
let (:resource_handler) { ResourceHandler.create(resource_type_code: 'code', name: 'resource name', tool_proxy: tool_proxy) }
|
||||
let (:message_handler) { MessageHandler.create(message_type: 'message_type', launch_path:'https://samplelaunch/blti', resource: resource_handler)}
|
||||
let(:message_handler) { MessageHandler.create(message_type: 'basic-lti-launch-request', launch_path: 'https://samplelaunch/blti', resource_handler: resource_handler) }
|
||||
let (:tool_proxy) { ToolProxy.create(
|
||||
shared_secret: 'shared_secret',
|
||||
guid: 'guid',
|
||||
|
@ -77,12 +77,13 @@ module Lti
|
|||
) }
|
||||
|
||||
context 'account' do
|
||||
before :each do
|
||||
@tool_proxy_binding = ToolProxyBinding.create(context: account, tool_proxy: tool_proxy)
|
||||
|
||||
before do
|
||||
ToolProxyBinding.create(context: account, tool_proxy: tool_proxy)
|
||||
end
|
||||
|
||||
it 'returns the signed params' do
|
||||
get 'basic_lti_launch_request', account_id: account.id, lti_message_handler_id: message_handler.id
|
||||
get 'basic_lti_launch_request', account_id: account.id, message_handler_id: message_handler.id, params: {tool_launch_context: 'my_custom_context'}
|
||||
response.code.should == "200"
|
||||
|
||||
lti_launch = assigns[:lti_launch]
|
||||
|
@ -97,10 +98,30 @@ module Lti
|
|||
end
|
||||
|
||||
it 'returns a 404 when when no handler is found' do
|
||||
get 'basic_lti_launch_request', account_id: account.id, lti_message_handler_id: 0
|
||||
get 'basic_lti_launch_request', account_id: account.id, message_handler_id: 0
|
||||
response.code.should == "404"
|
||||
end
|
||||
|
||||
it 'does custom variable expansion for tool settings' do
|
||||
parameters = %w( LtiLink.custom.url ToolProxyBinding.custom.url ToolProxy.custom.url ).map do |key|
|
||||
IMS::LTI::Models::Parameter.new(name: key.underscore, variable: key )
|
||||
end
|
||||
message_handler.parameters = parameters.as_json
|
||||
message_handler.save
|
||||
|
||||
get 'basic_lti_launch_request', account_id: account.id, message_handler_id: message_handler.id, params: {tool_launch_context: 'my_custom_context'}
|
||||
response.code.should == "200"
|
||||
|
||||
params = assigns[:lti_launch].params.with_indifferent_access
|
||||
params['custom_lti_link.custom.url'].should include('api/lti/tool_settings/')
|
||||
params['custom_tool_proxy_binding.custom.url'].should include('api/lti/tool_settings/')
|
||||
params['custom_tool_proxy.custom.url'].should include('api/lti/tool_settings/')
|
||||
end
|
||||
|
||||
it 'uses the correct binding' do
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,7 +25,7 @@ module Lti
|
|||
before(:each) do
|
||||
subject.message_type = 'message_type'
|
||||
subject.launch_path = 'launch_path'
|
||||
subject.resource = ResourceHandler.new
|
||||
subject.resource_handler = ResourceHandler.new
|
||||
end
|
||||
|
||||
it 'requires the message type' do
|
||||
|
@ -41,9 +41,9 @@ module Lti
|
|||
end
|
||||
|
||||
it 'requires a resource_handler' do
|
||||
subject.resource = nil
|
||||
subject.resource_handler = nil
|
||||
subject.save
|
||||
subject.errors.first.should == [:resource, "can't be blank"]
|
||||
subject.errors.first.should == [:resource_handler, "can't be blank"]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -6,9 +6,7 @@ module Lti
|
|||
let(:root_account) { mock('root account', lti_guid: 'my_guid') }
|
||||
let(:account) { mock('account', root_account: root_account) }
|
||||
let(:tcp_url) {'http://example.instructure.com/tcp/uuid'}
|
||||
# let(:root_account) {mock('root account').stubs(:lti_guid).returns('my_guid')}
|
||||
# let(:account) {mock('account').stubs(:root_account).returns(root_account)}
|
||||
subject { ToolConsumerProfileCreator.new(account, tcp_url, 'http://tool-consumer.com/tp/reg') }
|
||||
subject { ToolConsumerProfileCreator.new(account, tcp_url, 'example.instructure.com', 'account') }
|
||||
|
||||
describe '#create' do
|
||||
|
||||
|
@ -51,7 +49,7 @@ module Lti
|
|||
profile = subject.create
|
||||
reg_srv = profile.service_offered.find {|srv| srv.id.include? 'ToolProxy.collection'}
|
||||
reg_srv.id.should == "#{tcp_url}#ToolProxy.collection"
|
||||
reg_srv.endpoint.should == 'http://tool-consumer.com/tp/reg'
|
||||
reg_srv.endpoint.should == 'https://example.instructure.com/api/lti/accounts/{account_id}/tool_proxy'
|
||||
reg_srv.type.should == 'RestService'
|
||||
reg_srv.format.should == ["application/vnd.ims.lti.v2.toolproxy+json"]
|
||||
reg_srv.action.should include 'POST'
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb')
|
||||
|
||||
module Lti
|
||||
describe ToolLink do
|
||||
|
||||
let (:account) { Account.create }
|
||||
let (:product_family) { ProductFamily.create(vendor_code: '123', product_code: 'abc', vendor_name: 'acme', root_account: account) }
|
||||
let (:resource_handler) { ResourceHandler.create(resource_type_code: 'code', name: 'resource name', tool_proxy: tool_proxy) }
|
||||
let (:message_handler) { MessageHandler.create(message_type: 'message_type', launch_path:'https://samplelaunch/blti', resource: resource_handler)}
|
||||
let (:tool_proxy) { ToolProxy.create(
|
||||
shared_secret: 'shared_secret',
|
||||
guid: 'guid',
|
||||
product_version: '1.0beta',
|
||||
lti_version: 'LTI-2p0',
|
||||
product_family: product_family,
|
||||
context: account,
|
||||
workflow_state: 'active',
|
||||
raw_data: 'some raw data'
|
||||
) }
|
||||
subject{resource_handler.tool_links.create}
|
||||
|
||||
|
||||
describe '#create' do
|
||||
|
||||
it 'sets the uuid by default' do
|
||||
|
||||
link = resource_handler.tool_links.create
|
||||
link.uuid.should_not == nil
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
context 'tool_settings' do
|
||||
it 'can have a tool setting' do
|
||||
subject.create_tool_setting(custom: {name: :foo})
|
||||
subject.tool_setting[:custom].should == {name: :foo}
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
end
|
|
@ -43,31 +43,6 @@ describe ToolProxyBinding do
|
|||
subject.errors.first.should == [:tool_proxy, "can't be blank"]
|
||||
end
|
||||
|
||||
context 'tool_settings' do
|
||||
let (:account) { Account.create }
|
||||
let (:product_family) { ProductFamily.create(vendor_code: '123', product_code: 'abc', vendor_name: 'acme', root_account: account) }
|
||||
let (:resource_handler) { ResourceHandler.create(resource_type_code: 'code', name: 'resource name', tool_proxy: tool_proxy) }
|
||||
let (:message_handler) { MessageHandler.create(message_type: 'message_type', launch_path:'https://samplelaunch/blti', resource: resource_handler)}
|
||||
let (:tool_proxy) { ToolProxy.create(
|
||||
shared_secret: 'shared_secret',
|
||||
guid: 'guid',
|
||||
product_version: '1.0beta',
|
||||
lti_version: 'LTI-2p0',
|
||||
product_family: product_family,
|
||||
context: account,
|
||||
workflow_state: 'active',
|
||||
raw_data: 'some raw data'
|
||||
) }
|
||||
subject{ tool_proxy.bindings.create(context:account)}
|
||||
|
||||
it 'can have a tool setting' do
|
||||
subject.create_tool_setting(custom: {name: :foo})
|
||||
subject.tool_setting[:custom].should == {name: :foo}
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -102,24 +102,6 @@ module Lti
|
|||
subject.errors[:raw_data].should include("can't be blank")
|
||||
end
|
||||
|
||||
context 'tool_settings' do
|
||||
subject { ToolProxy.create(
|
||||
shared_secret: 'shared_secret',
|
||||
guid: 'guid',
|
||||
product_version: '1.0beta',
|
||||
lti_version: 'LTI-2p0',
|
||||
product_family: product_family,
|
||||
context: account,
|
||||
workflow_state: 'active',
|
||||
raw_data: 'some raw data'
|
||||
) }
|
||||
it 'can have a tool setting' do
|
||||
subject.create_tool_setting(custom: {name: :foo})
|
||||
subject.tool_setting[:custom].should == {name: :foo}
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -20,6 +20,35 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb')
|
|||
|
||||
module Lti
|
||||
describe ToolSetting do
|
||||
let (:account) { Account.create }
|
||||
let (:product_family) { ProductFamily.create(vendor_code: '123', product_code: 'abc', vendor_name: 'acme', root_account: account) }
|
||||
let (:resource_handler) { ResourceHandler.create(resource_type_code: 'code', name: 'resource name', tool_proxy: tool_proxy) }
|
||||
let (:message_handler) { MessageHandler.create(message_type: 'message_type', launch_path: 'https://samplelaunch/blti', resource: resource_handler) }
|
||||
let (:tool_proxy) { ToolProxy.create(
|
||||
shared_secret: 'shared_secret',
|
||||
guid: 'guid',
|
||||
product_version: '1.0beta',
|
||||
lti_version: 'LTI-2p0',
|
||||
product_family: product_family,
|
||||
context: account,
|
||||
workflow_state: 'active',
|
||||
raw_data: 'some raw data'
|
||||
) }
|
||||
|
||||
it 'can be associated with a resource link' do
|
||||
subject.tool_proxy = tool_proxy
|
||||
subject.context = account
|
||||
subject.resource_link_id = '123456'
|
||||
subject.save.should == true
|
||||
end
|
||||
|
||||
it 'fails if there is a resource_link_id and no context' do
|
||||
subject.tool_proxy = tool_proxy
|
||||
subject.resource_link_id = '123456'
|
||||
subject.save.should == false
|
||||
subject.errors.first.should == [:context, "can't be blank"]
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue