Slice module's attributes in LockedFor

Now that we're not using an OpenObject, we can't include the
completion_events attribute when instantiating an actual ContextModule
else we'll call the completion_events= setter, which tries to map
the actual completion_events string value instead of the deserialized
array. We really don't need any other attributes besides the ones
listed, so just include the limited set in lock_info.

fixes LF-1583
fixes CANVAS-N288
fixes CANVAS-N2P9
flag = none

Test plan:
 - Enable the grade_export plugin and mark a module as "Publish final
   grade for the student when this module is completed" OR find a
   module in the rails console and set completion_events:
   ["publish_final_grade"]
 - Add a page to that module
 - Unpublish that module
 - Visit the pages index as a student
 - Expect it to load
 - Expect the page to be locked (i.e., accessible on the index, but
   shows a lock page when clicked)

Change-Id: Ie24003ace402d0154fe3947752356ce9f65288f1
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/347131
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Cody Cutrer <cody@instructure.com>
QA-Review: Sarah Gerard <sarah.gerard@instructure.com>
Product-Review: Jackson Howe <jackson.howe@instructure.com>
This commit is contained in:
Jackson Howe 2024-05-09 15:44:54 -06:00
parent a32a26ac25
commit 3beb421cba
3 changed files with 14 additions and 2 deletions

View File

@ -1555,7 +1555,7 @@ class Attachment < ActiveRecord::Base
elsif lock_at && Time.now > lock_at
locked = { asset_string:, lock_at: }
elsif could_be_locked && (item = locked_by_module_item?(user, opts))
locked = { asset_string:, context_module: item.context_module.attributes }
locked = { asset_string:, context_module: item.context_module.attributes.slice(*LockedFor::MODULE_ATTRIBUTES) }
locked[:unlock_at] = locked[:context_module]["unlock_at"] if locked[:context_module]["unlock_at"] && locked[:context_module]["unlock_at"] > Time.now.utc
end
locked

View File

@ -19,12 +19,14 @@
#
module LockedFor
MODULE_ATTRIBUTES = %w[id name context_type context_id workflow_state unlock_at].freeze
def locked_for?(user, opts = {})
lock_info = low_level_locked_for?(user, opts).dup
return false if lock_info == false
lock_info[:asset_string] = lock_info.delete(:object).asset_string
lock_info[:context_module] = lock_info.delete(:module).attributes if lock_info.key?(:module)
lock_info[:context_module] = lock_info.delete(:module).attributes.slice(*MODULE_ATTRIBUTES) if lock_info.key?(:module)
lock_info
end
end

View File

@ -1541,6 +1541,16 @@ describe "Pages API", type: :request do
{ controller: "wiki_pages_api", action: "show", format: "json", course_id: other_course.id.to_s, url_or_id: "front-page" })
end
it "includes lock info on pages locked by a module with completion_events" do
cm = @course.context_modules.create!(name: "unpublished module", workflow_state: "unpublished", completion_events: ["publish_final_grade"])
cm.add_item(id: @front_page.id, type: "wiki_page")
json = api_call(:get,
"/api/v1/courses/#{@course.id}/pages",
{ controller: "wiki_pages_api", action: "index", format: "json", course_id: @course.id.to_s })
expect(response).to be_successful
expect(json.find { |page| page["url"] == @front_page.url }["lock_explanation"]).to eq("This page is part of an unpublished module and is not available yet.")
end
describe "module progression" do
before :once do
@mod = @course.context_modules.create!(name: "some module")