add include[]=can_edit to assignments index
test plan: - render API docs and note include[]=can_edit - set up some assignments and assignment overrides including dates inside and outside closed grading periods - use this endpoint, including can_edit and all_dates - as a teacher, - ensure can_edit is true for assignments and dates in the absence of grading periods or moderated grading - ensure can_edit is false for a date that lands in a closed grading period (still true for the assignment, however) - ensure can_edit is false for an assignment and all dates for a moderated grading assignment where the teacher lacks "select final grade" permission and isn't the moderator - as a student, - ensure can_edit is false everywhere - as an account administrator, - ensure can_edit is true everywhere - also test the can_edit include in - assignment show - assignment group index w/include[]=assignments flag=none closes LA-861 Change-Id: I7c0df7a0071cfd2bdb97e09cf4b77800de962d54 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/232004 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Anju Reddy <areddy@instructure.com> Product-Review: Jeremy Stanley <jeremy@instructure.com> Reviewed-by: James Williams <jamesw@instructure.com> Reviewed-by: Jon Willesen <jonw+gerrit@instructure.com>
This commit is contained in:
parent
2a8b3c95a4
commit
1c62e34641
|
@ -101,8 +101,8 @@ class AssignmentGroupsController < ApplicationController
|
|||
# Returns the paginated list of assignment groups for the current context.
|
||||
# The returned groups are sorted by their position field.
|
||||
#
|
||||
# @argument include[] [String, "assignments"|"discussion_topic"|"all_dates"|"assignment_visibility"|"overrides"|"submission"|"observed_users"]
|
||||
# Associations to include with the group. "discussion_topic", "all_dates"
|
||||
# @argument include[] [String, "assignments"|"discussion_topic"|"all_dates"|"assignment_visibility"|"overrides"|"submission"|"observed_users"|"can_edit"]
|
||||
# Associations to include with the group. "discussion_topic", "all_dates", "can_edit",
|
||||
# "assignment_visibility" & "submission" are only valid if "assignments" is also included.
|
||||
# The "assignment_visibility" option additionally requires that the Differentiated Assignments course feature be turned on.
|
||||
# If "observed_users" is passed along with "assignments" and "submission", submissions for observed users will also be included as an array.
|
||||
|
|
|
@ -627,10 +627,14 @@ class AssignmentsApiController < ApplicationController
|
|||
|
||||
# @API List assignments
|
||||
# Returns the paginated list of assignments for the current course or assignment group.
|
||||
# @argument include[] [String, "submission"|"assignment_visibility"|"all_dates"|"overrides"|"observed_users"]
|
||||
# Associations to include with the assignment. The "assignment_visibility" option
|
||||
# requires that the Differentiated Assignments course feature be turned on. If
|
||||
# "observed_users" is passed, submissions for observed users will also be included as an array.
|
||||
# @argument include[] [String, "submission"|"assignment_visibility"|"all_dates"|"overrides"|"observed_users"|"can_edit"]
|
||||
# Optional information to include with each assignment:
|
||||
# submission:: The current user's current +Submission+
|
||||
# assignment_visibility:: An array of ids of students who can see the assignment
|
||||
# all_dates:: An array of +AssignmentDate+ structures, one for each override, and also a +base+ if the assignment has an "Everyone" / "Everyone Else" date
|
||||
# overrides:: An array of +AssignmentOverride+ structures
|
||||
# observed_users:: An array of submissions for observed users
|
||||
# can_edit:: an extra Boolean value will be included with each +Assignment+ (and +AssignmentDate+ if +all_dates+ is supplied) to indicate whether the caller can edit the assignment or date. Moderated grading and closed grading periods may restrict a user's ability to edit an assignment.
|
||||
# @argument search_term [String]
|
||||
# The partial title of the assignments to match and return.
|
||||
# @argument override_assignment_dates [Boolean]
|
||||
|
@ -827,7 +831,8 @@ class AssignmentsApiController < ApplicationController
|
|||
include_all_dates: include_all_dates,
|
||||
bucket: params[:bucket],
|
||||
include_overrides: include_override_objects,
|
||||
preloaded_user_content_attachments: preloaded_attachments
|
||||
preloaded_user_content_attachments: preloaded_attachments,
|
||||
include_can_edit: include_params.include?('can_edit')
|
||||
)
|
||||
end
|
||||
hashes
|
||||
|
@ -836,7 +841,7 @@ class AssignmentsApiController < ApplicationController
|
|||
|
||||
# @API Get a single assignment
|
||||
# Returns the assignment with the given id.
|
||||
# @argument include[] [String, "submission"|"assignment_visibility"|"overrides"|"observed_users"]
|
||||
# @argument include[] [String, "submission"|"assignment_visibility"|"overrides"|"observed_users"|"can_edit"]
|
||||
# Associations to include with the assignment. The "assignment_visibility" option
|
||||
# requires that the Differentiated Assignments course feature be turned on. If
|
||||
# "observed_users" is passed, submissions for observed users will also be included.
|
||||
|
@ -879,7 +884,8 @@ class AssignmentsApiController < ApplicationController
|
|||
include_visibility: include_visibility,
|
||||
needs_grading_count_by_section: needs_grading_count_by_section,
|
||||
include_all_dates: include_all_dates,
|
||||
include_overrides: include_override_objects
|
||||
include_overrides: include_override_objects,
|
||||
include_can_edit: included_params.include?('can_edit')
|
||||
}
|
||||
|
||||
result_json = if use_quiz_json?
|
||||
|
|
|
@ -120,7 +120,8 @@ module Api::V1::Assignment
|
|||
override_dates: true,
|
||||
needs_grading_count_by_section: false,
|
||||
exclude_response_fields: [],
|
||||
include_planner_override: false
|
||||
include_planner_override: false,
|
||||
include_can_edit: false
|
||||
)
|
||||
|
||||
if opts[:override_dates] && !assignment.new_record?
|
||||
|
@ -314,6 +315,16 @@ module Api::V1::Assignment
|
|||
end
|
||||
end
|
||||
|
||||
if opts[:include_can_edit]
|
||||
can_edit_assignment = assignment.user_can_update?(user, session)
|
||||
hash['can_edit'] = can_edit_assignment
|
||||
hash['all_dates']&.each do |date_hash|
|
||||
in_closed_grading_period = date_in_closed_grading_period?(date_hash['due_at'])
|
||||
date_hash['in_closed_grading_period'] = in_closed_grading_period
|
||||
date_hash['can_edit'] = can_edit_assignment && (!in_closed_grading_period || !constrained_by_grading_periods?)
|
||||
end
|
||||
end
|
||||
|
||||
if opts[:include_module_ids]
|
||||
modulable = case assignment.submission_types
|
||||
when 'online_quiz' then assignment.quiz
|
||||
|
|
|
@ -73,6 +73,7 @@ module Api::V1::AssignmentGroup
|
|||
json = assignment_json(assignment, user, session,
|
||||
include_discussion_topic: includes.include?('discussion_topic'),
|
||||
include_all_dates: includes.include?('all_dates'),
|
||||
include_can_edit: includes.include?('can_edit'),
|
||||
include_module_ids: includes.include?('module_ids'),
|
||||
include_grades_published: includes.include?('grades_published'),
|
||||
override_dates: opts[:override_assignment_dates],
|
||||
|
|
|
@ -16,10 +16,14 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module SubmittablesGradingPeriodProtection
|
||||
def constrained_by_grading_periods?
|
||||
grading_periods? && !current_user_is_context_admin?
|
||||
end
|
||||
|
||||
def grading_periods_allow_submittable_create?(submittable, submittable_params, flash_message: false)
|
||||
apply_grading_params(submittable, submittable_params)
|
||||
return true unless submittable.graded?
|
||||
return true unless grading_periods? && !current_user_is_context_admin?
|
||||
return true unless constrained_by_grading_periods?
|
||||
return true if submittable_params[:only_visible_to_overrides]
|
||||
|
||||
submittable.due_at = submittable_params[:due_at]
|
||||
|
@ -36,7 +40,7 @@ module SubmittablesGradingPeriodProtection
|
|||
submittable_params[:only_visible_to_overrides] if submittable_params.key?(:only_visible_to_overrides)
|
||||
submittable.due_at = submittable_params[:due_at] if submittable_params.key?(:due_at)
|
||||
return true unless submittable.only_visible_to_overrides_changed? || due_at_changed?(submittable)
|
||||
return true unless grading_periods? && !current_user_is_context_admin?
|
||||
return true unless constrained_by_grading_periods?
|
||||
|
||||
in_closed_grading_period = date_in_closed_grading_period?(submittable.due_at_was)
|
||||
|
||||
|
@ -59,7 +63,7 @@ module SubmittablesGradingPeriodProtection
|
|||
end
|
||||
|
||||
def grading_periods_allow_assignment_overrides_batch_create?(submittable, overrides, flash_message: false)
|
||||
return true unless grading_periods? && !current_user_is_context_admin?
|
||||
return true unless constrained_by_grading_periods?
|
||||
return true unless overrides.any? {|override| date_in_closed_grading_period?(override[:due_at])}
|
||||
|
||||
apply_error(submittable, :due_at, ERROR_MESSAGES[:set_override_due_at_in_closed], flash_message)
|
||||
|
@ -67,14 +71,14 @@ module SubmittablesGradingPeriodProtection
|
|||
end
|
||||
|
||||
def grading_periods_allow_assignment_overrides_batch_update?(submittable, prepared_batch, flash_message: false)
|
||||
return true unless grading_periods? && !current_user_is_context_admin?
|
||||
return true unless constrained_by_grading_periods?
|
||||
can_create_overrides?(submittable, prepared_batch[:overrides_to_create], flash_message: flash_message) &&
|
||||
can_update_overrides?(submittable, prepared_batch[:overrides_to_update], flash_message: flash_message) &&
|
||||
can_delete_overrides?(submittable, prepared_batch[:overrides_to_delete], flash_message: flash_message)
|
||||
end
|
||||
|
||||
def grading_periods_allow_assignment_override_update?(override)
|
||||
return true unless grading_periods? && !current_user_is_context_admin?
|
||||
return true unless constrained_by_grading_periods?
|
||||
return true unless override.changed?
|
||||
|
||||
if date_in_closed_grading_period?(override.due_at_was)
|
||||
|
@ -90,6 +94,10 @@ module SubmittablesGradingPeriodProtection
|
|||
true
|
||||
end
|
||||
|
||||
def date_in_closed_grading_period?(date)
|
||||
GradingPeriodHelper.date_in_closed_grading_period?(date, context_grading_periods)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def due_at_changed?(submittable)
|
||||
|
@ -151,10 +159,6 @@ module SubmittablesGradingPeriodProtection
|
|||
@context_grading_periods ||= GradingPeriod.for(@context)
|
||||
end
|
||||
|
||||
def date_in_closed_grading_period?(date)
|
||||
GradingPeriodHelper.date_in_closed_grading_period?(date, context_grading_periods)
|
||||
end
|
||||
|
||||
def apply_error(submittable, attribute, message, flash_message)
|
||||
submittable.errors.add(attribute, message)
|
||||
flash[:error] = message if flash_message
|
||||
|
|
|
@ -480,10 +480,10 @@ describe AssignmentGroupsController, type: :request do
|
|||
a1.reload
|
||||
|
||||
json = api_call(:get,
|
||||
"/api/v1/courses/#{@course.id}/assignment_groups.json?include[]=assignments&include[]=all_dates",
|
||||
"/api/v1/courses/#{@course.id}/assignment_groups.json?include[]=assignments&include[]=all_dates&include[]=can_edit",
|
||||
{ controller: 'assignment_groups', action: 'index',
|
||||
format: 'json', course_id: @course.id.to_s,
|
||||
include: ['assignments', 'all_dates'] })
|
||||
include: ['assignments', 'all_dates', 'can_edit'] })
|
||||
|
||||
expected = [
|
||||
{
|
||||
|
@ -496,8 +496,8 @@ describe AssignmentGroupsController, type: :request do
|
|||
'integration_data' => {},
|
||||
'sis_source_id' => nil,
|
||||
'assignments' => [
|
||||
controller.assignment_json(a1, @user,session, include_all_dates: true).as_json,
|
||||
controller.assignment_json(a2, @user,session, include_all_dates: true).as_json
|
||||
controller.assignment_json(a1, @user,session, include_all_dates: true, include_can_edit: true).as_json,
|
||||
controller.assignment_json(a2, @user,session, include_all_dates: true, include_can_edit: true).as_json
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -5318,19 +5318,6 @@ describe AssignmentsApiController, type: :request do
|
|||
api_bulk_update(@course, [], expected_status: 401)
|
||||
end
|
||||
|
||||
it "disallows editing moderated assignments if you're not the moderator" do
|
||||
@course.account.role_overrides.create!(permission: :select_final_grade, enabled: false, role: ta_role)
|
||||
ta_in_course(:active_all => true)
|
||||
|
||||
api_bulk_update(@course, [{'id' => @a0.id, 'all_dates' => []}])
|
||||
|
||||
@a0.moderated_grading = true
|
||||
@a0.final_grader_id = @teacher
|
||||
@a0.grader_count = 1
|
||||
@a0.save!
|
||||
api_bulk_update(@course, [{'id' => @a0.id, 'all_dates' => []}], expected_status: 401)
|
||||
end
|
||||
|
||||
it "expects an array of assignments" do
|
||||
api_bulk_update(@course, {}, expected_status: 400)
|
||||
end
|
||||
|
@ -5518,6 +5505,84 @@ describe AssignmentsApiController, type: :request do
|
|||
expect_any_instance_of(Course).to receive(:recompute_student_scores_without_send_later).once
|
||||
api_bulk_update(@course, data)
|
||||
end
|
||||
|
||||
it "sets can_edit on each date if requested" do
|
||||
json = api_get_assignments_index_from_course(@course, include: %w(all_dates can_edit))
|
||||
a0_json = json.detect { |a| a['id'] == @a0.id }
|
||||
expect(a0_json['can_edit']).to eq true
|
||||
expect(a0_json['all_dates'].map { |d| d['can_edit'] }).to eq [true]
|
||||
expect(a0_json['all_dates'].map { |d| d['in_closed_grading_period'] }).to eq [false]
|
||||
|
||||
a1_json = json.detect { |a| a['id'] == @a1.id }
|
||||
expect(a1_json['can_edit']).to eq true
|
||||
expect(a1_json['all_dates'].map { |d| d['can_edit'] }).to eq [false]
|
||||
expect(a1_json['all_dates'].map { |d| d['in_closed_grading_period'] }).to eq [true]
|
||||
|
||||
a2_json = json.detect { |a| a['id'] == @a2.id }
|
||||
expect(a2_json['can_edit']).to eq true
|
||||
|
||||
ao0_json = a2_json['all_dates'].detect { |ao| ao['id'] == @ao0.id }
|
||||
expect(ao0_json['can_edit']).to eq false
|
||||
expect(ao0_json['in_closed_grading_period']).to eq true
|
||||
|
||||
ao1_json = a2_json['all_dates'].detect { |ao| ao['id'] == @ao1.id }
|
||||
expect(ao1_json['can_edit']).to eq true
|
||||
expect(ao1_json['in_closed_grading_period']).to eq false
|
||||
end
|
||||
|
||||
it "allows account admins to edit whatever they want" do
|
||||
account_admin_user
|
||||
json = api_get_assignments_index_from_course(@course, include: %w(all_dates can_edit))
|
||||
a0_json = json.detect { |a| a['id'] == @a0.id }
|
||||
expect(a0_json['can_edit']).to eq true
|
||||
expect(a0_json['all_dates'].map { |d| d['can_edit'] }).to eq [true]
|
||||
expect(a0_json['all_dates'].map { |d| d['in_closed_grading_period'] }).to eq [false]
|
||||
|
||||
a1_json = json.detect { |a| a['id'] == @a1.id }
|
||||
expect(a1_json['can_edit']).to eq true
|
||||
expect(a1_json['all_dates'].map { |d| d['can_edit'] }).to eq [true]
|
||||
expect(a1_json['all_dates'].map { |d| d['in_closed_grading_period'] }).to eq [true]
|
||||
|
||||
a2_json = json.detect { |a| a['id'] == @a2.id }
|
||||
expect(a2_json['can_edit']).to eq true
|
||||
|
||||
ao0_json = a2_json['all_dates'].detect { |ao| ao['id'] == @ao0.id }
|
||||
expect(ao0_json['can_edit']).to eq true
|
||||
expect(ao0_json['in_closed_grading_period']).to eq true
|
||||
|
||||
ao1_json = a2_json['all_dates'].detect { |ao| ao['id'] == @ao1.id }
|
||||
expect(ao1_json['can_edit']).to eq true
|
||||
expect(ao1_json['in_closed_grading_period']).to eq false
|
||||
end
|
||||
end
|
||||
|
||||
context "with moderated grading" do
|
||||
before :once do
|
||||
@course.account.role_overrides.create!(permission: :select_final_grade, enabled: false, role: ta_role)
|
||||
ta_in_course(:active_all => true)
|
||||
|
||||
@a0.moderated_grading = true
|
||||
@a0.final_grader_id = @teacher
|
||||
@a0.grader_count = 1
|
||||
@a0.save!
|
||||
end
|
||||
|
||||
it "disallows editing moderated assignments if you're not the moderator" do
|
||||
api_bulk_update(@course, [{'id' => @a0.id, 'all_dates' => []}], expected_status: 401)
|
||||
api_bulk_update(@course, [{'id' => @a1.id, 'all_dates' => []}])
|
||||
end
|
||||
|
||||
it "sets can_edit on each date if requested" do
|
||||
json = api_get_assignments_index_from_course(@course, include: %w(all_dates can_edit))
|
||||
|
||||
a0_json = json.detect { |a| a['id'] == @a0.id }
|
||||
expect(a0_json['can_edit']).to eq false
|
||||
expect(a0_json['all_dates'].map { |d| d['can_edit'] }).to eq [false]
|
||||
|
||||
a1_json = json.detect { |a| a['id'] == @a1.id }
|
||||
expect(a1_json['can_edit']).to eq true
|
||||
expect(a1_json['all_dates'].map { |d| d['can_edit'] }).to eq [true]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue