app/models/quiz_assignment.rb
module QuizAssignment
# Returns a set of topics that can be used for taking the quiz.
# We choose the topics if one of its quiz submissions has been attempted the fewest times so far
def candidate_topics_for_quiz
return nil if sign_up_topics.empty? # This is not a topic assignment
contributor_set = Array.new(contributors)
# Reject contributors that have not selected a topic, or have no submissions
contributor_set.reject! {|contributor| signed_up_topic(contributor).nil? }
# Reject contributions of topics whose deadline has passed
contributor_set.reject! do |contributor|
contributor.assignment.get_current_stage(signed_up_topic(contributor).id) == "Complete" or
contributor.assignment.get_current_stage(signed_up_topic(contributor).id) == "submission"
end
candidate_topics = Set.new
contributor_set.each {|contributor| candidate_topics.add(signed_up_topic(contributor)) }
candidate_topics
end
def assign_quiz_dynamically(reviewer, topic)
contributor = contributor_for_quiz(reviewer, topic)
reviewer.assign_quiz(contributor, reviewer, topic) unless contributor.nil?
end
# Returns a contributor whose quiz is to be taken if available, otherwise will raise an error
def contributor_for_quiz(reviewer, topic)
raise "Please select a topic." if topics? and topic.nil?
raise "This assignment does not have topics." if !topics? and topic
# This condition might happen if the reviewer/quiz taker waited too much time in the
# select topic page and other students have already selected this topic.
# Another scenario is someone that deliberately modifies the view.
if topic
raise "To many quizes have been taken for this topic; please select another one." unless candidate_topics_for_quiz.include?(topic)
end
contributor_set = Array.new(contributors)
work = topic.nil? ? 'assignment' : 'topic'
# 1) Only consider contributors that worked on this topic; 2) remove reviewer/quiz taker as contributor
# 3) remove contributors that have not submitted work yet
contributor_set.reject! do |contributor|
signed_up_topic(contributor) != topic or # both will be nil for assignments with no signup sheet
contributor.includes?(reviewer) # ##or !contributor.has_quiz?
end
raise "There are no more submissions to take quiz on for this #{work}." if contributor_set.empty?
# Reviewer/quiz taker can take quiz for each submission only once
contributor_set.reject! {|contributor| quiz_taken_by?(contributor, reviewer) }
# raise "You have already taken the quiz for all submissions for this #{work}." if contributor_set.empty?
# Choose a contributor at random (.sample) from the remaining contributors.
# Actually, we SHOULD pick the contributor who was least recently picked. But sample
# is much simpler, and probably almost as good, given that even if the contributors are
# picked in round-robin fashion, the reviews will not be submitted in the same order that
# they were picked.
contributor_set.sample
end
def quiz_taken_by?(contributor, reviewer)
quiz_id = QuizQuestionnaire.find_by(instructor_id: contributor.id).id
QuizResponseMap.where('reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',
contributor.id, reviewer.id, quiz_id).count > 0
end
end