mirror of
https://github.com/ClaperCo/Claper.git
synced 2026-09-02 03:59:46 +02:00
Add event-scoped retrieval functions for embeds, forms, polls, posts, and quizzes
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
- Fix stored XSS vulnerability in custom embed iframes via input sanitization with attribute whitelisting
|
||||
- Fix XSS vulnerability in URL link formatting by escaping user-submitted URLs
|
||||
- Fix IDOR on form export endpoint by adding authorization check
|
||||
- Fix cross-event IDOR on polls, quizzes, forms, embeds, and posts by enforcing event-scoped resource access in context layer
|
||||
- Fix atom exhaustion DoS by replacing `String.to_atom/1` on user input with explicit whitelists (8 locations)
|
||||
- Add rate limiting on authentication endpoints using Hammer 7.0
|
||||
|
||||
|
||||
@@ -59,6 +59,23 @@ defmodule Claper.Embeds do
|
||||
def get_embed!(id, preload \\ []),
|
||||
do: Repo.get!(Embed, id) |> Repo.preload(preload)
|
||||
|
||||
@doc """
|
||||
Gets a single embed scoped to the given event.
|
||||
|
||||
Returns `nil` if the embed does not exist or does not belong to the event.
|
||||
"""
|
||||
def get_embed_for_event(id, event_id, preload \\ []) do
|
||||
from(e in Embed,
|
||||
join: pf in assoc(e, :presentation_file),
|
||||
where: e.id == ^id and pf.event_id == ^event_id
|
||||
)
|
||||
|> Repo.one()
|
||||
|> case do
|
||||
nil -> nil
|
||||
embed -> Repo.preload(embed, preload)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single embed for a given position.
|
||||
|
||||
|
||||
@@ -61,6 +61,23 @@ defmodule Claper.Forms do
|
||||
def get_form!(id, preload \\ []),
|
||||
do: Repo.get!(Form, id) |> Repo.preload(preload)
|
||||
|
||||
@doc """
|
||||
Gets a single form scoped to the given event.
|
||||
|
||||
Returns `nil` if the form does not exist or does not belong to the event.
|
||||
"""
|
||||
def get_form_for_event(id, event_id, preload \\ []) do
|
||||
from(f in Form,
|
||||
join: pf in assoc(f, :presentation_file),
|
||||
where: f.id == ^id and pf.event_id == ^event_id
|
||||
)
|
||||
|> Repo.one()
|
||||
|> case do
|
||||
nil -> nil
|
||||
form -> Repo.preload(form, preload)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single form for a given position.
|
||||
|
||||
@@ -280,6 +297,20 @@ defmodule Claper.Forms do
|
||||
def get_form_submit_by_id!(id, preload \\ []),
|
||||
do: Repo.get_by!(FormSubmit, id: id) |> Repo.preload(preload)
|
||||
|
||||
@doc """
|
||||
Gets a single FormSubmit scoped to the given event.
|
||||
|
||||
Returns `nil` if the FormSubmit does not exist or does not belong to the event.
|
||||
"""
|
||||
def get_form_submit_for_event(id, event_id) do
|
||||
from(fs in FormSubmit,
|
||||
join: f in assoc(fs, :form),
|
||||
join: pf in assoc(f, :presentation_file),
|
||||
where: fs.id == ^id and pf.event_id == ^event_id
|
||||
)
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates or update a FormSubmit.
|
||||
|
||||
|
||||
@@ -72,6 +72,34 @@ defmodule Claper.Polls do
|
||||
)
|
||||
|> set_percentages()
|
||||
|
||||
@doc """
|
||||
Gets a single poll scoped to the given event.
|
||||
|
||||
Returns `nil` if the poll does not exist or does not belong to the event.
|
||||
"""
|
||||
def get_poll_for_event(id, event_id) do
|
||||
from(p in Poll,
|
||||
join: pf in assoc(p, :presentation_file),
|
||||
where: p.id == ^id and pf.event_id == ^event_id
|
||||
)
|
||||
|> Repo.one()
|
||||
|> case do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
poll ->
|
||||
poll
|
||||
|> Repo.preload(
|
||||
poll_opts:
|
||||
from(
|
||||
o in PollOpt,
|
||||
order_by: [asc: o.id]
|
||||
)
|
||||
)
|
||||
|> set_percentages()
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single poll for a given position.
|
||||
|
||||
|
||||
@@ -120,6 +120,22 @@ defmodule Claper.Posts do
|
||||
"""
|
||||
def get_post!(id, preload \\ []), do: Repo.get_by!(Post, uuid: id) |> Repo.preload(preload)
|
||||
|
||||
@doc """
|
||||
Gets a single post scoped to the given event.
|
||||
|
||||
Returns `nil` if the post does not exist or does not belong to the event.
|
||||
"""
|
||||
def get_post_for_event(uuid, event_id, preload \\ []) do
|
||||
from(p in Post,
|
||||
where: p.uuid == ^uuid and p.event_id == ^event_id
|
||||
)
|
||||
|> Repo.one()
|
||||
|> case do
|
||||
nil -> nil
|
||||
post -> Repo.preload(post, preload)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a post.
|
||||
|
||||
|
||||
@@ -70,6 +70,23 @@ defmodule Claper.Quizzes do
|
||||
|> set_percentages()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single quiz scoped to the given event.
|
||||
|
||||
Returns `nil` if the quiz does not exist or does not belong to the event.
|
||||
"""
|
||||
def get_quiz_for_event(id, event_id, preload \\ []) do
|
||||
from(q in Quiz,
|
||||
join: pf in assoc(q, :presentation_file),
|
||||
where: q.id == ^id and pf.event_id == ^event_id
|
||||
)
|
||||
|> Repo.one()
|
||||
|> case do
|
||||
nil -> nil
|
||||
quiz -> quiz |> Repo.preload(preload) |> set_percentages()
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single quiz for a given position.
|
||||
|
||||
|
||||
@@ -24,10 +24,14 @@ defmodule ClaperWeb.EmbedLive.FormComponent do
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"id" => id}, socket) do
|
||||
embed = Embeds.get_embed!(id)
|
||||
{:ok, _} = Embeds.delete_embed(socket.assigns.event_uuid, embed)
|
||||
case Embeds.get_embed_for_event(id, socket.assigns.presentation_file.event_id) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply, socket |> push_navigate(to: socket.assigns.return_to)}
|
||||
embed ->
|
||||
{:ok, _} = Embeds.delete_embed(socket.assigns.event_uuid, embed)
|
||||
{:noreply, socket |> push_navigate(to: socket.assigns.return_to)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
||||
@@ -76,6 +76,8 @@ defmodule ClaperWeb.EventLive.Manage do
|
||||
|
||||
defp leader?(_socket, _event), do: false
|
||||
|
||||
defp event_id(%{assigns: %{event: event}}), do: event.id
|
||||
|
||||
@impl true
|
||||
def handle_info(%{event: "presence_diff"}, %{assigns: %{event: event}} = socket) do
|
||||
attendees = Presence.list("event:#{event.uuid}")
|
||||
@@ -329,127 +331,175 @@ defmodule ClaperWeb.EventLive.Manage do
|
||||
end
|
||||
|
||||
def handle_event("poll-set-active", %{"id" => id}, socket) do
|
||||
with poll <- Polls.get_poll!(id), :ok <- Claper.Interactions.enable_interaction(poll) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, poll}
|
||||
)
|
||||
case Polls.get_poll_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, poll)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
poll ->
|
||||
with :ok <- Claper.Interactions.enable_interaction(poll) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, poll}
|
||||
)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, poll)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event("form-set-active", %{"id" => id}, socket) do
|
||||
with form <- Forms.get_form!(id), :ok <- Claper.Interactions.enable_interaction(form) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, form}
|
||||
)
|
||||
case Forms.get_form_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, form)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
form ->
|
||||
with :ok <- Claper.Interactions.enable_interaction(form) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, form}
|
||||
)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, form)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event("embed-set-active", %{"id" => id}, socket) do
|
||||
with embed <- Embeds.get_embed!(id), :ok <- Claper.Interactions.enable_interaction(embed) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, embed}
|
||||
)
|
||||
case Embeds.get_embed_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, embed)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
embed ->
|
||||
with :ok <- Claper.Interactions.enable_interaction(embed) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, embed}
|
||||
)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, embed)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event("poll-set-inactive", %{"id" => id}, socket) do
|
||||
with poll <- Polls.get_poll!(id), {:ok, _} <- Claper.Interactions.disable_interaction(poll) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, nil}
|
||||
)
|
||||
end
|
||||
case Polls.get_poll_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, nil)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
poll ->
|
||||
with {:ok, _} <- Claper.Interactions.disable_interaction(poll) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, nil}
|
||||
)
|
||||
end
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, nil)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event("form-set-inactive", %{"id" => id}, socket) do
|
||||
with form <- Forms.get_form!(id), {:ok, _} <- Claper.Interactions.disable_interaction(form) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, nil}
|
||||
)
|
||||
end
|
||||
case Forms.get_form_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, nil)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
form ->
|
||||
with {:ok, _} <- Claper.Interactions.disable_interaction(form) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, nil}
|
||||
)
|
||||
end
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, nil)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event("embed-set-inactive", %{"id" => id}, socket) do
|
||||
with embed <- Embeds.get_embed!(id),
|
||||
{:ok, _} <- Claper.Interactions.disable_interaction(embed) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, nil}
|
||||
)
|
||||
end
|
||||
case Embeds.get_embed_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, nil)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
embed ->
|
||||
with {:ok, _} <- Claper.Interactions.disable_interaction(embed) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, nil}
|
||||
)
|
||||
end
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, nil)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("quiz-set-active", %{"id" => id}, socket) do
|
||||
with quiz <- Quizzes.get_quiz!(id, [:quiz_questions, quiz_questions: :quiz_question_opts]),
|
||||
:ok <- Claper.Interactions.enable_interaction(quiz) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, quiz}
|
||||
)
|
||||
case Quizzes.get_quiz_for_event(id, event_id(socket), [
|
||||
:quiz_questions,
|
||||
quiz_questions: :quiz_question_opts
|
||||
]) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, quiz)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
quiz ->
|
||||
with :ok <- Claper.Interactions.enable_interaction(quiz) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, quiz}
|
||||
)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, quiz)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event("quiz-set-inactive", %{"id" => id}, socket) do
|
||||
with quiz <- Quizzes.get_quiz!(id),
|
||||
{:ok, _} <- Claper.Interactions.disable_interaction(quiz) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, nil}
|
||||
)
|
||||
end
|
||||
case Quizzes.get_quiz_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, nil)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
quiz ->
|
||||
with {:ok, _} <- Claper.Interactions.disable_interaction(quiz) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Claper.PubSub,
|
||||
"event:#{socket.assigns.event.uuid}",
|
||||
{:current_interaction, nil}
|
||||
)
|
||||
end
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:current_interaction, nil)
|
||||
|> interactions_at_position(socket.assigns.state.position)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
@@ -465,8 +515,10 @@ defmodule ClaperWeb.EventLive.Manage do
|
||||
|
||||
@impl true
|
||||
def handle_event("pin", %{"id" => id}, socket) do
|
||||
post = Claper.Posts.get_post!(id, [:event])
|
||||
pin(post, socket)
|
||||
case Claper.Posts.get_post_for_event(id, event_id(socket), [:event]) do
|
||||
nil -> {:noreply, socket}
|
||||
post -> pin(post, socket)
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
@@ -669,21 +721,26 @@ defmodule ClaperWeb.EventLive.Manage do
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"id" => id}, socket) do
|
||||
post = Claper.Posts.get_post!(id, [:event])
|
||||
{:ok, _} = Claper.Posts.delete_post(post)
|
||||
case Claper.Posts.get_post_for_event(id, event_id(socket), [:event]) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
updated_socket =
|
||||
if post.pinned do
|
||||
stream(socket, :pinned_posts, list_pinned_posts(socket, socket.assigns.event.uuid),
|
||||
reset: true
|
||||
)
|
||||
post ->
|
||||
{:ok, _} = Claper.Posts.delete_post(post)
|
||||
|
||||
stream(socket, :posts, list_all_posts(socket, socket.assigns.event.uuid), reset: true)
|
||||
else
|
||||
stream(socket, :posts, list_all_posts(socket, socket.assigns.event.uuid), reset: true)
|
||||
end
|
||||
updated_socket =
|
||||
if post.pinned do
|
||||
stream(socket, :pinned_posts, list_pinned_posts(socket, socket.assigns.event.uuid),
|
||||
reset: true
|
||||
)
|
||||
|
||||
{:noreply, updated_socket}
|
||||
stream(socket, :posts, list_all_posts(socket, socket.assigns.event.uuid), reset: true)
|
||||
else
|
||||
stream(socket, :posts, list_all_posts(socket, socket.assigns.event.uuid), reset: true)
|
||||
end
|
||||
|
||||
{:noreply, updated_socket}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
@@ -697,16 +754,21 @@ defmodule ClaperWeb.EventLive.Manage do
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("delete-form-submit", %{"event-id" => event_id, "id" => id}, socket) do
|
||||
form = Claper.Forms.get_form_submit_by_id!(id)
|
||||
{:ok, _} = Claper.Forms.delete_form_submit(event_id, form)
|
||||
def handle_event("delete-form-submit", %{"id" => id}, socket) do
|
||||
case Claper.Forms.get_form_submit_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply,
|
||||
assign(
|
||||
socket,
|
||||
:form_submits,
|
||||
list_form_submits(socket, socket.assigns.event.presentation_file.id)
|
||||
)}
|
||||
form_submit ->
|
||||
{:ok, _} = Claper.Forms.delete_form_submit(socket.assigns.event.uuid, form_submit)
|
||||
|
||||
{:noreply,
|
||||
assign(
|
||||
socket,
|
||||
:form_submits,
|
||||
list_form_submits(socket, socket.assigns.event.presentation_file.id)
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
@@ -762,18 +824,26 @@ defmodule ClaperWeb.EventLive.Manage do
|
||||
|
||||
@impl true
|
||||
def handle_event("delete-poll", %{"id" => id}, socket) do
|
||||
poll = Polls.get_poll!(id)
|
||||
{:ok, _} = Polls.delete_poll(socket.assigns.event.uuid, poll)
|
||||
case Polls.get_poll_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply, socket}
|
||||
poll ->
|
||||
{:ok, _} = Polls.delete_poll(socket.assigns.event.uuid, poll)
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("delete-quiz", %{"id" => id}, socket) do
|
||||
quiz = Quizzes.get_quiz!(id)
|
||||
{:ok, _} = Quizzes.delete_quiz(socket.assigns.event.uuid, quiz)
|
||||
case Quizzes.get_quiz_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply, socket}
|
||||
quiz ->
|
||||
{:ok, _} = Quizzes.delete_quiz(socket.assigns.event.uuid, quiz)
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
@@ -826,13 +896,19 @@ defmodule ClaperWeb.EventLive.Manage do
|
||||
end
|
||||
|
||||
defp apply_action(socket, :edit_poll, %{"id" => id}) do
|
||||
poll = Polls.get_poll!(id)
|
||||
case Polls.get_poll_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
socket
|
||||
|> put_flash(:error, gettext("Resource not found"))
|
||||
|> push_navigate(to: ~p"/e/#{socket.assigns.event.code}/manage")
|
||||
|
||||
socket
|
||||
|> assign(:create, "poll")
|
||||
|> assign(:interaction_modal, true)
|
||||
|> assign(:create_action, :edit)
|
||||
|> assign(:poll, poll)
|
||||
poll ->
|
||||
socket
|
||||
|> assign(:create, "poll")
|
||||
|> assign(:interaction_modal, true)
|
||||
|> assign(:create_action, :edit)
|
||||
|> assign(:poll, poll)
|
||||
end
|
||||
end
|
||||
|
||||
defp apply_action(socket, :add_form, _params) do
|
||||
@@ -859,23 +935,35 @@ defmodule ClaperWeb.EventLive.Manage do
|
||||
end
|
||||
|
||||
defp apply_action(socket, :edit_form, %{"id" => id}) do
|
||||
form = Forms.get_form!(id)
|
||||
case Forms.get_form_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
socket
|
||||
|> put_flash(:error, gettext("Resource not found"))
|
||||
|> push_navigate(to: ~p"/e/#{socket.assigns.event.code}/manage")
|
||||
|
||||
socket
|
||||
|> assign(:create, "form")
|
||||
|> assign(:interaction_modal, true)
|
||||
|> assign(:create_action, :edit)
|
||||
|> assign(:form, form)
|
||||
form ->
|
||||
socket
|
||||
|> assign(:create, "form")
|
||||
|> assign(:interaction_modal, true)
|
||||
|> assign(:create_action, :edit)
|
||||
|> assign(:form, form)
|
||||
end
|
||||
end
|
||||
|
||||
defp apply_action(socket, :edit_embed, %{"id" => id}) do
|
||||
embed = Embeds.get_embed!(id)
|
||||
case Embeds.get_embed_for_event(id, event_id(socket)) do
|
||||
nil ->
|
||||
socket
|
||||
|> put_flash(:error, gettext("Resource not found"))
|
||||
|> push_navigate(to: ~p"/e/#{socket.assigns.event.code}/manage")
|
||||
|
||||
socket
|
||||
|> assign(:create, "embed")
|
||||
|> assign(:interaction_modal, true)
|
||||
|> assign(:create_action, :edit)
|
||||
|> assign(:embed, embed)
|
||||
embed ->
|
||||
socket
|
||||
|> assign(:create, "embed")
|
||||
|> assign(:interaction_modal, true)
|
||||
|> assign(:create_action, :edit)
|
||||
|> assign(:embed, embed)
|
||||
end
|
||||
end
|
||||
|
||||
defp apply_action(socket, :add_quiz, _params) do
|
||||
@@ -900,13 +988,22 @@ defmodule ClaperWeb.EventLive.Manage do
|
||||
end
|
||||
|
||||
defp apply_action(socket, :edit_quiz, %{"id" => id}) do
|
||||
quiz = Quizzes.get_quiz!(id, [:quiz_questions, quiz_questions: :quiz_question_opts])
|
||||
case Quizzes.get_quiz_for_event(id, event_id(socket), [
|
||||
:quiz_questions,
|
||||
quiz_questions: :quiz_question_opts
|
||||
]) do
|
||||
nil ->
|
||||
socket
|
||||
|> put_flash(:error, gettext("Resource not found"))
|
||||
|> push_navigate(to: ~p"/e/#{socket.assigns.event.code}/manage")
|
||||
|
||||
socket
|
||||
|> assign(:create, "quiz")
|
||||
|> assign(:interaction_modal, true)
|
||||
|> assign(:create_action, :edit)
|
||||
|> assign(:quiz, quiz)
|
||||
quiz ->
|
||||
socket
|
||||
|> assign(:create, "quiz")
|
||||
|> assign(:interaction_modal, true)
|
||||
|> assign(:create_action, :edit)
|
||||
|> assign(:quiz, quiz)
|
||||
end
|
||||
end
|
||||
|
||||
defp pin(post, socket) do
|
||||
|
||||
@@ -1398,7 +1398,6 @@
|
||||
to: "#",
|
||||
phx_click: "delete-form-submit",
|
||||
phx_value_id: submission.id,
|
||||
phx_value_event_id: @event.uuid,
|
||||
data: [confirm: gettext("This cannot be undone, confirm ?")]
|
||||
)}
|
||||
</span>
|
||||
|
||||
@@ -17,10 +17,14 @@ defmodule ClaperWeb.FormLive.FormComponent do
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"id" => id}, socket) do
|
||||
form = Forms.get_form!(id)
|
||||
{:ok, _} = Forms.delete_form(socket.assigns.event_uuid, form)
|
||||
case Forms.get_form_for_event(id, socket.assigns.presentation_file.event_id) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply, socket |> push_navigate(to: socket.assigns.return_to)}
|
||||
form ->
|
||||
{:ok, _} = Forms.delete_form(socket.assigns.event_uuid, form)
|
||||
{:noreply, socket |> push_navigate(to: socket.assigns.return_to)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
||||
@@ -17,10 +17,14 @@ defmodule ClaperWeb.PollLive.FormComponent do
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"id" => id}, socket) do
|
||||
poll = Polls.get_poll!(id)
|
||||
{:ok, _} = Polls.delete_poll(socket.assigns.event_uuid, poll)
|
||||
case Polls.get_poll_for_event(id, socket.assigns.presentation_file.event_id) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply, socket |> push_navigate(to: socket.assigns.return_to)}
|
||||
poll ->
|
||||
{:ok, _} = Polls.delete_poll(socket.assigns.event_uuid, poll)
|
||||
{:noreply, socket |> push_navigate(to: socket.assigns.return_to)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
||||
@@ -17,10 +17,17 @@ defmodule ClaperWeb.QuizLive.QuizComponent do
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"id" => id}, socket) do
|
||||
quiz = Quizzes.get_quiz!(id, [:quiz_questions, quiz_questions: :quiz_question_opts])
|
||||
{:ok, _} = Quizzes.delete_quiz(socket.assigns.event.uuid, quiz)
|
||||
case Quizzes.get_quiz_for_event(id, socket.assigns.event.id, [
|
||||
:quiz_questions,
|
||||
quiz_questions: :quiz_question_opts
|
||||
]) do
|
||||
nil ->
|
||||
{:noreply, socket}
|
||||
|
||||
{:noreply, socket |> push_navigate(to: socket.assigns.return_to)}
|
||||
quiz ->
|
||||
{:ok, _} = Quizzes.delete_quiz(socket.assigns.event.uuid, quiz)
|
||||
{:noreply, socket |> push_navigate(to: socket.assigns.return_to)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
||||
@@ -138,5 +138,26 @@ defmodule Claper.EmbedsTest do
|
||||
embed = embed_fixture(%{presentation_file_id: presentation_file.id})
|
||||
assert %Ecto.Changeset{} = Embeds.change_embed(embed)
|
||||
end
|
||||
|
||||
test "get_embed_for_event/3 returns embed when it belongs to the event" do
|
||||
presentation_file = presentation_file_fixture()
|
||||
embed = embed_fixture(%{presentation_file_id: presentation_file.id})
|
||||
|
||||
fetched_embed = Embeds.get_embed_for_event(embed.id, presentation_file.event_id)
|
||||
assert fetched_embed.id == embed.id
|
||||
end
|
||||
|
||||
test "get_embed_for_event/3 returns nil when embed belongs to a different event" do
|
||||
presentation_file_a = presentation_file_fixture()
|
||||
presentation_file_b = presentation_file_fixture()
|
||||
embed = embed_fixture(%{presentation_file_id: presentation_file_a.id})
|
||||
|
||||
assert is_nil(Embeds.get_embed_for_event(embed.id, presentation_file_b.event_id))
|
||||
end
|
||||
|
||||
test "get_embed_for_event/3 returns nil for nonexistent embed id" do
|
||||
presentation_file = presentation_file_fixture()
|
||||
assert is_nil(Embeds.get_embed_for_event(-1, presentation_file.event_id))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -102,10 +102,63 @@ defmodule Claper.FormsTest do
|
||||
form = form_fixture(%{presentation_file_id: presentation_file.id})
|
||||
assert %Ecto.Changeset{} = Forms.change_form(form)
|
||||
end
|
||||
|
||||
test "get_form_for_event/3 returns form when it belongs to the event" do
|
||||
presentation_file = presentation_file_fixture()
|
||||
form = form_fixture(%{presentation_file_id: presentation_file.id})
|
||||
|
||||
fetched_form = Forms.get_form_for_event(form.id, presentation_file.event_id)
|
||||
assert fetched_form.id == form.id
|
||||
end
|
||||
|
||||
test "get_form_for_event/3 returns nil when form belongs to a different event" do
|
||||
presentation_file_a = presentation_file_fixture()
|
||||
presentation_file_b = presentation_file_fixture()
|
||||
form = form_fixture(%{presentation_file_id: presentation_file_a.id})
|
||||
|
||||
assert is_nil(Forms.get_form_for_event(form.id, presentation_file_b.event_id))
|
||||
end
|
||||
|
||||
test "get_form_for_event/3 returns nil for nonexistent form id" do
|
||||
presentation_file = presentation_file_fixture()
|
||||
assert is_nil(Forms.get_form_for_event(-1, presentation_file.event_id))
|
||||
end
|
||||
end
|
||||
|
||||
describe "form_submits" do
|
||||
import Claper.{FormsFixtures, PresentationsFixtures}
|
||||
import Claper.{FormsFixtures, PresentationsFixtures, AccountsFixtures}
|
||||
|
||||
test "get_form_submit_for_event/2 returns form submit when it belongs to the event" do
|
||||
presentation_file = presentation_file_fixture()
|
||||
form = form_fixture(%{presentation_file_id: presentation_file.id})
|
||||
user = user_fixture()
|
||||
|
||||
{:ok, form_submit} =
|
||||
Forms.create_form_submit(%{
|
||||
form_id: form.id,
|
||||
user_id: user.id,
|
||||
response: %{"Name" => "Test"}
|
||||
})
|
||||
|
||||
fetched = Forms.get_form_submit_for_event(form_submit.id, presentation_file.event_id)
|
||||
assert fetched.id == form_submit.id
|
||||
end
|
||||
|
||||
test "get_form_submit_for_event/2 returns nil when form submit belongs to a different event" do
|
||||
presentation_file_a = presentation_file_fixture()
|
||||
presentation_file_b = presentation_file_fixture()
|
||||
form = form_fixture(%{presentation_file_id: presentation_file_a.id})
|
||||
user = user_fixture()
|
||||
|
||||
{:ok, form_submit} =
|
||||
Forms.create_form_submit(%{
|
||||
form_id: form.id,
|
||||
user_id: user.id,
|
||||
response: %{"Name" => "Test"}
|
||||
})
|
||||
|
||||
assert is_nil(Forms.get_form_submit_for_event(form_submit.id, presentation_file_b.event_id))
|
||||
end
|
||||
|
||||
test "get_form_submit/2 returns the form_submit with given id and user id" do
|
||||
form_submit = form_submit_fixture()
|
||||
|
||||
@@ -106,6 +106,27 @@ defmodule Claper.PollsTest do
|
||||
poll = poll_fixture(%{presentation_file_id: presentation_file.id})
|
||||
assert %Ecto.Changeset{} = Polls.change_poll(poll)
|
||||
end
|
||||
|
||||
test "get_poll_for_event/2 returns poll when it belongs to the event" do
|
||||
presentation_file = presentation_file_fixture()
|
||||
poll = poll_fixture(%{presentation_file_id: presentation_file.id})
|
||||
|
||||
fetched_poll = Polls.get_poll_for_event(poll.id, presentation_file.event_id)
|
||||
assert fetched_poll.id == poll.id
|
||||
end
|
||||
|
||||
test "get_poll_for_event/2 returns nil when poll belongs to a different event" do
|
||||
presentation_file_a = presentation_file_fixture()
|
||||
presentation_file_b = presentation_file_fixture()
|
||||
poll = poll_fixture(%{presentation_file_id: presentation_file_a.id})
|
||||
|
||||
assert is_nil(Polls.get_poll_for_event(poll.id, presentation_file_b.event_id))
|
||||
end
|
||||
|
||||
test "get_poll_for_event/2 returns nil for nonexistent poll id" do
|
||||
presentation_file = presentation_file_fixture()
|
||||
assert is_nil(Polls.get_poll_for_event(-1, presentation_file.event_id))
|
||||
end
|
||||
end
|
||||
|
||||
describe "poll_opts" do
|
||||
|
||||
@@ -52,6 +52,27 @@ defmodule Claper.PostsTest do
|
||||
assert {:ok, %Post{}} = Posts.delete_post(post)
|
||||
assert_raise Ecto.NoResultsError, fn -> Posts.get_post!(post.uuid) end
|
||||
end
|
||||
|
||||
test "get_post_for_event/3 returns post when it belongs to the event" do
|
||||
event = event_fixture()
|
||||
post = post_fixture(%{event: event}, [:event])
|
||||
|
||||
fetched_post = Posts.get_post_for_event(post.uuid, event.id, [:event])
|
||||
assert fetched_post.id == post.id
|
||||
end
|
||||
|
||||
test "get_post_for_event/3 returns nil when post belongs to a different event" do
|
||||
event_a = event_fixture()
|
||||
event_b = event_fixture()
|
||||
post = post_fixture(%{event: event_a})
|
||||
|
||||
assert is_nil(Posts.get_post_for_event(post.uuid, event_b.id))
|
||||
end
|
||||
|
||||
test "get_post_for_event/3 returns nil for nonexistent post uuid" do
|
||||
event = event_fixture()
|
||||
assert is_nil(Posts.get_post_for_event(Ecto.UUID.generate(), event.id))
|
||||
end
|
||||
end
|
||||
|
||||
describe "reactions" do
|
||||
|
||||
@@ -196,6 +196,27 @@ defmodule Claper.QuizzesTest do
|
||||
assert length(responses) == 1
|
||||
end
|
||||
|
||||
test "get_quiz_for_event/3 returns quiz when it belongs to the event" do
|
||||
presentation_file = presentation_file_fixture()
|
||||
quiz = quiz_fixture(%{presentation_file: presentation_file})
|
||||
|
||||
fetched_quiz = Quizzes.get_quiz_for_event(quiz.id, presentation_file.event_id)
|
||||
assert fetched_quiz.id == quiz.id
|
||||
end
|
||||
|
||||
test "get_quiz_for_event/3 returns nil when quiz belongs to a different event" do
|
||||
presentation_file_a = presentation_file_fixture()
|
||||
presentation_file_b = presentation_file_fixture()
|
||||
quiz = quiz_fixture(%{presentation_file: presentation_file_a})
|
||||
|
||||
assert is_nil(Quizzes.get_quiz_for_event(quiz.id, presentation_file_b.event_id))
|
||||
end
|
||||
|
||||
test "get_quiz_for_event/3 returns nil for nonexistent quiz id" do
|
||||
presentation_file = presentation_file_fixture()
|
||||
assert is_nil(Quizzes.get_quiz_for_event(-1, presentation_file.event_id))
|
||||
end
|
||||
|
||||
test "submit_quiz/4 with user and duplicate opts deduplicates by id" do
|
||||
quiz = quiz_fixture()
|
||||
user = user_fixture()
|
||||
|
||||
Reference in New Issue
Block a user