defmodule QuizGrader do require Ami.Gettext import Ecto.Query alias Ami.{ Repo, Enrollment, Quiz, User, UserAnswer, Score, Answer, Gettext } def grade(params) do enrollment = Repo.get(Enrollment, params["enrollment_id"]) |> Repo.preload([:scores, course_period: [:course]]) quiz = Repo.get(Quiz, params["quiz_id"]) |> Repo.preload(questions: [answers: from(a in Answer, order_by: [asc: a.id])]) user = Repo.get(User, params["user_id"]) |> Repo.preload(:profile) score = Score.find(quiz.id, enrollment.id) if score != nil do { Gettext.gettext( "You have already taken this quiz - Please move on to the activity and next lesson." ), enrollment, quiz, user } else user_answers = Map.drop(params, [ "course_id", "enrollment_id", "lesson_id", "quiz_id", "user_id", "submit_confirmed" ]) correct_answers = correct_answers(user_answers, quiz) total_questions = total_questions(quiz) quiz_score = score(user_answers, quiz) if length(Map.to_list(user_answers)) != total_questions do { Gettext.gettext("Please answer all the questions to get a grade for this quiz"), enrollment, quiz, user } else user_answers |> save_answers(enrollment, quiz, user) Score.insert_changeset(%Score{}, %{ value: quiz_score, answers_correct: correct_answers, total_questions: total_questions, quiz_id: quiz.id, user_id: user.id, enrollment_id: enrollment.id, course_id: enrollment.course_period.course_id, course_period_id: enrollment.course_period.id }) |> Repo.insert() # Update the enrollment progress binary {:ok, enrollment} = enrollment |> Repo.preload([:scores, course_period: [:course]], force: true) |> Enrollment.update_progress() {:ok, enrollment} = Enrollment.update_course_flags(enrollment) {:ok, enrollment} = Ecto.Changeset.change(enrollment, %{updated_at: Timex.now()}) |> Repo.update() {:ok, enrollment} = if enrollment.course_started == false do Ecto.Changeset.change(enrollment, %{course_started: true, updated_at: Timex.now()}) |> Repo.update() else {:ok, enrollment} end if quiz.title == "Final Exam" do { Gettext.gettext( "Congratulations on completing your final exam! You scored %{score}%. Now, please go to the Final Assignment tab and review, complete and submit your assignment to complete the course.", score: quiz_score ), enrollment, quiz, user } else {Gettext.gettext("You scored a %{score}% on this quiz.", score: quiz_score), enrollment, quiz, user} end end end end defp save_answers(answers, enrollment, quiz, user) do Enum.each(answers, fn {k, v} -> question = Enum.find(quiz.questions, &(&1.id == String.to_integer(k))) answer = Enum.find(question.answers, &(&1.value == v)) UserAnswer.changeset(%UserAnswer{}, %{ user_id: user.id, answer_id: answer.id, course_period_id: enrollment.course_period.id, question_id: question.id, quiz_id: quiz.id }) |> Repo.insert() end) answers end defp correct_answers(answers, quiz) do Enum.filter(answers, fn {k, v} -> question = Enum.find(quiz.questions, &(&1.id == String.to_integer(k))) correct_answer = Enum.find(question.answers, &(&1.correct_answer == true)) correct_answer.value == v end) |> length() end defp total_questions(quiz), do: length(quiz.questions) defp score(answers, quiz) do (correct_answers(answers, quiz) * 100 / total_questions(quiz)) |> Float.round() |> Kernel.trunc() end end