Skip to content

Commit

Permalink
Catch wrong UUID and missing brainstorming (#508)
Browse files Browse the repository at this point in the history
  • Loading branch information
JannikStreek authored Dec 10, 2024
1 parent 41cdb8f commit 7d64088
Show file tree
Hide file tree
Showing 12 changed files with 132 additions and 65 deletions.
52 changes: 36 additions & 16 deletions lib/mindwendel/brainstormings.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,29 +51,46 @@ defmodule Mindwendel.Brainstormings do
@doc """
Gets a single brainstorming.
Raises `Ecto.NoResultsError` if the Brainstorming does not exist.
Returns an error tuple instead of raising exceptions to handle invalid UUIDs gracefully,
particularly important for initial brainstorming fetches that may receive spam requests.
## Examples
iex> get_brainstorming!("0323906b-b496-4778-ae67-1dd779d3de3c")
iex> get_brainstorming("0323906b-b496-4778-ae67-1dd779d3de3c")
%Brainstorming{ ... }
iex> get_brainstorming!("0323906b-b496-4778-ae67-1dd779d3de3c")
** (Ecto.NoResultsError)
iex> get_brainstorming("0323906b-b496-4778-ae67-1dd779d3de3c")
{:error, :not_found}
iex> get_brainstorming!("not_a_valid_uuid_string")
** (Ecto.Query.CastError)
iex> get_brainstorming("not_a_valid_uuid_string")
{:error, :invalid_uuid}
"""
# See https://stackoverflow.com/questions/53802091/elixir-uuid-how-to-handle-500-error-when-uuid-doesnt-match
def get_brainstorming!(id) do
Repo.get!(Brainstorming, id)
|> Repo.preload([
:users,
:moderating_users,
labels: from(idea_label in IdeaLabel, order_by: idea_label.position_order)
])
|> update_last_accessed_at
def get_brainstorming(id) do
case Ecto.UUID.cast(id) do
{:ok, id} -> get_brainstorming_with_valid_uuid(id)
:error -> {:error, :invalid_uuid}
end
end

# No uuid check here, has to be done before
defp get_brainstorming_with_valid_uuid(id) do
case Repo.get(Brainstorming, id) do
nil ->
{:error, :not_found}

brainstorming ->
preloaded_brainstorming =
brainstorming
|> Repo.preload([
:users,
:moderating_users,
labels: from(idea_label in IdeaLabel, order_by: idea_label.position_order)
])
|> update_last_accessed_at()

{:ok, preloaded_brainstorming}
end
end

@doc """
Expand Down Expand Up @@ -240,7 +257,10 @@ defmodule Mindwendel.Brainstormings do
"""
def validate_admin_secret(brainstorming, admin_secret_id) do
brainstorming.admin_url_id == admin_secret_id
case brainstorming.admin_url_id do
nil -> false
admin_url_id -> admin_url_id == admin_secret_id
end
end

@doc """
Expand Down
2 changes: 1 addition & 1 deletion lib/mindwendel/lanes.ex
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ defmodule Mindwendel.Lanes do
"""
def get_lanes_for_brainstorming_with_labels_filtered(id) do
brainstorming = Brainstormings.get_brainstorming!(id)
{:ok, brainstorming} = Brainstormings.get_brainstorming(id)

filter_label =
if length(brainstorming.filter_labels_ids) > 0,
Expand Down
54 changes: 28 additions & 26 deletions lib/mindwendel_web/live/brainstorming_live/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ defmodule MindwendelWeb.BrainstormingLive.Show do

alias Mindwendel.Accounts
alias Mindwendel.Brainstormings
alias Mindwendel.FeatureFlag
alias Mindwendel.Lanes
alias Mindwendel.Ideas
alias Mindwendel.Brainstormings.Idea
Expand All @@ -16,27 +15,36 @@ defmodule MindwendelWeb.BrainstormingLive.Show do
# If the admin secret in the URL after the hash (only available inside the client session) is given, add the user as moderating user to the brainstorming.
# If not, add the user as normal user.
current_user_id = Mindwendel.Services.SessionService.get_current_user_id(session)
brainstorming = Brainstormings.get_brainstorming!(id)
admin_secret = get_connect_params(socket)["adminSecret"]

if Brainstormings.validate_admin_secret(brainstorming, admin_secret) do
Accounts.add_moderating_user(brainstorming, current_user_id)
case Brainstormings.get_brainstorming(id) do
{:ok, brainstorming} ->
admin_secret = get_connect_params(socket)["adminSecret"]

if Brainstormings.validate_admin_secret(brainstorming, admin_secret) do
Accounts.add_moderating_user(brainstorming, current_user_id)
end

Accounts.merge_brainstorming_user(brainstorming, current_user_id)

lanes = Lanes.get_lanes_for_brainstorming_with_labels_filtered(id)
# load the user, also for permissions of brainstormings
current_user = Mindwendel.Accounts.get_user(current_user_id)

{
:ok,
socket
|> assign(:brainstorming, brainstorming)
|> assign(:lanes, lanes)
|> assign(:current_user, current_user)
|> assign(:inspiration, Mindwendel.Help.random_inspiration())
}

{:error, _} ->
{:ok,
socket
|> put_flash(:error, gettext("Brainstorming not found"))
|> push_navigate(to: "/")}
end

Accounts.merge_brainstorming_user(brainstorming, current_user_id)

lanes = Lanes.get_lanes_for_brainstorming_with_labels_filtered(id)
# load the user, also for permissions of brainstormings
current_user = Mindwendel.Accounts.get_user(current_user_id)

{
:ok,
socket
|> assign(:brainstorming, brainstorming)
|> assign(:lanes, lanes)
|> assign(:current_user, current_user)
|> assign(:inspiration, inspiration())
}
end

def mount(%{"brainstorming_id" => brainstorming_id, "idea_id" => _idea_id}, session, socket) do
Expand Down Expand Up @@ -180,10 +188,4 @@ defmodule MindwendelWeb.BrainstormingLive.Show do
socket
|> assign(:page_title, socket.assigns.brainstorming.name)
end

defp inspiration do
if FeatureFlag.enabled?(:feature_brainstorming_teasers) do
Mindwendel.Help.random_inspiration()
end
end
end
6 changes: 3 additions & 3 deletions lib/mindwendel_web/live/lane_live/index_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ defmodule MindwendelWeb.LaneLive.IndexComponent do
},
socket
) do
brainstorming = Brainstormings.get_brainstorming!(brainstorming_id)
{:ok, brainstorming} = Brainstormings.get_brainstorming(brainstorming_id)

if has_move_permission(brainstorming, socket.assigns.current_user) do
Ideas.update_ideas_for_brainstorming_by_user_move(
Expand Down Expand Up @@ -62,7 +62,7 @@ defmodule MindwendelWeb.LaneLive.IndexComponent do
end

def handle_event("sort_by_likes", %{"id" => id, "lane-id" => lane_id}, socket) do
brainstorming = Brainstormings.get_brainstorming!(id)
{:ok, brainstorming} = Brainstormings.get_brainstorming(id)

if has_move_permission(brainstorming, socket.assigns.current_user) do
Ideas.update_ideas_for_brainstorming_by_likes(id, lane_id)
Expand All @@ -72,7 +72,7 @@ defmodule MindwendelWeb.LaneLive.IndexComponent do
end

def handle_event("sort_by_label", %{"id" => id, "lane-id" => lane_id}, socket) do
brainstorming = Brainstormings.get_brainstorming!(id)
{:ok, brainstorming} = Brainstormings.get_brainstorming(id)

if has_move_permission(brainstorming, socket.assigns.current_user) do
Ideas.update_ideas_for_brainstorming_by_labels(id, lane_id)
Expand Down
13 changes: 9 additions & 4 deletions priv/gettext/de/LC_MESSAGES/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ msgstr "Wie können wir ..."
msgid "Ready?"
msgstr "Fertig?"

#: lib/mindwendel_web/live/brainstorming_live/show.ex:175
#: lib/mindwendel_web/live/brainstorming_live/show.ex:184
#, elixir-autogen, elixir-format
msgid "%{name} - Edit"
msgstr "%{name} - Editieren"

#: lib/mindwendel_web/live/brainstorming_live/show.ex:152
#: lib/mindwendel_web/live/brainstorming_live/show.ex:161
#, elixir-autogen, elixir-format
msgid "%{name} - New Idea"
msgstr "%{name} - Neue Idee"
Expand Down Expand Up @@ -299,7 +299,7 @@ msgstr "Bist du sicher, dass das Brainstorming geleert werden soll?"
msgid "Empty brainstorming"
msgstr "Leere das Brainstorming"

#: lib/mindwendel_web/live/live_helpers.ex:29
#: lib/mindwendel_web/live/live_helpers.ex:30
#, elixir-autogen, elixir-format, fuzzy
msgid "Brainstorming will be deleted %{days}"
msgstr "Brainstorming wird gelöscht %{days}"
Expand Down Expand Up @@ -385,7 +385,7 @@ msgstr "Löschen"
msgid "Type the label name"
msgstr "Gebe dem Label einen Namen"

#: lib/mindwendel_web/live/brainstorming_live/show.ex:162
#: lib/mindwendel_web/live/brainstorming_live/show.ex:171
#, elixir-autogen, elixir-format, fuzzy
msgid "%{name} - New Lane"
msgstr "%{name} - Neue Idee"
Expand Down Expand Up @@ -562,3 +562,8 @@ msgstr "Detailansicht"
#, elixir-autogen, elixir-format
msgid "Give moderating permissions"
msgstr "Änderungen erlauben"

#: lib/mindwendel_web/live/brainstorming_live/show.ex:45
#, elixir-autogen, elixir-format, fuzzy
msgid "Brainstorming not found"
msgstr "Brainstorming konnte nicht gefunden werden"
11 changes: 8 additions & 3 deletions priv/gettext/default.pot
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ msgstr ""
msgid "Ready?"
msgstr ""

#: lib/mindwendel_web/live/brainstorming_live/show.ex:176
#: lib/mindwendel_web/live/brainstorming_live/show.ex:184
#, elixir-autogen, elixir-format
msgid "%{name} - Edit"
msgstr ""

#: lib/mindwendel_web/live/brainstorming_live/show.ex:153
#: lib/mindwendel_web/live/brainstorming_live/show.ex:161
#, elixir-autogen, elixir-format
msgid "%{name} - New Idea"
msgstr ""
Expand Down Expand Up @@ -384,7 +384,7 @@ msgstr ""
msgid "Type the label name"
msgstr ""

#: lib/mindwendel_web/live/brainstorming_live/show.ex:163
#: lib/mindwendel_web/live/brainstorming_live/show.ex:171
#, elixir-autogen, elixir-format
msgid "%{name} - New Lane"
msgstr ""
Expand Down Expand Up @@ -561,3 +561,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Give moderating permissions"
msgstr ""

#: lib/mindwendel_web/live/brainstorming_live/show.ex:45
#, elixir-autogen, elixir-format
msgid "Brainstorming not found"
msgstr ""
13 changes: 9 additions & 4 deletions priv/gettext/en/LC_MESSAGES/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ msgstr ""
msgid "Ready?"
msgstr ""

#: lib/mindwendel_web/live/brainstorming_live/show.ex:175
#: lib/mindwendel_web/live/brainstorming_live/show.ex:184
#, elixir-autogen, elixir-format
msgid "%{name} - Edit"
msgstr ""

#: lib/mindwendel_web/live/brainstorming_live/show.ex:152
#: lib/mindwendel_web/live/brainstorming_live/show.ex:161
#, elixir-autogen, elixir-format
msgid "%{name} - New Idea"
msgstr ""
Expand Down Expand Up @@ -299,7 +299,7 @@ msgstr "Are you sure that you want to delete this brainstorming?"
msgid "Empty brainstorming"
msgstr ""

#: lib/mindwendel_web/live/live_helpers.ex:29
#: lib/mindwendel_web/live/live_helpers.ex:30
#, elixir-autogen, elixir-format, fuzzy
msgid "Brainstorming will be deleted %{days}"
msgstr ""
Expand Down Expand Up @@ -385,7 +385,7 @@ msgstr ""
msgid "Type the label name"
msgstr ""

#: lib/mindwendel_web/live/brainstorming_live/show.ex:162
#: lib/mindwendel_web/live/brainstorming_live/show.ex:171
#, elixir-autogen, elixir-format, fuzzy
msgid "%{name} - New Lane"
msgstr ""
Expand Down Expand Up @@ -562,3 +562,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Give moderating permissions"
msgstr ""

#: lib/mindwendel_web/live/brainstorming_live/show.ex:45
#, elixir-autogen, elixir-format, fuzzy
msgid "Brainstorming not found"
msgstr ""
4 changes: 2 additions & 2 deletions test/mindwendel/accounts_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ defmodule Mindwendel.AccountsTest do
assert brainstorming_moderatoring_user.user_id == user.id
assert brainstorming_moderatoring_user.brainstorming_id == brainstorming.id

assert [%User{id: ^user_id}] =
Brainstormings.get_brainstorming!(brainstorming.id).moderating_users
{:ok, brainstorming} = Brainstormings.get_brainstorming(brainstorming.id)
assert [%User{id: ^user_id}] = brainstorming.moderating_users
end

test "responds with an error when brainstorming already contains the moderating user", %{
Expand Down
32 changes: 29 additions & 3 deletions test/mindwendel/brainstormings_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,37 @@ defmodule Mindwendel.BrainstormingsTest do
}
end

describe "get_brainstorming" do
test "returns the brainstorming", %{brainstorming: brainstorming} do
{:ok, loaded_brainstorming} = Brainstormings.get_brainstorming(brainstorming.id)
assert loaded_brainstorming.id == brainstorming.id
end

test "returns an error for the wrong uuid" do
assert {:error, :invalid_uuid} == Brainstormings.get_brainstorming("invalid_uuid")
end

test "returns an error for a missing brainstorming" do
assert {:error, :not_found} ==
Brainstormings.get_brainstorming("8a4f5d37-28c4-424e-ac4a-5637a41486c4")
end

test "returns an error for a nil value" do
assert {:error, :invalid_uuid} ==
Brainstormings.get_brainstorming(nil)
end
end

describe "validate_admin_secret" do
test "returns false if secret is wrong", %{brainstorming: brainstorming} do
refute Brainstormings.validate_admin_secret(brainstorming, "wrong")
end

test "returns false if secret is nil", %{brainstorming: brainstorming} do
brainstorming = %{brainstorming | admin_url_id: nil}
refute Brainstormings.validate_admin_secret(brainstorming, nil)
end

test "returns true if secret is correct", %{brainstorming: brainstorming} do
assert Brainstormings.validate_admin_secret(brainstorming, brainstorming.admin_url_id)
end
Expand Down Expand Up @@ -253,7 +279,7 @@ defmodule Mindwendel.BrainstormingsTest do
assert Enum.count(brainstorming.ideas) == 1
Brainstormings.empty(brainstorming)
# reload brainstorming:
brainstorming = Brainstormings.get_brainstorming!(brainstorming.id)
{:ok, brainstorming} = Brainstormings.get_brainstorming(brainstorming.id)
brainstorming = brainstorming |> Repo.preload([:ideas, :lanes])
assert Enum.empty?(brainstorming.lanes)
end
Expand Down Expand Up @@ -302,8 +328,8 @@ defmodule Mindwendel.BrainstormingsTest do
assert Enum.count(other_brainstorming.ideas) == 1
Brainstormings.empty(brainstorming)
# reload brainstorming:
brainstorming = Brainstormings.get_brainstorming!(brainstorming.id) |> Repo.preload(:lanes)
brainstorming = brainstorming |> Repo.preload([:ideas])
{:ok, brainstorming} = Brainstormings.get_brainstorming(brainstorming.id)
brainstorming = brainstorming |> Repo.preload([:ideas, :lanes])
other_brainstorming = other_brainstorming |> Repo.preload([:ideas])
assert Enum.empty?(brainstorming.lanes)
assert Enum.count(other_brainstorming.lanes) == 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ defmodule MindwendelWeb.Admin.BrainstormingLive.EditTest do
|> form("#form-labels", %{brainstorming: %{labels: %{"0": %{name: "new label"}}}})
|> render_change()

assert Brainstormings.get_brainstorming!(brainstorming.id).labels
{:ok, brainstorming} = Brainstormings.get_brainstorming(brainstorming.id)

assert brainstorming.labels
|> Enum.map(fn a -> a.name end)
|> Enum.member?("new label")
end
Expand Down
4 changes: 3 additions & 1 deletion test/mindwendel_web/live/brainstorming_live_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,10 @@ defmodule MindwendelWeb.BrainstormingLiveTest do
|> element(".btn[data-testid=\"#{selected_ideal_label.id}\"]")
|> render_click()

{:ok, brainstorming} = Brainstormings.get_brainstorming(brainstorming.id)

assert(
Brainstormings.get_brainstorming!(brainstorming.id).filter_labels_ids == [
brainstorming.filter_labels_ids == [
selected_ideal_label.id
]
)
Expand Down
Loading

0 comments on commit 7d64088

Please sign in to comment.