mirror of
https://github.com/ClaperCo/Claper.git
synced 2025-12-16 11:57:58 +01:00
Fix duplicate key quiz when duplicate (#182)
* add quiz_responses association to user * bugfix possible duplicate key entries in multi when adding quiz responses * remove user_id from casting changeset in QuizResponse * pass whole user to submit_quiz function * update test to match changes * simplify submit_quiz/3 function for inserting quiz response --------- Co-authored-by: Dimitrije Dimitrijevic <me@dimitrijedimitrijevic.com>
This commit is contained in:
committed by
GitHub
parent
fc667bb478
commit
16bcce1a60
@@ -30,6 +30,7 @@ defmodule Claper.Accounts.User do
|
|||||||
|
|
||||||
has_many :events, Claper.Events.Event
|
has_many :events, Claper.Events.Event
|
||||||
has_one :lti_user, Lti13.Users.User
|
has_one :lti_user, Lti13.Users.User
|
||||||
|
has_many :quiz_responses, Claper.Quizzes.QuizResponse
|
||||||
|
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ defmodule Claper.Quizzes do
|
|||||||
import Ecto.Query, warn: false
|
import Ecto.Query, warn: false
|
||||||
alias Claper.Repo
|
alias Claper.Repo
|
||||||
|
|
||||||
|
alias Claper.Accounts.User
|
||||||
|
|
||||||
alias Claper.Quizzes.Quiz
|
alias Claper.Quizzes.Quiz
|
||||||
alias Claper.Quizzes.QuizQuestion
|
alias Claper.Quizzes.QuizQuestion
|
||||||
alias Claper.Quizzes.QuizQuestionOpt
|
alias Claper.Quizzes.QuizQuestionOpt
|
||||||
@@ -265,28 +267,62 @@ defmodule Claper.Quizzes do
|
|||||||
{:ok, quiz}
|
{:ok, quiz}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def submit_quiz(user_id, quiz_opts, quiz_id)
|
|
||||||
when is_number(user_id) and is_list(quiz_opts) do
|
# Pattern match on user, from user we create QuizResponse struct
|
||||||
case Enum.reduce(quiz_opts, Ecto.Multi.new(), fn opt, multi ->
|
# def submit_quiz(user_id, quiz_opts, quiz_id)
|
||||||
Ecto.Multi.update(
|
# when is_number(user_id) and is_list(quiz_opts) do
|
||||||
multi,
|
# quiz_opts = Enum.with_index(quiz_opts)
|
||||||
{:update_quiz_opt, opt.id},
|
|
||||||
|
# case Enum.reduce(quiz_opts, Ecto.Multi.new(), fn {opt, index}, multi ->
|
||||||
|
# unique_key = "#{opt.id}_#{user_id + index}"
|
||||||
|
|
||||||
|
# multi
|
||||||
|
# |> Ecto.Multi.update(
|
||||||
|
# "update_quiz_opt_#{unique_key}",
|
||||||
|
# QuizQuestionOpt.changeset(opt, %{"response_count" => opt.response_count + 1})
|
||||||
|
# )
|
||||||
|
# |> Ecto.Multi.insert(
|
||||||
|
# "insert_quiz_response_#{unique_key}",
|
||||||
|
# QuizResponse.changeset(%QuizResponse{}, %{
|
||||||
|
# user_id: user_id,
|
||||||
|
# quiz_question_opt_id: opt.id,
|
||||||
|
# quiz_question_id: opt.quiz_question_id,
|
||||||
|
# quiz_id: quiz_id
|
||||||
|
# })
|
||||||
|
# )
|
||||||
|
# end)
|
||||||
|
# |> Repo.transact() do
|
||||||
|
# {:ok, _} ->
|
||||||
|
# quiz = get_quiz!(quiz_id, [:quiz_questions, quiz_questions: :quiz_question_opts])
|
||||||
|
# Lti13.QuizScoreReporter.report_quiz_score(quiz, user_id)
|
||||||
|
# {:ok, quiz}
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
def submit_quiz(%User{} = user, quiz_opts, quiz_id) do
|
||||||
|
quiz_opts = Enum.with_index(quiz_opts)
|
||||||
|
|
||||||
|
case Enum.reduce(quiz_opts, Ecto.Multi.new(), fn {opt, index}, multi ->
|
||||||
|
unique_key = "#{opt.id}_#{user.id + index}"
|
||||||
|
|
||||||
|
multi
|
||||||
|
|> Ecto.Multi.update(
|
||||||
|
"update_quiz_opt_#{unique_key}",
|
||||||
QuizQuestionOpt.changeset(opt, %{"response_count" => opt.response_count + 1})
|
QuizQuestionOpt.changeset(opt, %{"response_count" => opt.response_count + 1})
|
||||||
)
|
)
|
||||||
|> Ecto.Multi.insert(
|
|> Ecto.Multi.insert(
|
||||||
{:insert_quiz_response, opt.id},
|
"insert_quiz_response_#{unique_key}",
|
||||||
QuizResponse.changeset(%QuizResponse{}, %{
|
Ecto.build_assoc(user, :quiz_responses, %{
|
||||||
user_id: user_id,
|
|
||||||
quiz_question_opt_id: opt.id,
|
quiz_question_opt_id: opt.id,
|
||||||
quiz_question_id: opt.quiz_question_id,
|
quiz_question_id: opt.quiz_question_id,
|
||||||
quiz_id: quiz_id
|
quiz_id: quiz_id
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|> Repo.transaction() do
|
|> Repo.transact() do
|
||||||
{:ok, _} ->
|
{:ok, _} ->
|
||||||
quiz = get_quiz!(quiz_id, [:quiz_questions, quiz_questions: :quiz_question_opts])
|
quiz = get_quiz!(quiz_id, [:quiz_questions, quiz_questions: :quiz_question_opts])
|
||||||
Lti13.QuizScoreReporter.report_quiz_score(quiz, user_id)
|
Lti13.QuizScoreReporter.report_quiz_score(quiz, user.id)
|
||||||
{:ok, quiz}
|
{:ok, quiz}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -294,8 +330,8 @@ defmodule Claper.Quizzes do
|
|||||||
def submit_quiz(attendee_identifier, quiz_opts, quiz_id)
|
def submit_quiz(attendee_identifier, quiz_opts, quiz_id)
|
||||||
when is_binary(attendee_identifier) and is_list(quiz_opts) do
|
when is_binary(attendee_identifier) and is_list(quiz_opts) do
|
||||||
case Enum.reduce(quiz_opts, Ecto.Multi.new(), fn opt, multi ->
|
case Enum.reduce(quiz_opts, Ecto.Multi.new(), fn opt, multi ->
|
||||||
Ecto.Multi.update(
|
multi
|
||||||
multi,
|
|> Ecto.Multi.update(
|
||||||
{:update_quiz_opt, opt.id},
|
{:update_quiz_opt, opt.id},
|
||||||
QuizQuestionOpt.changeset(opt, %{"response_count" => opt.response_count + 1})
|
QuizQuestionOpt.changeset(opt, %{"response_count" => opt.response_count + 1})
|
||||||
)
|
)
|
||||||
@@ -309,7 +345,7 @@ defmodule Claper.Quizzes do
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|> Repo.transaction() do
|
|> Repo.transact() do
|
||||||
{:ok, _} ->
|
{:ok, _} ->
|
||||||
quiz = get_quiz!(quiz_id, [:quiz_questions, quiz_questions: :quiz_question_opts])
|
quiz = get_quiz!(quiz_id, [:quiz_questions, quiz_questions: :quiz_question_opts])
|
||||||
{:ok, quiz}
|
{:ok, quiz}
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ defmodule Claper.Quizzes.QuizResponse do
|
|||||||
:attendee_identifier,
|
:attendee_identifier,
|
||||||
:quiz_id,
|
:quiz_id,
|
||||||
:quiz_question_id,
|
:quiz_question_id,
|
||||||
:quiz_question_opt_id,
|
:quiz_question_opt_id
|
||||||
:user_id
|
|
||||||
])
|
])
|
||||||
|> validate_required([:quiz_id, :quiz_question_id, :quiz_question_opt_id])
|
|> validate_required([:quiz_id, :quiz_question_id, :quiz_question_opt_id])
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -693,7 +693,7 @@ defmodule ClaperWeb.EventLive.Show do
|
|||||||
)
|
)
|
||||||
when is_map(current_user) do
|
when is_map(current_user) do
|
||||||
case Claper.Quizzes.submit_quiz(
|
case Claper.Quizzes.submit_quiz(
|
||||||
current_user.id,
|
current_user,
|
||||||
opts,
|
opts,
|
||||||
socket.assigns.current_interaction.id
|
socket.assigns.current_interaction.id
|
||||||
) do
|
) do
|
||||||
|
|||||||
@@ -113,14 +113,14 @@ defmodule Claper.QuizzesTest do
|
|||||||
assert length(new_question.quiz_question_opts) == 2
|
assert length(new_question.quiz_question_opts) == 2
|
||||||
end
|
end
|
||||||
|
|
||||||
test "submit_quiz/3 with user_id records responses and updates counts" do
|
test "submit_quiz/3 with user records responses and updates counts" do
|
||||||
quiz = quiz_fixture()
|
quiz = quiz_fixture()
|
||||||
user = user_fixture()
|
user = user_fixture()
|
||||||
question = List.first(quiz.quiz_questions)
|
question = List.first(quiz.quiz_questions)
|
||||||
option = List.first(question.quiz_question_opts)
|
option = List.first(question.quiz_question_opts)
|
||||||
|
|
||||||
assert {:ok, updated_quiz} =
|
assert {:ok, updated_quiz} =
|
||||||
Quizzes.submit_quiz(user.id, [option], quiz.id)
|
Quizzes.submit_quiz(user, [option], quiz.id)
|
||||||
|
|
||||||
updated_option =
|
updated_option =
|
||||||
updated_quiz.quiz_questions
|
updated_quiz.quiz_questions
|
||||||
@@ -151,7 +151,7 @@ defmodule Claper.QuizzesTest do
|
|||||||
correct_option = Enum.find(question.quiz_question_opts, & &1.is_correct)
|
correct_option = Enum.find(question.quiz_question_opts, & &1.is_correct)
|
||||||
|
|
||||||
# Submit correct answer
|
# Submit correct answer
|
||||||
{:ok, _} = Quizzes.submit_quiz(user.id, [correct_option], quiz.id)
|
{:ok, _} = Quizzes.submit_quiz(user, [correct_option], quiz.id)
|
||||||
assert {1, 1} = Quizzes.calculate_user_score(user.id, quiz.id)
|
assert {1, 1} = Quizzes.calculate_user_score(user.id, quiz.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user