diff --git a/app/helpers/assignments_helper.rb b/app/helpers/assignments_helper.rb index 1a217e9080d..3a4a99da8bc 100644 --- a/app/helpers/assignments_helper.rb +++ b/app/helpers/assignments_helper.rb @@ -65,7 +65,13 @@ module AssignmentsHelper if assignment.expects_submission? && can_do(assignment, user, :submit) submit_text = user_submission.try(:has_submission?) ? I18n.t("Re-submit Assignment") : I18n.t("Submit Assignment") late = user_submission.try(:late?) ? "late" : "" - link_to(submit_text, '#', :role => "button", :class => "Button Button--primary submit_assignment_link #{late}") + link_to( + submit_text, + '#', + :role => "button", + :class => "Button Button--primary submit_assignment_link #{late}", + :disabled => user_submission && user_submission.attempts_left == 0, + ) end end diff --git a/app/models/submission.rb b/app/models/submission.rb index 4525c679ebf..caa032cb050 100644 --- a/app/models/submission.rb +++ b/app/models/submission.rb @@ -58,6 +58,8 @@ class Submission < ActiveRecord::Base }.freeze }.freeze + SUBMISSION_TYPES_GOVERNED_BY_ALLOWED_ATTEMPTS = %w[online_upload online_url online_text_entry].freeze + attr_readonly :assignment_id attr_accessor :visible_to_user, :skip_grade_calc, @@ -119,6 +121,7 @@ class Submission < ActiveRecord::Base validates :late_policy_status, inclusion: ['none', 'missing', 'late'], allow_nil: true validate :ensure_grader_can_grade validate :extra_attempts_can_only_be_set_on_online_uploads + validate :ensure_attempts_are_in_range scope :active, -> { where("submissions.workflow_state <> 'deleted'") } scope :for_enrollments, -> (enrollments) { where(user_id: enrollments.select(:user_id)) } @@ -1518,14 +1521,26 @@ class Submission < ActiveRecord::Base def extra_attempts_can_only_be_set_on_online_uploads return true unless changes.key?("extra_attempts") && assignment - allowed_submission_types = %w[online_upload online_url online_text_entry] - return true if (assignment.submission_types.split(",") & allowed_submission_types).any? + return true if (assignment.submission_types.split(",") & SUBMISSION_TYPES_GOVERNED_BY_ALLOWED_ATTEMPTS).any? - error_msg = 'extra_attempts can only be set on submissions for an assignment with a type of online_upload, online_url, or online_text_entry' + error_msg = 'can only be set on submissions for an assignment with a type of online_upload, online_url, or online_text_entry' errors.add(:extra_attempts, error_msg) false end + def attempts_left + return nil if self.assignment.allowed_attempts.nil? || self.assignment.allowed_attempts < 0 + [0, self.assignment.allowed_attempts + (self.extra_attempts || 0) - (self.attempt || 0)].max + end + + def ensure_attempts_are_in_range + return true unless changes.key?("submitted_at") && assignment + return true unless (assignment.submission_types.split(",") & SUBMISSION_TYPES_GOVERNED_BY_ALLOWED_ATTEMPTS).any? + return true if attempts_left.nil? || attempts_left > 0 + errors.add(:attempt, 'you have reached the maximum number of allowed attempts for this assignment') + false + end + def can_autograde? result = GRADE_STATUS_MESSAGES_MAP[can_autograde_symbolic_status] result ||= { status: false, message: I18n.t('Cannot autograde at this time') } diff --git a/app/stylesheets/bundles/submission.scss b/app/stylesheets/bundles/submission.scss index 5367adbc0bc..aa75458ac9c 100644 --- a/app/stylesheets/bundles/submission.scss +++ b/app/stylesheets/bundles/submission.scss @@ -62,6 +62,15 @@ } .submission-details-header__info { margin-top: $ic-sp / 3; + display: flex; + + .submission-details-header__attempts_info { + margin: 0px 0px 0px 40px; + + > span { + margin: 0px 20px 0px 0px; + } + } } .submission-details-header__time { margin-#{direction(right)}: $ic-sp / 4; diff --git a/app/stylesheets/pages/assignments/_assignments.scss b/app/stylesheets/pages/assignments/_assignments.scss index f92e1ae0a59..3b1daca3421 100644 --- a/app/stylesheets/pages/assignments/_assignments.scss +++ b/app/stylesheets/pages/assignments/_assignments.scss @@ -139,7 +139,7 @@ padding-#{direction(right)}: 0.5em; } .value { - padding-#{direction(right)}: 2.5em; + padding-#{direction(right)}: 2.0em; } } .form-horizontal.display-only .control-group { diff --git a/app/views/assignments/show.html.erb b/app/views/assignments/show.html.erb index a802a6f3a97..d18a9c770d5 100644 --- a/app/views/assignments/show.html.erb +++ b/app/views/assignments/show.html.erb @@ -151,6 +151,16 @@ <% end %> <% end %> + <% if @assignment.allowed_attempts&.> 0 %> +