182 lines
7.7 KiB
Ruby
182 lines
7.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
#
|
|
# Copyright (C) 2016 - present 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 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 constrained_by_grading_periods?
|
|
return true if submittable_params[:only_visible_to_overrides]
|
|
|
|
submittable.due_at = submittable_params[:due_at]
|
|
return true unless GradingPeriodHelper.date_in_closed_grading_period?(submittable.due_at, context_grading_periods)
|
|
|
|
apply_error(submittable, :due_at, ERROR_MESSAGES[:set_due_at_in_closed], flash_message)
|
|
false
|
|
end
|
|
|
|
def grading_periods_allow_submittable_update?(submittable, submittable_params, flash_message: false)
|
|
return true unless submittable.graded?
|
|
|
|
if submittable_params.key?(:only_visible_to_overrides)
|
|
submittable.only_visible_to_overrides =
|
|
submittable_params[:only_visible_to_overrides]
|
|
end
|
|
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 constrained_by_grading_periods?
|
|
|
|
in_closed_grading_period = date_in_closed_grading_period?(submittable.due_at_was)
|
|
|
|
if in_closed_grading_period && !submittable.only_visible_to_overrides_was
|
|
if due_at_changed?(submittable)
|
|
apply_error(submittable, :due_at, ERROR_MESSAGES[:change_due_at_in_closed], flash_message)
|
|
else
|
|
message = ERROR_MESSAGES[:change_only_visible_to_overrides]
|
|
apply_error(submittable, :only_visible_to_overrides, message, flash_message)
|
|
end
|
|
return false
|
|
end
|
|
|
|
return true if submittable.only_visible_to_overrides && submittable.only_visible_to_overrides_was
|
|
return true unless date_in_closed_grading_period?(submittable.due_at)
|
|
|
|
apply_error(submittable, :due_at, ERROR_MESSAGES[:change_due_at_to_closed], flash_message)
|
|
false
|
|
end
|
|
|
|
def grading_periods_allow_assignment_overrides_batch_create?(submittable, overrides, flash_message: false)
|
|
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)
|
|
false
|
|
end
|
|
|
|
def grading_periods_allow_assignment_overrides_batch_update?(submittable, prepared_batch, flash_message: false)
|
|
return true unless constrained_by_grading_periods?
|
|
|
|
can_create_overrides?(submittable, prepared_batch[:overrides_to_create], flash_message:) &&
|
|
can_update_overrides?(submittable, prepared_batch[:overrides_to_update], flash_message:) &&
|
|
can_delete_overrides?(submittable, prepared_batch[:overrides_to_delete], flash_message:)
|
|
end
|
|
|
|
def grading_periods_allow_assignment_override_update?(override)
|
|
return true unless constrained_by_grading_periods?
|
|
return true unless override.changed?
|
|
|
|
if date_in_closed_grading_period?(override.due_at_was)
|
|
apply_error(override, :due_at, ERROR_MESSAGES[:change_override_due_at_in_closed], false)
|
|
return false
|
|
end
|
|
|
|
if date_in_closed_grading_period?(override.due_at)
|
|
apply_error(override, :due_at, ERROR_MESSAGES[:change_override_due_at_to_closed], false)
|
|
return false
|
|
end
|
|
|
|
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)
|
|
submittable.due_at_was.to_i != submittable.due_at.to_i
|
|
end
|
|
|
|
def apply_grading_params(submittable, submittable_params)
|
|
case submittable
|
|
when Quizzes::Quiz
|
|
submittable.quiz_type = submittable_params[:quiz_type]
|
|
when Assignment
|
|
submittable.submission_types = submittable_params[:submission_types]
|
|
end
|
|
end
|
|
|
|
def can_create_overrides?(submittable, overrides, flash_message: false)
|
|
# Known Issue: This method explicitly does not handle the case where
|
|
# creating an override would cause a student to assume a due date in an
|
|
# open grading period when previously in a closed grading period.
|
|
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)
|
|
false
|
|
end
|
|
|
|
def can_update_overrides?(submittable, overrides, flash_message: false)
|
|
changed_overrides = overrides.reject { |override| override.due_at_was.to_i == override.due_at.to_i }
|
|
return true if changed_overrides.empty?
|
|
|
|
if changed_overrides.any? { |override| date_in_closed_grading_period?(override.due_at_was) }
|
|
apply_error(submittable, :due_at, ERROR_MESSAGES[:change_override_due_at_in_closed], flash_message)
|
|
return false
|
|
end
|
|
|
|
return true unless changed_overrides.any? { |override| date_in_closed_grading_period?(override.due_at) }
|
|
|
|
apply_error(submittable, :due_at, ERROR_MESSAGES[:change_override_due_at_to_closed], flash_message)
|
|
false
|
|
end
|
|
|
|
def can_delete_overrides?(submittable, overrides, flash_message: false)
|
|
# Known Issue: This method explicitly does not handle the case where
|
|
# deleting an override would cause a student to assume a due date in a
|
|
# closed grading period when previously in an open grading period.
|
|
return true unless overrides.any? { |override| date_in_closed_grading_period?(override.due_at) }
|
|
|
|
apply_error(submittable, :due_at, ERROR_MESSAGES[:delete_override_in_closed], flash_message)
|
|
false
|
|
end
|
|
|
|
def current_user_is_context_admin?
|
|
if @current_user_is_context_admin.nil?
|
|
@current_user_is_context_admin = @context.account_membership_allows(@current_user)
|
|
end
|
|
@current_user_is_context_admin
|
|
end
|
|
|
|
def context_grading_periods
|
|
@context_grading_periods ||= GradingPeriod.for(@context)
|
|
end
|
|
|
|
def apply_error(submittable, attribute, message, flash_message)
|
|
submittable.errors.add(attribute, message)
|
|
flash[:error] = message if flash_message
|
|
end
|
|
|
|
ERROR_MESSAGES = {
|
|
set_due_at_in_closed: I18n.t("Cannot set the due date to a date within a closed grading period"),
|
|
change_due_at_in_closed: I18n.t("Cannot change the due date when due in a closed grading period"),
|
|
change_due_at_to_closed: I18n.t("Cannot change the due date to a date within a closed grading period"),
|
|
set_override_due_at_in_closed: I18n.t("Cannot set override due date to a date within a closed grading period"),
|
|
change_override_due_at_in_closed: I18n.t("Cannot change the due date of an override in a closed grading period"),
|
|
change_override_due_at_to_closed: I18n.t("Cannot change an override due date to a date within a closed grading period"),
|
|
delete_override_in_closed: I18n.t("Cannot delete an override with a due date within a closed grading period"),
|
|
change_only_visible_to_overrides: I18n.t("Cannot set only visible to overrides when due in a closed grading period")
|
|
}.freeze
|
|
end
|