From dc2a6dad660037ff5e191802528c62dfaf75ae86 Mon Sep 17 00:00:00 2001 From: Bradan Schwanke Date: Tue, 17 Mar 2026 10:14:36 -0600 Subject: [PATCH 1/3] Add lti_resource_link_created/updated live event methods Co-Authored-By: Claude Sonnet 4.6 --- lib/canvas/live_events.rb | 24 +++++++++++++ spec/lib/canvas/live_events_spec.rb | 56 +++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/lib/canvas/live_events.rb b/lib/canvas/live_events.rb index b3c4c6592bdca..5cd34e96d6144 100644 --- a/lib/canvas/live_events.rb +++ b/lib/canvas/live_events.rb @@ -630,6 +630,30 @@ def self.wiki_page_deleted(page) }) end + def self.get_lti_resource_link_data(resource_link) + { + resource_link_id: resource_link.global_id, + resource_link_uuid: resource_link.resource_link_uuid, + lookup_uuid: resource_link.lookup_uuid, + context_id: resource_link.global_context_id, + context_type: resource_link.context_type, + context_external_tool_id: resource_link.original_context_external_tool.global_id, + url: resource_link.url, + title: resource_link.title, + workflow_state: resource_link.workflow_state + } + end + + def self.lti_resource_link_created(resource_link) + post_event_stringified("lti_resource_link_created", + get_lti_resource_link_data(resource_link)) + end + + def self.lti_resource_link_updated(resource_link) + post_event_stringified("lti_resource_link_updated", + get_lti_resource_link_data(resource_link)) + end + def self.attachment_created(attachment) post_event_stringified("attachment_created", get_attachment_data(attachment)) end diff --git a/spec/lib/canvas/live_events_spec.rb b/spec/lib/canvas/live_events_spec.rb index be5205990fa9b..bda315fc9e559 100644 --- a/spec/lib/canvas/live_events_spec.rb +++ b/spec/lib/canvas/live_events_spec.rb @@ -284,6 +284,62 @@ def body end end + describe ".lti_resource_link_created" do + before do + course_with_teacher + @tool = external_tool_model(context: @course) + @resource_link = Lti::ResourceLink.create!( + context: @course, + context_external_tool: @tool, + url: "http://example.com/launch", + title: "My Link" + ) + end + + it "posts the correct event and payload" do + expect_event("lti_resource_link_created", { + resource_link_id: @resource_link.global_id.to_s, + resource_link_uuid: @resource_link.resource_link_uuid, + lookup_uuid: @resource_link.lookup_uuid, + context_id: @resource_link.global_context_id.to_s, + context_type: "Course", + context_external_tool_id: @tool.global_id.to_s, + url: "http://example.com/launch", + title: "My Link", + workflow_state: "active" + }) + Canvas::LiveEvents.lti_resource_link_created(@resource_link) + end + end + + describe ".lti_resource_link_updated" do + before do + course_with_teacher + @tool = external_tool_model(context: @course) + @resource_link = Lti::ResourceLink.create!( + context: @course, + context_external_tool: @tool, + url: "http://example.com/launch", + title: "My Link" + ) + end + + it "posts the correct event and payload" do + expect_event("lti_resource_link_updated", { + resource_link_id: @resource_link.global_id.to_s, + resource_link_uuid: @resource_link.resource_link_uuid, + lookup_uuid: @resource_link.lookup_uuid, + context_id: @resource_link.global_context_id.to_s, + context_type: "Course", + context_external_tool_id: @tool.global_id.to_s, + url: "http://example.com/launch", + title: "My Link", + workflow_state: "active" + }) + Canvas::LiveEvents.lti_resource_link_updated(@resource_link) + end + end + describe ".wiki_page_updated" do before do course_with_teacher From dd7136102f3ed7b578453787ba6c48f19bcafdc9 Mon Sep 17 00:00:00 2001 From: Bradan Schwanke Date: Tue, 17 Mar 2026 10:19:56 -0600 Subject: [PATCH 2/3] Use safe navigation for original_context_external_tool in resource link payload --- lib/canvas/live_events.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/canvas/live_events.rb b/lib/canvas/live_events.rb index 5cd34e96d6144..d36e41cef5ec1 100644 --- a/lib/canvas/live_events.rb +++ b/lib/canvas/live_events.rb @@ -637,7 +637,7 @@ def self.get_lti_resource_link_data(resource_link) lookup_uuid: resource_link.lookup_uuid, context_id: resource_link.global_context_id, context_type: resource_link.context_type, - context_external_tool_id: resource_link.original_context_external_tool.global_id, + context_external_tool_id: resource_link.original_context_external_tool&.global_id, url: resource_link.url, title: resource_link.title, workflow_state: resource_link.workflow_state From 58beb7a0b6370de8bf6c2d28b8b20ee4126ebf3a Mon Sep 17 00:00:00 2001 From: Bradan Schwanke Date: Tue, 17 Mar 2026 10:22:44 -0600 Subject: [PATCH 3/3] Wire Lti::ResourceLink to live events observer and callbacks Co-Authored-By: Claude Sonnet 4.6 --- app/observers/live_events_observer.rb | 1 + lib/canvas/live_events_callbacks.rb | 4 +++ spec/observers/live_events_observer_spec.rb | 34 +++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/app/observers/live_events_observer.rb b/app/observers/live_events_observer.rb index eab4298248bb0..2c78326519f6b 100644 --- a/app/observers/live_events_observer.rb +++ b/app/observers/live_events_observer.rb @@ -53,6 +53,7 @@ class LiveEventsObserver < ActiveRecord::Observer :user_account_association, :user, :wiki_page, + "Lti::ResourceLink", "MasterCourses::MasterTemplate", "MasterCourses::MasterMigration", "MasterCourses::ChildSubscription", diff --git a/lib/canvas/live_events_callbacks.rb b/lib/canvas/live_events_callbacks.rb index e531b773edbbc..08119bf7d51bb 100644 --- a/lib/canvas/live_events_callbacks.rb +++ b/lib/canvas/live_events_callbacks.rb @@ -46,6 +46,8 @@ def self.after_create(obj) Canvas::LiveEvents.group_membership_created(obj) when WikiPage Canvas::LiveEvents.wiki_page_created(obj) + when Lti::ResourceLink + Canvas::LiveEvents.lti_resource_link_created(obj) when Assignment Canvas::LiveEvents.assignment_created(obj) when AssignmentGroup @@ -135,6 +137,8 @@ def self.after_update(obj, changes) changes["title"]&.first, changes["body"]&.first) end + when Lti::ResourceLink + Canvas::LiveEvents.lti_resource_link_updated(obj) when Assignment Canvas::LiveEvents.assignment_updated(obj) when AssignmentGroup diff --git a/spec/observers/live_events_observer_spec.rb b/spec/observers/live_events_observer_spec.rb index e69696ba42858..2f2394ac47172 100644 --- a/spec/observers/live_events_observer_spec.rb +++ b/spec/observers/live_events_observer_spec.rb @@ -69,6 +69,40 @@ end end + describe "lti_resource_link" do + let(:course) { Course.create!(name: "Course") } + let(:tool) { external_tool_model(context: course) } + + it "posts lti_resource_link_created when a resource link is created" do + expect(Canvas::LiveEvents).to receive(:lti_resource_link_created).once + Lti::ResourceLink.create!( + context: course, + context_external_tool: tool, + url: "http://example.com/launch" + ) + end + + it "posts lti_resource_link_updated when a resource link is updated" do + resource_link = Lti::ResourceLink.create!( + context: course, + context_external_tool: tool, + url: "http://example.com/launch" + ) + expect(Canvas::LiveEvents).to receive(:lti_resource_link_updated).once + resource_link.update!(title: "New Title") + end + + it "posts lti_resource_link_updated (not deleted) when a resource link is soft deleted" do + resource_link = Lti::ResourceLink.create!( + context: course, + context_external_tool: tool, + url: "http://example.com/launch" + ) + expect(Canvas::LiveEvents).to receive(:lti_resource_link_updated).once + resource_link.destroy + end + end + describe "wiki" do it "posts create events" do expect(Canvas::LiveEvents).to receive(:wiki_page_created).once