Consider resource type code when sending tool events

Fixes INTEROP-6252
flag=none

Test Plan:
- Install multiple plagiarism detection tools
  in the same account with _different_ resource
  type codes. Each tool should also have a different
  endpoint
- Associate an assignment with one of the tools
- Submit and verify an event is sent to the tool
  with the matching resource type code
- Verify events were not sent to the other tools

Change-Id: I5892451c2ac3af64254881319d6f1143703a5cb6
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/249776
Reviewed-by: Mysti Lilla <mysti@instructure.com>
QA-Review: Tucker Mcknight <tmcknight@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Product-Review: Weston Dransfield <wdransfield@instructure.com>
This commit is contained in:
wdransfield 2020-10-09 21:22:13 -06:00 committed by Weston Dransfield
parent cbcaafb773
commit 2e96e905b2
5 changed files with 144 additions and 29 deletions

View File

@ -69,7 +69,7 @@ module Lti
ToolProxy.joins("JOIN (#{subquery}) bindings on lti_tool_proxies.id = bindings.tool_proxy_id").where('bindings.enabled = true')
end
def self.find_all_proxies_for_context_by_context_order_by_vendor_product_code(context:, vendor_code:, product_code:)
def self.proxies_in_order_by_codes(context:, vendor_code:, product_code:, resource_type_code:)
account_ids = context.account_chain.map { |a| a.id }
# Added i+1 on this to ensure that the x.ordering later doesn't have 2 0's
@ -89,12 +89,13 @@ module Lti
select('lti_tool_proxies.*, bindings.enabled AS binding_enabled').
# changed this from eager_load, because eager_load likes to wipe out custom select attributes
joins(:product_family).
preload(:product_family).
joins(:resources).
# changed the order to go from the special ordering set up (to make sure we're going from the course to the
# root account in order of parent accounts) and then takes the most recently installed tool
order('ordering, lti_tool_proxies.id DESC').
where('lti_tool_proxies.workflow_state = ?', 'active').
where('lti_product_families.vendor_code = ? AND lti_product_families.product_code = ?', vendor_code, product_code)
where('lti_product_families.vendor_code = ? AND lti_product_families.product_code = ?', vendor_code, product_code).
where('lti_resource_handlers.resource_type_code = ?', resource_type_code)
# You can disable a tool_binding somewhere in the account chain, and anything below that that reenables it should be
# available, but nothing above it, so we're getting rid of anything that is disabled and above
tools.split{|tool| !tool.binding_enabled}.first

View File

@ -240,10 +240,11 @@ module Canvas::LiveEvents
domain = assignment.root_account&.domain(ApplicationController.test_cluster_name)
event[:domain] = domain if domain
if actl
if (tool_proxy = Lti::ToolProxy.find_all_proxies_for_context_by_context_order_by_vendor_product_code(
if (tool_proxy = Lti::ToolProxy.proxies_in_order_by_codes(
context: assignment.course,
vendor_code: actl.tool_vendor_code,
product_code: actl.tool_product_code
product_code: actl.tool_product_code,
resource_type_code: actl.tool_resource_type_code
).first)
event[:associated_integration_id] = [actl.tool_vendor_code, actl.tool_product_code, tool_proxy.event_endpoint].join('_')
end
@ -344,10 +345,11 @@ module Canvas::LiveEvents
}
actl = submission.assignment.assignment_configuration_tool_lookups.take
if actl
if (tool_proxy = Lti::ToolProxy.find_all_proxies_for_context_by_context_order_by_vendor_product_code(
if (tool_proxy = Lti::ToolProxy.proxies_in_order_by_codes(
context: submission.course,
vendor_code: actl.tool_vendor_code,
product_code: actl.tool_product_code
product_code: actl.tool_product_code,
resource_type_code: actl.tool_resource_type_code
).first)
event[:associated_integration_id] = [actl.tool_vendor_code, actl.tool_product_code, tool_proxy.event_endpoint].join('_')
end

View File

@ -591,12 +591,23 @@ describe Canvas::LiveEvents do
end
it 'should include the associated_integration_id if there is an installed tool proxy with that id' do
submission.assignment.assignment_configuration_tool_lookups.create!(tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com', tool_type: 'Lti::MessageHandler')
submission.assignment.assignment_configuration_tool_lookups.create!(
tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com',
tool_resource_type_code: 'resource-type-code',
tool_type: 'Lti::MessageHandler'
)
tool_proxy = create_tool_proxy(submission.assignment.course)
tool_proxy[:raw_data]['tool_profile'] = {'service_offered' => [submission_event_service]}
tool_proxy.save!
Lti::ResourceHandler.create!(
tool_proxy: tool_proxy,
name: 'resource_handler',
resource_type_code: 'resource-type-code'
)
expect_event('submission_created',
hash_including(
associated_integration_id: "turnitin.com_turnitin-lti_test.com/submission"
@ -680,12 +691,23 @@ describe Canvas::LiveEvents do
end
it 'should include the associated_integration_id if there is an installed tool proxy with that id' do
submission.assignment.assignment_configuration_tool_lookups.create!(tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com', tool_type: 'Lti::MessageHandler')
submission.assignment.assignment_configuration_tool_lookups.create!(
tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com',
tool_resource_type_code: 'resource-type-code',
tool_type: 'Lti::MessageHandler'
)
tool_proxy = create_tool_proxy(submission.assignment.course)
tool_proxy[:raw_data]['tool_profile'] = {'service_offered' => [submission_event_service]}
tool_proxy.save!
Lti::ResourceHandler.create!(
tool_proxy: tool_proxy,
name: 'resource_handler',
resource_type_code: 'resource-type-code'
)
expect_event('submission_updated',
hash_including(
associated_integration_id: "turnitin.com_turnitin-lti_test.com/submission"
@ -803,12 +825,23 @@ describe Canvas::LiveEvents do
end
it 'should include the associated_integration_id if there is an installed tool proxy with that id' do
submission.assignment.assignment_configuration_tool_lookups.create!(tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com', tool_type: 'Lti::MessageHandler')
submission.assignment.assignment_configuration_tool_lookups.create!(
tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com',
tool_resource_type_code: 'resource-type-code',
tool_type: 'Lti::MessageHandler'
)
tool_proxy = create_tool_proxy(submission.assignment.course)
tool_proxy[:raw_data]['tool_profile'] = {'service_offered' => [submission_event_service]}
tool_proxy.save!
Lti::ResourceHandler.create!(
tool_proxy: tool_proxy,
name: 'resource_handler',
resource_type_code: 'resource-type-code'
)
expect_event('plagiarism_resubmit',
hash_including(
associated_integration_id: "turnitin.com_turnitin-lti_test.com/submission"
@ -987,11 +1020,21 @@ describe Canvas::LiveEvents do
end
it 'should include the associated_integration_id if there is an installed tool proxy with that id' do
@assignment.assignment_configuration_tool_lookups.create!(tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com', tool_type: 'Lti::MessageHandler')
@assignment.assignment_configuration_tool_lookups.create!(
tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com',
tool_resource_type_code: 'resource-type-code',
tool_type: 'Lti::MessageHandler'
)
tool_proxy = create_tool_proxy(@assignment.course)
tool_proxy[:raw_data]['tool_profile'] = {'service_offered' => [submission_event_service]}
tool_proxy.save!
tool_proxy[:raw_data]['tool_profile'] = {'service_offered' => [submission_event_service]}
tool_proxy.save!
Lti::ResourceHandler.create!(
tool_proxy: tool_proxy,
name: 'resource_handler',
resource_type_code: 'resource-type-code'
)
expect_event('assignment_created',
hash_including(
@ -1001,8 +1044,12 @@ describe Canvas::LiveEvents do
end
it 'should not include the associated_integration_id if there is no longer an installed tool with that id' do
@assignment.assignment_configuration_tool_lookups.create!(tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com', tool_type: 'Lti::MessageHandler')
@assignment.assignment_configuration_tool_lookups.create!(
tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com',
tool_resource_type_code: 'resource-type-code',
tool_type: 'Lti::MessageHandler'
)
expect_event('assignment_created',
hash_not_including(
@ -1056,11 +1103,22 @@ describe Canvas::LiveEvents do
end
it 'should include the associated_integration_id if there is an installed tool proxy with that id' do
@assignment.assignment_configuration_tool_lookups.create!(tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com', tool_type: 'Lti::MessageHandler')
@assignment.assignment_configuration_tool_lookups.create!(
tool_product_code: 'turnitin-lti',
tool_vendor_code: 'turnitin.com',
tool_resource_type_code: 'resource-type-code',
tool_type: 'Lti::MessageHandler'
)
tool_proxy = create_tool_proxy(@assignment.course)
tool_proxy[:raw_data]['tool_profile'] = {'service_offered' => [submission_event_service]}
tool_proxy.save!
tool_proxy[:raw_data]['tool_profile'] = {'service_offered' => [submission_event_service]}
tool_proxy.save!
Lti::ResourceHandler.create!(
tool_proxy: tool_proxy,
name: 'resource_handler',
resource_type_code: 'resource-type-code'
)
expect_event('assignment_updated',
hash_including(

View File

@ -108,6 +108,7 @@ RSpec.shared_context "lti2_spec_helper", :shared_context => :metadata do
},
lti_version: '1'
)
Lti::ToolProxyBinding.where(context_id: context.id, context_type: context.class.to_s,
tool_proxy_id: tp).first_or_create!
tp

View File

@ -195,7 +195,7 @@ module Lti
end
end
describe '#find_all_proxies_for_context_by_context_order_by_vendor_product_code' do
describe '#proxies_in_order_by_codes' do
let(:course) { course_model(account: sub_account_2_1) }
it 'returns tool proxies in context hierarchy order' do
@ -206,7 +206,12 @@ module Lti
tool_proxy3 = create_tool_proxy(context: course)
tool_proxy3.bindings.create!(context: course)
tools = described_class.find_all_proxies_for_context_by_context_order_by_vendor_product_code(context: course, vendor_code: '123', product_code: 'abc')
tools = described_class.proxies_in_order_by_codes(
context: course,
vendor_code: '123',
product_code: 'abc',
resource_type_code: 'resource-type-code'
)
expect(tools.map(&:id)).to eq([tool_proxy3.id, tool_proxy2.id, tool_proxy1.id])
end
@ -220,7 +225,12 @@ module Lti
tool_proxy4 = create_tool_proxy(context: course)
tool_proxy4.bindings.create!(context: course)
tools = described_class.find_all_proxies_for_context_by_context_order_by_vendor_product_code(context: course, vendor_code: '123', product_code: 'abc')
tools = described_class.proxies_in_order_by_codes(
context: course,
vendor_code: '123',
product_code: 'abc',
resource_type_code: 'resource-type-code'
)
expect(tools.map(&:id)).to eq([tool_proxy4.id, tool_proxy3.id, tool_proxy2.id, tool_proxy1.id])
end
@ -228,16 +238,47 @@ module Lti
tool_proxy = create_tool_proxy(context: sub_account_2_1)
tool_proxy.bindings.create!(context: sub_account_2_1, enabled: false)
tool_proxy.bindings.create!(context: sub_account_1_1)
proxies = described_class.find_all_proxies_for_context_by_context_order_by_vendor_product_code(context: sub_account_2_1, vendor_code: '123', product_code: 'abc')
proxies = described_class.proxies_in_order_by_codes(
context: sub_account_2_1,
vendor_code: '123',
product_code: 'abc',
resource_type_code: 'resource-type-code'
)
expect(proxies.count).to eq 0
end
it "doesn't return deleted tool proxies" do
tool_proxy = create_tool_proxy(context: sub_account_2_1, workflow_state: 'deleted')
tool_proxy.bindings.create!(context: sub_account_2_1)
proxies = described_class.find_all_proxies_for_context_by_context_order_by_vendor_product_code(context: sub_account_2_1, vendor_code: '123', product_code: 'abc')
proxies = described_class.proxies_in_order_by_codes(
context: sub_account_2_1,
vendor_code: '123',
product_code: 'abc',
resource_type_code: 'resource-type-code'
)
expect(proxies.count).to eq 0
end
it "does not return tools with mismatched resource type codes" do
tool_proxy1 = create_tool_proxy(context: root_account)
tool_proxy1.bindings.create!(context: root_account)
tool_proxy2 = create_tool_proxy(context: root_account)
tool_proxy2.bindings.create!(context: root_account)
tool_proxy3 = create_tool_proxy(context: course)
tool_proxy3.bindings.create!(context: course)
tool_proxy4 = create_tool_proxy(context: course)
tool_proxy4.bindings.create!(context: course)
tool_proxy4.resources.first.update!(resource_type_code: 'changed!')
tools = described_class.proxies_in_order_by_codes(
context: course,
vendor_code: '123',
product_code: 'abc',
resource_type_code: 'resource-type-code'
)
expect(tools.map(&:id)).to eq([tool_proxy3.id, tool_proxy2.id, tool_proxy1.id])
end
end
describe "#find_active_proxies_for_context_by_vendor_code_and_product_code" do
@ -318,7 +359,19 @@ module Lti
workflow_state: 'active',
raw_data: 'some raw data'
}
ToolProxy.create(default_opts.merge(opts))
tp = ToolProxy.create(default_opts.merge(opts))
create_resource_handler(tp)
tp
end
def create_resource_handler(tool_proxy)
return unless tool_proxy.persisted?
Lti::ResourceHandler.create!(
tool_proxy: tool_proxy,
name: 'resource_handler',
resource_type_code: 'resource-type-code'
)
end
context "singleton message handlers" do