Fix form submission crash for anonymous attendees (#210)

The FormSubmit changeset required user_id, but anonymous attendees only
have attendee_identifier. This caused a CaseClauseError since the error
tuple was unhandled. Now the changeset accepts either user_id or
attendee_identifier, and error cases are properly handled.
This commit is contained in:
Alexandre Lion
2026-02-09 19:19:05 +01:00
committed by GitHub
parent 8f46837900
commit 910627f4ba
5 changed files with 81 additions and 1 deletions

View File

@@ -10,6 +10,7 @@
### Fixes and improvements
- Fix form submission crash for anonymous attendees
- Improve SMTP config and handling (#197)
- Fix presentation slides URL (#200)
- Fix custom S3 endpoint (#199)

View File

@@ -324,6 +324,9 @@ defmodule Claper.Forms do
nil -> broadcast({:ok, r, event_uuid}, :form_submit_created)
_form_submit -> broadcast({:ok, r, event_uuid}, :form_submit_updated)
end
{:error, changeset} ->
{:error, changeset}
end
end
@@ -344,6 +347,7 @@ defmodule Claper.Forms do
|> Repo.delete()
|> case do
{:ok, r} -> broadcast({:ok, r, event_uuid}, :form_submit_deleted)
{:error, changeset} -> {:error, changeset}
end
end

View File

@@ -25,6 +25,18 @@ defmodule Claper.Forms.FormSubmit do
def changeset(form_submit, attrs) do
form_submit
|> cast(attrs, [:attendee_identifier, :user_id, :form_id, :response])
|> validate_required([:form_id, :user_id, :response])
|> validate_required([:form_id, :response])
|> validate_user_or_attendee()
end
defp validate_user_or_attendee(changeset) do
user_id = get_field(changeset, :user_id)
attendee_identifier = get_field(changeset, :attendee_identifier)
if is_nil(user_id) and is_nil(attendee_identifier) do
add_error(changeset, :user_id, "either user_id or attendee_identifier must be present")
else
changeset
end
end
end

View File

@@ -148,6 +148,9 @@ defmodule ClaperWeb.EventLive.FormComponent do
{:noreply,
socket
|> assign(:current_form_submit, form_submit)}
{:error, _changeset} ->
{:noreply, socket}
end
end
@@ -167,6 +170,9 @@ defmodule ClaperWeb.EventLive.FormComponent do
{:noreply,
socket
|> assign(:current_form_submit, form_submit)}
{:error, _changeset} ->
{:noreply, socket}
end
end

View File

@@ -126,5 +126,62 @@ defmodule Claper.FormsTest do
}
)
end
test "create_or_update_form_submit/2 with attendee_identifier creates a form_submit" do
presentation_file = presentation_file_fixture(%{}, [:event])
f = form_fixture(%{presentation_file_id: presentation_file.id})
assert {:ok, %Claper.Forms.FormSubmit{} = form_submit} =
Forms.create_or_update_form_submit(
presentation_file.event.uuid,
%{
"attendee_identifier" => "test-attendee-123",
"form_id" => f.id,
"response" => %{"Name" => "Daniel"}
}
)
assert form_submit.attendee_identifier == "test-attendee-123"
assert is_nil(form_submit.user_id)
assert form_submit.form_id == f.id
end
test "create_or_update_form_submit/2 with attendee_identifier updates existing form_submit" do
presentation_file = presentation_file_fixture(%{}, [:event])
f = form_fixture(%{presentation_file_id: presentation_file.id})
{:ok, _first_submit} =
Forms.create_or_update_form_submit(
presentation_file.event.uuid,
%{
"attendee_identifier" => "test-attendee-123",
"form_id" => f.id,
"response" => %{"Name" => "Daniel"}
}
)
assert {:ok, %Claper.Forms.FormSubmit{} = updated_submit} =
Forms.create_or_update_form_submit(
presentation_file.event.uuid,
%{
"attendee_identifier" => "test-attendee-123",
"form_id" => f.id,
"response" => %{"Name" => "Updated Name"}
}
)
assert updated_submit.response == %{"Name" => "Updated Name"}
end
test "create_or_update_form_submit/2 without user_id or attendee_identifier returns error" do
presentation_file = presentation_file_fixture(%{}, [:event])
f = form_fixture(%{presentation_file_id: presentation_file.id})
assert {:error, %Ecto.Changeset{}} =
Forms.create_form_submit(%{
form_id: f.id,
response: %{"Name" => "Daniel"}
})
end
end
end