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:
Derek Bender 2019-06-25 11:16:39 -05:00
parent 3664d5ddea
commit 19a0d49b02
2 changed files with 244 additions and 226 deletions

View File

@ -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

View File

@ -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