Fixes event rebuild tools, optimization for event_aggregator

This should make event rebuilding equivalent with versions rebuilding
in the most substantial ways (doesn't cause bug in quiz showing with
unsupported question types).

Refs CNVS-20069

Test Plan:
  - contact Ryan for DB migration script
  - Run custom migration
  - Delete a single quiz submission with raw SQL query
  - Rebuild that quiz_submission from the events log
  - Confirm that the quiz is viewable, contains the same questions, and
    is properly graded.

Change-Id: Ia66a3f15e86e5dffd8ba2eff1ce5ff1ce663ad9b
Reviewed-on: https://gerrit.instructure.com/55164
Tested-by: Cameron Sutter <csutter@instructure.com>
Reviewed-by: Brian Finney <bfinney@instructure.com>
QA-Review: Robert Lamb <rlamb@instructure.com>
Product-Review: Ryan Taylor <rtaylor@instructure.com>
This commit is contained in:
Ryan Taylor 2015-05-27 10:43:36 -06:00
parent 46f31b42fb
commit 6ebff05c4a
2 changed files with 70 additions and 3 deletions

View File

@ -85,7 +85,7 @@ module Quizzes::LogAuditing
def build_submission_data_from_answers(answers)
submission_data = {}
answers.each do |question_id, answer|
question = quiz.quiz_questions.find { |qq| qq.id == question_id }
question = quiz.quiz_questions.find { |qq| qq.id == question_id.to_i }
question = Quizzes::QuizQuestion.where(id: question_id).first unless question
if question.question_data["question_type"] != "text_only_question"
serializer = Quizzes::QuizQuestion::AnswerSerializers.serializer_for(question)

View File

@ -114,6 +114,74 @@ module DataFixup::RebuildQuizSubmissionsFromQuizSubmissionEvents
qs
end
def self.pick_questions(qs, seen_question_ids)
# Parsing all the deets from events can do it though
quiz_group_picks = Hash.new {|h, k| h[k] = []}
quiz_group_pick_counts = {}
picked_questions = qs.quiz.stored_questions.select do |question|
if question["entry_type"] == "quiz_group"
group_name = question["id"]
quiz_group_pick_counts[group_name] = question["pick_count"]
matching_questions = question["questions"].select {|q| seen_question_ids.include? q["id"].to_s}
matching_questions.each {|q| q["points_possible"] = question["question_points"]}
quiz_group_picks[group_name] += matching_questions
false
else
true
end
end
quiz_group_picks.each do |k,v|
qs.quiz.stored_questions.select {|q| q["id"] == k }.map do |question|
question["questions"].shuffle.each do |q|
break if v.count == quiz_group_pick_counts[k]
q["points_possible"] = question["question_points"]
v << q unless v.include? q
end
end
end
picked_questions += quiz_group_picks.values.flatten
if qs.quiz.question_count != picked_questions.size
Rails.logger.error LOG_PREFIX + "#{qs.id} doesn't match it's question count"
end
picked_questions
end
# Because we can't regenerate quiz data without getting a different set of questions,
# we need to select the quiz_questions from the questions we can know the student has
# seen.
def self.aggregate_quiz_data_from_events(qs, events)
question_events = events.select {|e| ["question_answered", "question_viewed", "question_flagged"].include?(e.event_type)}
seen_question_ids = []
question_events.each do |event|
if event.event_type == "question_viewed"
seen_question_ids << event.answers
else
seen_question_ids << event.answers.flatten.map {|h| h["quiz_question_id"]}
end
end
seen_question_ids = seen_question_ids.flatten.uniq
builder = Quizzes::QuizQuestionBuilder.new({
shuffle_answers: qs.quiz.shuffle_answers
})
if seen_question_ids.count > 0
picked_questions = pick_questions(qs, seen_question_ids)
raw_data = builder.shuffle_quiz_data!(picked_questions)
raw_data.each_with_index do |question, index|
Quizzes::QuizQuestionBuilder.decorate_question_for_submission(question, index)
end
else
submission.quiz_data = begin
qs.quiz.stored_questions = nil
builder.build_submission_questions(qs.quiz.id, qs.quiz.stored_questions)
end
end
end
def self.build_new_submission_from_quiz_submission_events(submission)
if submission.submission_type != "online_quiz"
Rails.logger.warn LOG_PREFIX + "Skipping because this isn't a quiz!\tsubmission_id: #{submission.id}"
@ -160,14 +228,13 @@ module DataFixup::RebuildQuizSubmissionsFromQuizSubmissionEvents
# This is sad because assumptions
qs.quiz_version = qs.versions.map {|v| v.model.quiz_version}.sort.last
qs.quiz_data = aggregate_quiz_data_from_events(qs, events)
# Set reasonable timestamps
qs.created_at = submission.created_at
qs.started_at = times.first
qs.finished_at = submission.submitted_at
# Set internal data for grading
qs.quiz_data = submission.assignment.quiz.quiz_data
qs.submission_data = submission_data_hash
qs.save!