Refactor speed_grader/assignment.rb
Remove ivars for better flexibility and rework specs for clarity and maintainability. This work was extracted out of a forthcoming patchset. Refs: GRADE-2245 Test Plan: - specs pass Change-Id: Ide53a2473f2146c1c2410efedb58287e140b0486 Reviewed-on: https://gerrit.instructure.com/198927 Tested-by: Jenkins QA-Review: Derek Bender <djbender@instructure.com> Product-Review: Derek Bender <djbender@instructure.com> Reviewed-by: Adrian Packel <apackel@instructure.com> Reviewed-by: Keith Garner <kgarner@instructure.com>
This commit is contained in:
parent
3664d5ddea
commit
19a0d49b02
|
@ -26,12 +26,9 @@ module SpeedGrader
|
|||
|
||||
def initialize(assignment, current_user, avatars: false, grading_role: :grader)
|
||||
@assignment = assignment
|
||||
@course = @assignment.context
|
||||
@avatars = avatars
|
||||
@current_user = current_user
|
||||
@display_avatars = avatars && !@assignment.grade_as_group?
|
||||
@grading_role = grading_role
|
||||
account_context = @course.try(:account) || @course.try(:root_account)
|
||||
@should_migrate_to_canvadocs = account_context.present? && account_context.migrate_to_canvadocs?
|
||||
end
|
||||
|
||||
def json
|
||||
|
@ -41,28 +38,28 @@ module SpeedGrader
|
|||
submission_type score points_deducted assignment_id submission_comments
|
||||
grading_period_id excused updated_at)
|
||||
|
||||
submission_json_fields << (anonymous_students?(current_user: @current_user, assignment: @assignment) ? :anonymous_id : :user_id)
|
||||
submission_json_fields << :posted_at if @course.post_policies_enabled?
|
||||
submission_json_fields << (anonymous_students?(current_user: current_user, assignment: assignment) ? :anonymous_id : :user_id)
|
||||
submission_json_fields << :posted_at if course.post_policies_enabled?
|
||||
|
||||
attachment_json_fields = %i(id comment_id content_type context_id context_type display_name
|
||||
filename mime_class size submitter_id workflow_state)
|
||||
|
||||
if !@assignment.anonymize_students? || @course.account_membership_allows(@current_user)
|
||||
if !assignment.anonymize_students? || course.account_membership_allows(current_user)
|
||||
attachment_json_fields << :viewed_at
|
||||
end
|
||||
|
||||
enrollment_json_fields = %i(course_section_id workflow_state user_id)
|
||||
|
||||
res = @assignment.as_json(
|
||||
res = assignment.as_json(
|
||||
:include => {
|
||||
:context => { :only => :id },
|
||||
:rubric_association => { :except => {} }
|
||||
},
|
||||
:include_root => false
|
||||
)
|
||||
res['anonymize_students'] = @assignment.anonymize_students?
|
||||
res['anonymize_graders'] = !@assignment.can_view_other_grader_identities?(@current_user)
|
||||
res['post_manually'] = @assignment.post_manually? if @course.post_policies_enabled?
|
||||
res['anonymize_students'] = assignment.anonymize_students?
|
||||
res['anonymize_graders'] = !assignment.can_view_other_grader_identities?(current_user)
|
||||
res['post_manually'] = assignment.post_manually? if course.post_policies_enabled?
|
||||
|
||||
# include :provisional here someday if we need to distinguish
|
||||
# between provisional and real comments (also in
|
||||
|
@ -75,94 +72,99 @@ module SpeedGrader
|
|||
# If we're working with anonymous IDs, skip students who don't have a
|
||||
# valid submission object, which means no inactive or concluded students
|
||||
# even if the user has elected to show them in gradebook
|
||||
includes = @assignment.anonymize_students? ? [] : gradebook_includes(user: @current_user, course: @course)
|
||||
@students = @assignment.representatives(@current_user, includes: includes) do |rep, others|
|
||||
includes = assignment.anonymize_students? ? [] : gradebook_includes(user: current_user, course: course)
|
||||
students = assignment.representatives(current_user, includes: includes) do |rep, others|
|
||||
others.each { |s| res[:context][:rep_for_student][s.id] = rep.id }
|
||||
end
|
||||
|
||||
# Ensure that any test students are sorted last
|
||||
@students = @students.partition { |r| r.preferences[:fake_student] != true }.flatten
|
||||
students = students.partition { |r| r.preferences[:fake_student] != true }.flatten
|
||||
|
||||
enrollments = @course.apply_enrollment_visibility(
|
||||
gradebook_enrollment_scope(user: @current_user, course: @course),
|
||||
@current_user,
|
||||
enrollments = course.apply_enrollment_visibility(
|
||||
gradebook_enrollment_scope(user: current_user, course: course),
|
||||
current_user,
|
||||
nil,
|
||||
include: includes
|
||||
)
|
||||
|
||||
current_user_rubric_assessments = @assignment.visible_rubric_assessments_for(@current_user, provisional_grader: provisional_grader_or_moderator?) || []
|
||||
current_user_rubric_assessments = assignment.visible_rubric_assessments_for(current_user, provisional_grader: provisional_grader_or_moderator?) || []
|
||||
|
||||
# include all the rubric assessments if a moderator
|
||||
all_provisional_rubric_assessments =
|
||||
@grading_role == :moderator ? @assignment.visible_rubric_assessments_for(@current_user, :provisional_moderator => true) : []
|
||||
grading_role == :moderator ? assignment.visible_rubric_assessments_for(current_user, :provisional_moderator => true) : []
|
||||
|
||||
ActiveRecord::Associations::Preloader.new.preload(@assignment, :moderated_grading_selections) if provisional_grader_or_moderator?
|
||||
ActiveRecord::Associations::Preloader.new.preload(assignment, :moderated_grading_selections) if provisional_grader_or_moderator?
|
||||
|
||||
includes = [{ versions: :versionable }, :quiz_submission, :user, :attachment_associations, :assignment, :originality_reports]
|
||||
includes << {all_submission_comments: {submission: {assignment: { context: :root_account }}}}
|
||||
@submissions = @assignment.submissions.where(:user_id => @students).preload(*includes)
|
||||
submissions = assignment.submissions.where(user_id: students).preload(*includes)
|
||||
|
||||
student_json_fields = anonymous_students?(current_user: @current_user, assignment: @assignment) ? [] : %i(name id sortable_name)
|
||||
student_json_fields = anonymous_students?(current_user: current_user, assignment: assignment) ? [] : %i(name id sortable_name)
|
||||
|
||||
res[:context][:students] = @students.map do |student|
|
||||
res[:context][:students] = students.map do |student|
|
||||
json = student.as_json(include_root: false, methods: submission_comment_methods, only: student_json_fields)
|
||||
if anonymous_students?(current_user: @current_user, assignment: @assignment)
|
||||
anonymous_ids = student_ids_to_anonymous_ids(current_user: @current_user, assignment: @assignment, course: @course, submissions: @submissions)
|
||||
if anonymous_students?(current_user: current_user, assignment: assignment)
|
||||
anonymous_ids = student_ids_to_anonymous_ids(current_user: current_user, assignment: assignment, course: course, submissions: submissions)
|
||||
json[:anonymous_id] = anonymous_ids[student.id.to_s]
|
||||
end
|
||||
json[:needs_provisional_grade] = @assignment.can_be_moderated_grader?(@current_user) if provisional_grader_or_moderator?
|
||||
json[:rubric_assessments] = rubric_assessments_to_json(current_user_rubric_assessments.select {|assessment| assessment.user_id == student.id})
|
||||
json[:needs_provisional_grade] = assignment.can_be_moderated_grader?(current_user) if provisional_grader_or_moderator?
|
||||
json[:rubric_assessments] = rubric_assessments_to_json(
|
||||
rubric_assessments: current_user_rubric_assessments.select do |assessment|
|
||||
assessment.user_id == student.id
|
||||
end,
|
||||
submissions: submissions
|
||||
)
|
||||
json
|
||||
end
|
||||
|
||||
res[:context][:active_course_sections] = @assignment.context.
|
||||
sections_visible_to(@current_user, @assignment.sections_with_visibility(@current_user)).
|
||||
res[:context][:active_course_sections] = assignment.context.
|
||||
sections_visible_to(current_user, assignment.sections_with_visibility(current_user)).
|
||||
map { |section| section.as_json(include_root: false, only: [:id, :name]) }
|
||||
|
||||
res[:context][:enrollments] = enrollments.map do |enrollment|
|
||||
enrollment_json = enrollment.as_json(include_root: false, only: enrollment_json_fields)
|
||||
if anonymous_students?(current_user: @current_user, assignment: @assignment)
|
||||
if anonymous_students?(current_user: current_user, assignment: assignment)
|
||||
enrollment_json[:anonymous_id] = student_ids_to_anonymous_ids(
|
||||
current_user: @current_user,
|
||||
assignment: @assignment,
|
||||
course: @course,
|
||||
submissions: @submissions
|
||||
current_user: current_user,
|
||||
assignment: assignment,
|
||||
course: course,
|
||||
submissions: submissions
|
||||
).fetch(enrollment.user_id.to_s, nil)
|
||||
enrollment_json.delete(:user_id)
|
||||
end
|
||||
enrollment_json
|
||||
end
|
||||
res[:context][:quiz] = @assignment.quiz.as_json(:include_root => false, :only => [:anonymous_submissions])
|
||||
res[:context][:quiz] = assignment.quiz.as_json(:include_root => false, :only => [:anonymous_submissions])
|
||||
|
||||
attachment_includes = %i(crocodoc_document canvadoc root_attachment)
|
||||
# Preload attachments for later looping
|
||||
attachments_for_submission =
|
||||
::Submission.bulk_load_attachments_for_submissions(@submissions, preloads: attachment_includes)
|
||||
::Submission.bulk_load_attachments_for_submissions(submissions, preloads: attachment_includes)
|
||||
|
||||
# Preloading submission history versioned attachments and originality reports
|
||||
submission_histories = @submissions.map(&:submission_history).flatten
|
||||
submission_histories = submissions.map(&:submission_history).flatten
|
||||
::Submission.bulk_load_versioned_attachments(submission_histories,
|
||||
preloads: attachment_includes)
|
||||
::Submission.bulk_load_versioned_originality_reports(submission_histories)
|
||||
::Submission.bulk_load_text_entry_originality_reports(submission_histories)
|
||||
|
||||
preloaded_provisional_selections =
|
||||
@grading_role == :moderator ? @assignment.moderated_grading_selections.index_by(&:student_id) : {}
|
||||
grading_role == :moderator ? assignment.moderated_grading_selections.index_by(&:student_id) : {}
|
||||
|
||||
res[:too_many_quiz_submissions] = too_many = @assignment.too_many_qs_versions?(@submissions)
|
||||
qs_versions = @assignment.quiz_submission_versions(@submissions, too_many)
|
||||
res[:too_many_quiz_submissions] = too_many = assignment.too_many_qs_versions?(submissions)
|
||||
qs_versions = assignment.quiz_submission_versions(submissions, too_many)
|
||||
|
||||
enrollment_types_by_id = enrollments.inject({}){ |h, e| h[e.user_id] ||= e.type; h }
|
||||
|
||||
if @assignment.quiz
|
||||
if @assignment.quiz.assignment_overrides.to_a.select(&:active?).count == 0
|
||||
@assignment.quiz.has_no_overrides = true
|
||||
if assignment.quiz
|
||||
if assignment.quiz.assignment_overrides.to_a.select(&:active?).count == 0
|
||||
assignment.quiz.has_no_overrides = true
|
||||
else
|
||||
@assignment.quiz.context.preload_user_roles!
|
||||
assignment.quiz.context.preload_user_roles!
|
||||
end
|
||||
end
|
||||
|
||||
res[:submissions] = @submissions.map do |sub|
|
||||
res[:submissions] = submissions.map do |sub|
|
||||
json = sub.as_json(
|
||||
include_root: false,
|
||||
methods: %i(submission_history late external_tool_url entered_score entered_grade),
|
||||
|
@ -170,17 +172,17 @@ module SpeedGrader
|
|||
).merge("from_enrollment_type" => enrollment_types_by_id[sub.user_id])
|
||||
|
||||
if provisional_grader_or_moderator?
|
||||
provisional_grade = sub.provisional_grade(@current_user, preloaded_grades: preloaded_provisional_grades)
|
||||
provisional_grade = sub.provisional_grade(current_user, preloaded_grades: preloaded_provisional_grades)
|
||||
json.merge! provisional_grade_to_json(provisional_grade)
|
||||
end
|
||||
|
||||
json[:submission_comments] = anonymous_moderated_submission_comments_json(
|
||||
assignment: @assignment,
|
||||
course: @course,
|
||||
current_user: @current_user,
|
||||
assignment: assignment,
|
||||
course: course,
|
||||
current_user: current_user,
|
||||
avatars: display_avatars?,
|
||||
submission_comments: sub.visible_submission_comments_for(@current_user),
|
||||
submissions: @submissions
|
||||
submission_comments: sub.visible_submission_comments_for(current_user),
|
||||
submissions: submissions
|
||||
)
|
||||
|
||||
# We get the attachments this way to avoid loading the
|
||||
|
@ -192,23 +194,23 @@ module SpeedGrader
|
|||
|
||||
sub_attachments = []
|
||||
url_opts = {
|
||||
anonymous_instructor_annotations: @assignment.anonymous_instructor_annotations,
|
||||
enable_annotations: !provisional_grader_or_moderator? || @assignment.can_be_moderated_grader?(@current_user),
|
||||
anonymous_instructor_annotations: assignment.anonymous_instructor_annotations,
|
||||
enable_annotations: !provisional_grader_or_moderator? || assignment.can_be_moderated_grader?(current_user),
|
||||
moderated_grading_whitelist: sub.moderated_grading_whitelist(
|
||||
@current_user,
|
||||
current_user,
|
||||
loaded_attachments: attachments_for_submission[sub]
|
||||
),
|
||||
submission_id: sub.id
|
||||
}
|
||||
|
||||
if url_opts[:enable_annotations]
|
||||
url_opts[:enrollment_type] = canvadocs_user_role(@course, @current_user)
|
||||
url_opts[:enrollment_type] = canvadocs_user_role(course, current_user)
|
||||
end
|
||||
|
||||
if quizzes_next_submission?
|
||||
quiz_lti_submission = BasicLTI::QuizzesNextVersionedSubmission.new(@assignment, sub.user)
|
||||
quiz_lti_submission = BasicLTI::QuizzesNextVersionedSubmission.new(assignment, sub.user)
|
||||
json['submission_history'] = quiz_lti_submission.grade_history.map { |submission| { submission: submission } }
|
||||
elsif json['submission_history'] && (@assignment.quiz.nil? || too_many)
|
||||
elsif json['submission_history'] && (assignment.quiz.nil? || too_many)
|
||||
json['submission_history'] = json['submission_history'].map do |version|
|
||||
# to avoid a call to the DB in Submission#missing?
|
||||
version.assignment = sub.assignment
|
||||
|
@ -221,7 +223,7 @@ module SpeedGrader
|
|||
|
||||
# Fill in the parent's anonymous ID if this version was serialized
|
||||
# without it
|
||||
if @assignment.anonymize_students? && version_json['submission']['anonymous_id'].blank?
|
||||
if assignment.anonymize_students? && version_json['submission']['anonymous_id'].blank?
|
||||
version_json['submission']['anonymous_id'] = sub.anonymous_id
|
||||
end
|
||||
|
||||
|
@ -233,23 +235,23 @@ module SpeedGrader
|
|||
if version_json['submission'][:submission_type] == 'discussion_topic'
|
||||
url_opts[:enable_annotations] = false
|
||||
end
|
||||
if @grading_role == :moderator
|
||||
if grading_role == :moderator
|
||||
# we'll use to create custom crocodoc urls for each prov grade
|
||||
sub_attachments << a
|
||||
end
|
||||
a.as_json(only: attachment_json_fields).tap do |json|
|
||||
json[:attachment][:view_inline_ping_url] = assignment_file_inline_view_path(@assignment.id, a.id)
|
||||
json[:attachment][:canvadoc_url] = a.canvadoc_url(@current_user, url_opts)
|
||||
json[:attachment][:crocodoc_url] = a.crocodoc_url(@current_user, url_opts)
|
||||
json[:attachment][:view_inline_ping_url] = assignment_file_inline_view_path(assignment.id, a.id)
|
||||
json[:attachment][:canvadoc_url] = a.canvadoc_url(current_user, url_opts)
|
||||
json[:attachment][:crocodoc_url] = a.crocodoc_url(current_user, url_opts)
|
||||
json[:attachment][:submitted_to_crocodoc] = a.crocodoc_document.present?
|
||||
json[:attachment][:hijack_crocodoc_session] = a.crocodoc_document.present? && @should_migrate_to_canvadocs
|
||||
json[:attachment][:hijack_crocodoc_session] = a.crocodoc_document.present? && migrate_to_canvadocs?
|
||||
json[:attachment][:upload_status] = AttachmentUploadStatus.upload_status(a)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elsif @assignment.quiz && sub.quiz_submission
|
||||
elsif assignment.quiz && sub.quiz_submission
|
||||
json['submission_history'] = qs_versions[sub.quiz_submission.id].map do |v|
|
||||
# don't use v.model, because these are huge objects, and can be significantly expensive
|
||||
# to instantiate an actual AR object deserializing and reserializing the inner YAML
|
||||
|
@ -263,7 +265,7 @@ module SpeedGrader
|
|||
id: sub.id,
|
||||
show_grade_in_dropdown: true,
|
||||
submitted_at: qs['finished_at'],
|
||||
late: Quizzes::QuizSubmission.late_from_attributes?(qs, @assignment.quiz, sub),
|
||||
late: Quizzes::QuizSubmission.late_from_attributes?(qs, assignment.quiz, sub),
|
||||
version: v.number,
|
||||
}}
|
||||
end
|
||||
|
@ -272,17 +274,19 @@ module SpeedGrader
|
|||
if provisional_grader_or_moderator?
|
||||
pgs = preloaded_provisional_grades[sub.id] || []
|
||||
selection = preloaded_provisional_selections[sub.user.id]
|
||||
unless pgs.count == 0 || (pgs.count == 1 && pgs.first.scorer_id == @current_user.id)
|
||||
unless pgs.count == 0 || (pgs.count == 1 && pgs.first.scorer_id == current_user.id)
|
||||
json['provisional_grades'] = []
|
||||
pgs.each do |pg|
|
||||
current_pg_json = provisional_grade_to_json(pg).tap do |pg_json|
|
||||
assessments = all_provisional_rubric_assessments.select {|assessment| assessment.artifact_id == pg.id}
|
||||
pg_json[:rubric_assessments] = rubric_assessments_to_json(assessments)
|
||||
|
||||
rubric_assessments = all_provisional_rubric_assessments.select {|assessment| assessment.artifact_id == pg.id}
|
||||
pg_json[:rubric_assessments] = rubric_assessments_to_json(
|
||||
rubric_assessments: rubric_assessments,
|
||||
submissions: submissions
|
||||
)
|
||||
pg_json[:selected] = !!(selection && selection.selected_provisional_grade_id == pg.id)
|
||||
# this should really be provisional_doc_view_urls :: https://instructure.atlassian.net/browse/CNVS-38202
|
||||
pg_json[:crocodoc_urls] = sub_attachments.map { |a| pg.attachment_info(@current_user, a) }
|
||||
pg_json[:readonly] = !pg.final && (pg.scorer_id != @current_user.id)
|
||||
pg_json[:crocodoc_urls] = sub_attachments.map { |a| pg.attachment_info(current_user, a) }
|
||||
pg_json[:readonly] = !pg.final && (pg.scorer_id != current_user.id)
|
||||
end
|
||||
|
||||
if pg.final
|
||||
|
@ -297,31 +301,31 @@ module SpeedGrader
|
|||
json
|
||||
end
|
||||
|
||||
res[:GROUP_GRADING_MODE] = @assignment.grade_as_group?
|
||||
res[:GROUP_GRADING_MODE] = assignment.grade_as_group?
|
||||
StringifyIds.recursively_stringify_ids(res)
|
||||
ensure
|
||||
Attachment.skip_thumbnails = nil
|
||||
end
|
||||
|
||||
def quizzes_next_submission?
|
||||
@assignment.quiz_lti? && @assignment.root_account.feature_enabled?(:quizzes_next_submission_history)
|
||||
assignment.quiz_lti? && assignment.root_account.feature_enabled?(:quizzes_next_submission_history)
|
||||
end
|
||||
|
||||
def preloaded_provisional_grades
|
||||
@preloaded_provisional_grades ||= begin
|
||||
provisional_grades = @assignment.provisional_grades
|
||||
unless anonymous_graders?(current_user: @current_user, assignment: @assignment)
|
||||
provisional_grades = assignment.provisional_grades
|
||||
unless anonymous_graders?(current_user: current_user, assignment: assignment)
|
||||
provisional_grades = provisional_grades.preload(:scorer)
|
||||
end
|
||||
|
||||
if @grading_role == :provisional_grader
|
||||
provisional_grades = if grader_comments_hidden?(current_user: @current_user, assignment: @assignment)
|
||||
provisional_grades.not_final.where(scorer: @current_user)
|
||||
if grading_role == :provisional_grader
|
||||
provisional_grades = if grader_comments_hidden?(current_user: current_user, assignment: assignment)
|
||||
provisional_grades.not_final.where(scorer: current_user)
|
||||
else
|
||||
select_fields = ModeratedGrading::GRADE_ATTRIBUTES_ONLY.dup.push(:id, :submission_id)
|
||||
provisional_grades.select(select_fields)
|
||||
end
|
||||
elsif @grading_role == :grader
|
||||
elsif grading_role == :grader
|
||||
provisional_grades = ModeratedGrading::ProvisionalGrade.none
|
||||
end
|
||||
provisional_grades.order(:id).to_a.group_by(&:submission_id)
|
||||
|
@ -330,27 +334,38 @@ module SpeedGrader
|
|||
|
||||
private
|
||||
|
||||
def rubric_assessments_to_json(rubric_assessments)
|
||||
attr_reader :assignment, :avatars, :current_user, :grading_role
|
||||
|
||||
def course
|
||||
assignment.context
|
||||
end
|
||||
|
||||
def migrate_to_canvadocs?
|
||||
account_context = course.try(:account) || course.try(:root_account)
|
||||
account_context.present? && account_context.migrate_to_canvadocs?
|
||||
end
|
||||
|
||||
def rubric_assessments_to_json(rubric_assessments:, submissions:)
|
||||
rubric_assessments.map do |assessment|
|
||||
json = assessment.as_json(methods: [:assessor_name], include_root: false)
|
||||
assessor_id = json[:assessor_id]
|
||||
|
||||
if anonymous_graders?(current_user: @current_user, assignment: @assignment)
|
||||
if anonymous_graders?(current_user: current_user, assignment: assignment)
|
||||
json.delete(:assessor_id)
|
||||
json[:anonymous_assessor_id] = @assignment.grader_ids_to_anonymous_ids[assessor_id.to_s]
|
||||
json.delete(:assessor_name) unless assessor_id == @current_user.id
|
||||
json[:anonymous_assessor_id] = assignment.grader_ids_to_anonymous_ids[assessor_id.to_s]
|
||||
json.delete(:assessor_name) unless assessor_id == current_user.id
|
||||
end
|
||||
|
||||
if anonymous_students?(current_user: @current_user, assignment: @assignment)
|
||||
if anonymous_students?(current_user: current_user, assignment: assignment)
|
||||
json[:anonymous_user_id] = student_ids_to_anonymous_ids(
|
||||
current_user: @current_user,
|
||||
assignment: @assignment,
|
||||
course: @course,
|
||||
submissions: @submissions
|
||||
current_user: current_user,
|
||||
assignment: assignment,
|
||||
course: course,
|
||||
submissions: submissions
|
||||
).fetch(json.delete(:user_id).to_s)
|
||||
end
|
||||
|
||||
if grader_comments_hidden_or_other_grader?(assessor_id)
|
||||
if grader_comments_hidden_or_other_grader?(assessor_id: assessor_id, submissions: submissions)
|
||||
json['data'].each do |datum|
|
||||
datum.delete(:comments)
|
||||
datum.delete(:comments_html)
|
||||
|
@ -363,8 +378,8 @@ module SpeedGrader
|
|||
|
||||
def provisional_grade_to_json(provisional_grade)
|
||||
provisional_grade.grade_attributes.tap do |json|
|
||||
if anonymous_graders?(current_user: @current_user, assignment: @assignment)
|
||||
json[:anonymous_grader_id] = @assignment.grader_ids_to_anonymous_ids[json.delete(:scorer_id).to_s]
|
||||
if anonymous_graders?(current_user: current_user, assignment: assignment)
|
||||
json[:anonymous_grader_id] = assignment.grader_ids_to_anonymous_ids[json.delete(:scorer_id).to_s]
|
||||
else
|
||||
json[:scorer_name] = provisional_grade.scorer&.name
|
||||
end
|
||||
|
@ -372,21 +387,21 @@ module SpeedGrader
|
|||
end
|
||||
|
||||
def provisional_grader_or_moderator?
|
||||
@grading_role == :provisional_grader || @grading_role == :moderator
|
||||
grading_role == :provisional_grader || grading_role == :moderator
|
||||
end
|
||||
|
||||
def display_avatars?
|
||||
@display_avatars
|
||||
avatars && !assignment.grade_as_group?
|
||||
end
|
||||
|
||||
def grader_comments_hidden_or_other_grader?(assessor_id)
|
||||
grader_comments_hidden?(current_user: @current_user, assignment: @assignment) &&
|
||||
def grader_comments_hidden_or_other_grader?(assessor_id:, submissions:)
|
||||
grader_comments_hidden?(current_user: current_user, assignment: assignment) &&
|
||||
other_grader?(
|
||||
user_id: assessor_id,
|
||||
current_user: @current_user,
|
||||
course: @course,
|
||||
assignment: @assignment,
|
||||
submissions: @submissions
|
||||
current_user: current_user,
|
||||
course: course,
|
||||
assignment: assignment,
|
||||
submissions: submissions
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,7 +39,7 @@ describe SpeedGrader::Assignment do
|
|||
end
|
||||
|
||||
context "add students to the group" do
|
||||
let(:category) { @course.group_categories.create! name: "Assignment Groups" }
|
||||
let(:category) { @course.group_categories.create! name: "Group Set" }
|
||||
let(:assignment) do
|
||||
@course.assignments.create!(
|
||||
group_category_id: category.id,
|
||||
|
@ -544,156 +544,159 @@ describe SpeedGrader::Assignment do
|
|||
|
||||
context "group assignments" do
|
||||
before :once do
|
||||
course_with_teacher(active_all: true)
|
||||
@gc = @course.group_categories.create! name: "Assignment Groups"
|
||||
@groups = [1, 2].map { |i| @gc.groups.create! name: "Group #{i}", context: @course }
|
||||
@teacher = course_with_teacher(active_all: true).user
|
||||
@group_category = @course.group_categories.create!(name: 'Group Set')
|
||||
@first_group = @group_category.groups.create!(name: 'Group 1', context: @course)
|
||||
@second_group = @group_category.groups.create!(name: 'Group 2', context: @course)
|
||||
@groups = [@first_group, @second_group]
|
||||
students = create_users_in_course(@course, 6, return_type: :record)
|
||||
students.each_with_index { |s, i| @groups[i % @groups.size].add_user(s) }
|
||||
@assignment = @course.assignments.create!(
|
||||
group_category_id: @gc.id,
|
||||
grade_group_students_individually: false,
|
||||
submission_types: %w(text_entry)
|
||||
)
|
||||
students.each_with_index do |student, index|
|
||||
@groups.fetch(index % @groups.size).add_user(student)
|
||||
end
|
||||
end
|
||||
|
||||
it "is not in group mode for non-group assignments" do
|
||||
assignment_model(course: @course)
|
||||
@assignment.submit_homework(@user, {submission_type: 'online_text_entry', body: 'blah'})
|
||||
json = SpeedGrader::Assignment.new(@assignment, @teacher).json
|
||||
expect(json["GROUP_GRADING_MODE"]).not_to be_truthy
|
||||
assignment = @course.assignments.create!
|
||||
assignment.submit_homework(@student, {submission_type: 'online_text_entry', body: 'blah'})
|
||||
json = SpeedGrader::Assignment.new(assignment, @teacher).json
|
||||
expect(json["GROUP_GRADING_MODE"]).to be false
|
||||
end
|
||||
|
||||
it "sorts student view students last" do
|
||||
test_student = @course.student_view_student
|
||||
json = SpeedGrader::Assignment.new(@assignment, @teacher).json
|
||||
expect(json[:context][:students].last[:id]).to eq(test_student.id.to_s)
|
||||
end
|
||||
|
||||
it 'returns "groups" instead of students' do
|
||||
json = SpeedGrader::Assignment.new(@assignment, @teacher).json
|
||||
@groups.each do |group|
|
||||
j = json["context"]["students"].find { |g| g["name"] == group.name }
|
||||
expect(group.users.map { |u| u.id.to_s }).to include j["id"]
|
||||
end
|
||||
expect(json["GROUP_GRADING_MODE"]).to be_truthy
|
||||
end
|
||||
|
||||
it 'chooses the student with turnitin data to represent' do
|
||||
turnitin_submissions = @groups.map do |group|
|
||||
rep = group.users.sample
|
||||
turnitin_submission = @assignment.grade_student(rep, grade: 10, grader: @teacher)[0]
|
||||
turnitin_submission.update_attribute :turnitin_data, {blah: 1}
|
||||
turnitin_submission
|
||||
context 'given a group assignment' do
|
||||
before(:once) do
|
||||
@assignment = @course.assignments.create!(
|
||||
group_category_id: @group_category.id,
|
||||
grade_group_students_individually: false,
|
||||
submission_types: %w(text_entry)
|
||||
)
|
||||
end
|
||||
|
||||
@assignment.update_attribute :turnitin_enabled, true
|
||||
json = SpeedGrader::Assignment.new(@assignment, @teacher).json
|
||||
|
||||
expect(json["submissions"].map do |s|
|
||||
s["id"]
|
||||
end.sort).to eq turnitin_submissions.map { |t| t.id.to_s }.sort
|
||||
end
|
||||
|
||||
it 'prefers people with submissions' do
|
||||
g1, = @groups
|
||||
@assignment.grade_student(g1.users.first, score: 10, grader: @teacher)
|
||||
g1rep = g1.users.sample
|
||||
s = @assignment.submission_for_student(g1rep)
|
||||
s.update_attribute :submission_type, 'online_upload'
|
||||
expect(@assignment.representatives(@teacher)).to include g1rep
|
||||
end
|
||||
|
||||
it "prefers people who aren't excused when submission exists" do
|
||||
g1, = @groups
|
||||
g1rep, *others = g1.users.to_a.shuffle
|
||||
@assignment.submit_homework(g1rep, {
|
||||
submission_type: 'online_text_entry',
|
||||
body: 'hi'
|
||||
})
|
||||
others.each do |u|
|
||||
@assignment.grade_student(u, excuse: true, grader: @teacher)
|
||||
it "sorts student view students last" do
|
||||
test_student = @course.student_view_student
|
||||
json = SpeedGrader::Assignment.new(@assignment, @teacher).json
|
||||
expect(json[:context][:students].last[:id]).to eq(test_student.id.to_s)
|
||||
end
|
||||
expect(@assignment.representatives(@teacher)).to include g1rep
|
||||
end
|
||||
|
||||
it "includes users who aren't in a group" do
|
||||
student_in_course active_all: true
|
||||
expect(@assignment.representatives(@teacher).last).to eq @student
|
||||
end
|
||||
it 'returns "groups" instead of students' do
|
||||
json = SpeedGrader::Assignment.new(@assignment, @teacher).json
|
||||
@groups.each do |group|
|
||||
j = json["context"]["students"].find { |g| g["name"] == group.name }
|
||||
expect(group.users.map { |u| u.id.to_s }).to include j["id"]
|
||||
end
|
||||
expect(json["GROUP_GRADING_MODE"]).to be_truthy
|
||||
end
|
||||
|
||||
it "doesn't include deleted groups" do
|
||||
student_in_course active_all: true
|
||||
deleted_group = @gc.groups.create! name: "DELETE ME", context: @course
|
||||
deleted_group.add_user(@student)
|
||||
rep_names = @assignment.representatives(@teacher).map(&:name)
|
||||
expect(rep_names).to include "DELETE ME"
|
||||
it 'chooses the student with turnitin data to represent' do
|
||||
@assignment.update!(turnitin_enabled: true)
|
||||
submissions = @groups.map do |group|
|
||||
rep = group.users.sample
|
||||
@assignment.grade_student(rep, grade: 10, grader: @teacher).first.tap do |submission|
|
||||
submission.update!(turnitin_data: {blah: 1})
|
||||
end
|
||||
end
|
||||
|
||||
deleted_group.destroy!
|
||||
rep_names = @assignment.representatives(@teacher).map(&:name)
|
||||
expect(rep_names).not_to include "DELETE ME"
|
||||
end
|
||||
json = SpeedGrader::Assignment.new(@assignment, @teacher).json
|
||||
json_submission_ids = json["submissions"].map {|s| s.fetch('id')}
|
||||
submission_ids = submissions.map { |t| t.id.to_s }
|
||||
expect(json_submission_ids).to match_array(submission_ids)
|
||||
end
|
||||
|
||||
it 'prefers active users over other workflow states' do
|
||||
group = @groups.first
|
||||
enrollments = group.all_real_student_enrollments
|
||||
enrollments[0].deactivate
|
||||
enrollments[1].conclude
|
||||
it 'prefers people with submissions' do
|
||||
@assignment.grade_student(@first_group.users.first, score: 10, grader: @teacher)
|
||||
first_group_representative = @first_group.users.sample
|
||||
submission = @assignment.submission_for_student(first_group_representative)
|
||||
submission.update!(submission_type: 'online_upload')
|
||||
expect(@assignment.representatives(@teacher)).to include first_group_representative
|
||||
end
|
||||
|
||||
reps = @assignment.representatives(@teacher, includes: %i[inactive completed])
|
||||
user = reps.select { |u| u.name == group.name }.first
|
||||
expect(user.id).to eql(enrollments[2].user_id)
|
||||
end
|
||||
it "prefers people who aren't excused when submission exists" do
|
||||
first_group_representative, *everyone_else = @first_group.users.to_a.shuffle
|
||||
@assignment.submit_homework(first_group_representative, {
|
||||
submission_type: 'online_text_entry',
|
||||
body: 'hi'
|
||||
})
|
||||
everyone_else.each do |user|
|
||||
@assignment.grade_student(user, excuse: true, grader: @teacher)
|
||||
end
|
||||
expect(@assignment.representatives(@teacher)).to include first_group_representative
|
||||
end
|
||||
|
||||
it 'prefers inactive users when no active users are present' do
|
||||
group = @groups.first
|
||||
enrollments = group.all_real_student_enrollments
|
||||
enrollments[0].conclude
|
||||
enrollments[1].deactivate
|
||||
enrollments[2].conclude
|
||||
it "includes users who aren't in a group" do
|
||||
student_in_course active_all: true
|
||||
expect(@assignment.representatives(@teacher)).to include @student
|
||||
end
|
||||
|
||||
reps = @assignment.representatives(@teacher, includes: %i[inactive completed])
|
||||
user = reps.select { |u| u.name == group.name }.first
|
||||
expect(user.id).to eql(enrollments[1].user_id)
|
||||
end
|
||||
it "includes groups" do
|
||||
student_in_course active_all: true
|
||||
group = @group_category.groups.create!(context: @course)
|
||||
group.add_user(@student)
|
||||
expect(@assignment.representatives(@teacher).map(&:name)).to include group.name
|
||||
end
|
||||
|
||||
it 'includes concluded students when included' do
|
||||
group = @groups.first
|
||||
enrollments = group.all_real_student_enrollments
|
||||
enrollments.each(&:conclude)
|
||||
it "doesn't include deleted groups" do
|
||||
student_in_course active_all: true
|
||||
group = @group_category.groups.create!(context: @course)
|
||||
group.add_user(@student)
|
||||
group.destroy!
|
||||
expect(@assignment.representatives(@teacher).map(&:name)).not_to include group.name
|
||||
end
|
||||
|
||||
reps = @assignment.representatives(@teacher, includes: [:completed])
|
||||
user = reps.select { |u| u.name == group.name }.first
|
||||
expect(user.id).to eql(enrollments[0].user_id)
|
||||
end
|
||||
it 'prefers active users over other workflow states' do
|
||||
enrollments = @first_group.all_real_student_enrollments
|
||||
enrollments.first.deactivate
|
||||
enrollments.second.conclude
|
||||
|
||||
it 'does not include concluded students when included' do
|
||||
group = @groups.first
|
||||
enrollments = group.all_real_student_enrollments
|
||||
enrollments.each(&:conclude)
|
||||
reps = @assignment.representatives(@teacher, includes: %i[inactive completed])
|
||||
user = reps.find { |u| u.name == @first_group.name }
|
||||
expect(user).to eql(enrollments.third.user)
|
||||
end
|
||||
|
||||
reps = @assignment.representatives(@teacher, includes: [])
|
||||
user = reps.select { |u| u.name == group.name }.first
|
||||
expect(user).to be_nil
|
||||
end
|
||||
it 'prefers inactive users when no active users are present' do
|
||||
enrollments = @first_group.all_real_student_enrollments
|
||||
enrollments.first.conclude
|
||||
enrollments.second.deactivate
|
||||
enrollments.third.conclude
|
||||
|
||||
it 'includes inactive students when included' do
|
||||
group = @groups.first
|
||||
enrollments = group.all_real_student_enrollments
|
||||
enrollments.each(&:deactivate)
|
||||
reps = @assignment.representatives(@teacher, includes: %i[inactive completed])
|
||||
user = reps.find { |u| u.name == @first_group.name }
|
||||
expect(user).to eql(enrollments.second.user)
|
||||
end
|
||||
|
||||
reps = @assignment.representatives(@teacher, includes: [:inactive])
|
||||
user = reps.select { |u| u.name == group.name }.first
|
||||
expect(user.id).to eql(enrollments[0].user_id)
|
||||
end
|
||||
it 'includes concluded students when included' do
|
||||
enrollments = @first_group.all_real_student_enrollments
|
||||
enrollments.each(&:conclude)
|
||||
|
||||
it 'does not include inactive students when included' do
|
||||
group = @groups.first
|
||||
enrollments = group.all_real_student_enrollments
|
||||
enrollments.each(&:deactivate)
|
||||
reps = @assignment.representatives(@teacher, includes: [:completed])
|
||||
user = reps.find { |u| u.name == @first_group.name }
|
||||
expect(user).to eql(enrollments.first.user)
|
||||
end
|
||||
|
||||
reps = @assignment.representatives(@teacher, includes: [])
|
||||
user = reps.select { |u| u.name == group.name }.first
|
||||
expect(user).to be_nil
|
||||
it 'does not include concluded students when included' do
|
||||
enrollments = @first_group.all_real_student_enrollments
|
||||
enrollments.each(&:conclude)
|
||||
|
||||
reps = @assignment.representatives(@teacher, includes: [])
|
||||
user = reps.find { |u| u.name == @first_group.name }
|
||||
expect(user).to be_nil
|
||||
end
|
||||
|
||||
it 'includes inactive students when included' do
|
||||
enrollments = @first_group.all_real_student_enrollments
|
||||
enrollments.each(&:deactivate)
|
||||
|
||||
reps = @assignment.representatives(@teacher, includes: [:inactive])
|
||||
user = reps.find { |u| u.name == @first_group.name }
|
||||
expect(user).to eql(enrollments.first.user)
|
||||
end
|
||||
|
||||
it 'does not include inactive students when included' do
|
||||
enrollments = @first_group.all_real_student_enrollments
|
||||
enrollments.each(&:deactivate)
|
||||
|
||||
reps = @assignment.representatives(@teacher, includes: [])
|
||||
user = reps.find { |u| u.name == @first_group.name }
|
||||
expect(user).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue