diff --git a/lib/mindwendel/brainstormings.ex b/lib/mindwendel/brainstormings.ex index 3a1bb74b..3d941be6 100644 --- a/lib/mindwendel/brainstormings.ex +++ b/lib/mindwendel/brainstormings.ex @@ -98,6 +98,10 @@ defmodule Mindwendel.Brainstormings do end end + def get_bare_brainstorming!(id) do + Repo.get!(Brainstorming, id) + end + @doc """ Gets a single brainstorming with the admin url id """ diff --git a/lib/mindwendel/brainstormings/idea_idea_label.ex b/lib/mindwendel/brainstormings/idea_idea_label.ex index ccb2bdf7..865ffadb 100644 --- a/lib/mindwendel/brainstormings/idea_idea_label.ex +++ b/lib/mindwendel/brainstormings/idea_idea_label.ex @@ -24,4 +24,13 @@ defmodule Mindwendel.Brainstormings.IdeaIdeaLabel do name: :idea_idea_labels_idea_id_idea_label_id_index ) end + + def bare_creation_changeset(idea_idea_label \\ %__MODULE__{}, attrs) do + idea_idea_label + |> cast(attrs, [:idea_id, :idea_label_id]) + |> validate_required([:idea_id, :idea_label_id]) + |> unique_constraint([:idea_id, :idea_label_id], + name: :idea_idea_labels_idea_id_idea_label_id_index + ) + end end diff --git a/lib/mindwendel/idea_labels.ex b/lib/mindwendel/idea_labels.ex index 5e85f546..be4f479d 100644 --- a/lib/mindwendel/idea_labels.ex +++ b/lib/mindwendel/idea_labels.ex @@ -28,29 +28,24 @@ defmodule Mindwendel.IdeaLabels do nil end - def add_idea_label_to_idea(%Idea{} = idea, %IdeaLabel{} = idea_label) do - idea = Repo.preload(idea, :idea_labels) - - idea_labels = - (idea.idea_labels ++ [idea_label]) - |> Enum.map(&Ecto.Changeset.change/1) - + # As the broadcast results in a full reload of the ideas, we don't need to actually update + # the idea struct, a new association is enough + def add_idea_label_to_idea(idea, idea_label_id) do result = - idea - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_assoc(:idea_labels, idea_labels) - |> Repo.update() + %{idea_id: idea.id, idea_label_id: idea_label_id} + |> IdeaIdeaLabel.bare_creation_changeset() + |> Repo.insert() Lanes.broadcast_lanes_update(idea.brainstorming_id) result end - def remove_idea_label_from_idea(%Idea{} = idea, %IdeaLabel{} = idea_label) do + def remove_idea_label_from_idea(%Idea{} = idea, idea_label_id) do result = from(idea_idea_label in IdeaIdeaLabel, where: idea_idea_label.idea_id == ^idea.id and - idea_idea_label.idea_label_id == ^idea_label.id + idea_idea_label.idea_label_id == ^idea_label_id ) |> Repo.delete_all() diff --git a/lib/mindwendel/lanes.ex b/lib/mindwendel/lanes.ex index b1b35d14..8121cdd1 100644 --- a/lib/mindwendel/lanes.ex +++ b/lib/mindwendel/lanes.ex @@ -72,10 +72,7 @@ defmodule Mindwendel.Lanes do def get_lanes_for_brainstorming_with_labels_filtered(id) do {:ok, brainstorming} = Brainstormings.get_brainstorming(id) - filter_label = - if length(brainstorming.filter_labels_ids) > 0, - do: %{filter_labels_ids: brainstorming.filter_labels_ids}, - else: %{} + filter_label = %{filter_labels_ids: brainstorming.filter_labels_ids} get_lanes_for_brainstorming(id, filter_label) end @@ -89,7 +86,7 @@ defmodule Mindwendel.Lanes do [%Lane{}, ...] """ - def get_lanes_for_brainstorming(id, filters \\ %{}) do + def get_lanes_for_brainstorming(id, filters \\ %{filter_labels_ids: []}) do lane_query = from lane in Lane, where: lane.brainstorming_id == ^id, @@ -105,6 +102,10 @@ defmodule Mindwendel.Lanes do |> Repo.preload(ideas: {ideas_advanced_query, [:link, :likes, :idea_labels, :files]}) end + defp build_ideas_query_with_filter(%{filter_labels_ids: []}) do + from(idea in Idea) + end + defp build_ideas_query_with_filter(%{filter_labels_ids: filter_labels_ids}) do distinct_ideas = from idea in Idea, @@ -118,10 +119,6 @@ defmodule Mindwendel.Lanes do ) end - defp build_ideas_query_with_filter(%{} = _filters) do - from(idea in Idea) - end - @doc """ Creates a lane. diff --git a/lib/mindwendel/repo.ex b/lib/mindwendel/repo.ex index a26ea71d..622ddd21 100644 --- a/lib/mindwendel/repo.ex +++ b/lib/mindwendel/repo.ex @@ -2,4 +2,8 @@ defmodule Mindwendel.Repo do use Ecto.Repo, otp_app: :mindwendel, adapter: Ecto.Adapters.Postgres + + def count(query) do + aggregate(query, :count) + end end diff --git a/lib/mindwendel_web/live/idea_live/card_component.ex b/lib/mindwendel_web/live/idea_live/card_component.ex index 9a3c1b55..8f934c7c 100644 --- a/lib/mindwendel_web/live/idea_live/card_component.ex +++ b/lib/mindwendel_web/live/idea_live/card_component.ex @@ -6,8 +6,8 @@ defmodule MindwendelWeb.IdeaLive.CardComponent do alias Mindwendel.Likes @impl true - def handle_event("delete_idea", %{"id" => id}, socket) do - idea = Ideas.get_idea!(id) + def handle_event("delete_idea", _params, socket) do + idea = socket.assigns.idea %{current_user: current_user, brainstorming: brainstorming} = socket.assigns @@ -19,14 +19,14 @@ defmodule MindwendelWeb.IdeaLive.CardComponent do {:noreply, socket} end - def handle_event("like", %{"id" => id}, socket) do - Likes.add_like(id, socket.assigns.current_user.id) + def handle_event("like", _params, socket) do + Likes.add_like(socket.assigns.idea.id, socket.assigns.current_user.id) {:noreply, socket} end - def handle_event("unlike", %{"id" => id}, socket) do - Likes.delete_like(id, socket.assigns.current_user.id) + def handle_event("unlike", _params, socket) do + Likes.delete_like(socket.assigns.idea.id, socket.assigns.current_user.id) {:noreply, socket} end @@ -34,35 +34,22 @@ defmodule MindwendelWeb.IdeaLive.CardComponent do def handle_event( "add_idea_label_to_idea", %{ - "idea-id" => idea_id, "idea-label-id" => idea_label_id }, socket ) do - idea = Ideas.get_idea!(idea_id) - idea_label = IdeaLabels.get_idea_label(idea_label_id) - - case(IdeaLabels.add_idea_label_to_idea(idea, idea_label)) do - {:ok, _idea} -> - {:noreply, socket} - - {:error, _changeset} -> - {:noreply, socket} - end + IdeaLabels.add_idea_label_to_idea(socket.assigns.idea, idea_label_id) + {:noreply, socket} end def handle_event( "remove_idea_label_from_idea", %{ - "idea-id" => idea_id, "idea-label-id" => idea_label_id }, socket ) do - idea = Ideas.get_idea!(idea_id) - idea_label = IdeaLabels.get_idea_label(idea_label_id) - - IdeaLabels.remove_idea_label_from_idea(idea, idea_label) + IdeaLabels.remove_idea_label_from_idea(socket.assigns.idea, idea_label_id) {:noreply, socket} end end diff --git a/lib/mindwendel_web/live/idea_live/card_component.html.heex b/lib/mindwendel_web/live/idea_live/card_component.html.heex index 07a84bee..ad3811a8 100644 --- a/lib/mindwendel_web/live/idea_live/card_component.html.heex +++ b/lib/mindwendel_web/live/idea_live/card_component.html.heex @@ -13,7 +13,6 @@ class="float-end ms-3 mb-3" phx-click="delete_idea" phx-target={@myself} - phx-value-id={@idea.id} title={gettext("Delete idea")} data-confirm={gettext("Are you sure you want to delete this idea?")} > @@ -97,7 +96,6 @@ data-testid={brainstorming_idea_label.id} phx-click="add_idea_label_to_idea" phx-target={@myself} - phx-value-idea-id={@idea.id} title={"Label #{brainstorming_idea_label.name}"} phx-value-idea-label-id={brainstorming_idea_label.id} > @@ -116,7 +114,6 @@ data-testid={brainstorming_idea_label.id} phx-click="remove_idea_label_from_idea" phx-target={@myself} - phx-value-idea-id={@idea.id} title={"Label #{brainstorming_idea_label.name}"} phx-value-idea-label-id={brainstorming_idea_label.id} > @@ -145,11 +142,11 @@ {length(@idea.likes)} <%= if Mindwendel.Likes.exists_user_in_likes?(@idea.likes, @current_user.id) do %> - <.link phx-click="unlike" phx-target={@myself} phx-value-id={@idea.id} title="Unlike"> + <.link phx-click="unlike" phx-target={@myself} title="Unlike"> <% else %> - <.link phx-click="like" phx-target={@myself} phx-value-id={@idea.id} title="Like"> + <.link phx-click="like" phx-target={@myself} title="Like"> <% end %> diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index a8d6e46d..9e168660 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -36,7 +36,7 @@ msgid "%{name} - New Idea" msgstr "" #: lib/mindwendel_web/live/comment_live/show_component.html.heex:22 -#: lib/mindwendel_web/live/idea_live/card_component.html.heex:18 +#: lib/mindwendel_web/live/idea_live/card_component.html.heex:17 #, elixir-autogen, elixir-format msgid "Are you sure you want to delete this idea?" msgstr "" @@ -195,7 +195,7 @@ msgstr "" #: lib/mindwendel_web/controllers/admin/brainstorming_html/export.html.heex:3 #: lib/mindwendel_web/live/comment_live/show_component.html.heex:40 -#: lib/mindwendel_web/live/idea_live/card_component.html.heex:85 +#: lib/mindwendel_web/live/idea_live/card_component.html.heex:84 #, elixir-autogen, elixir-format msgid "By" msgstr "" @@ -451,13 +451,13 @@ msgstr "" msgid "No lanes available" msgstr "" -#: lib/mindwendel_web/live/idea_live/card_component.html.heex:25 +#: lib/mindwendel_web/live/idea_live/card_component.html.heex:24 #, elixir-autogen, elixir-format msgid "Edit idea" msgstr "" #: lib/mindwendel_web/live/comment_live/show_component.html.heex:30 -#: lib/mindwendel_web/live/idea_live/card_component.html.heex:17 +#: lib/mindwendel_web/live/idea_live/card_component.html.heex:16 #, elixir-autogen, elixir-format msgid "Delete idea" msgstr "" @@ -472,7 +472,7 @@ msgstr "" msgid "Additional Attachment" msgstr "" -#: lib/mindwendel_web/live/idea_live/card_component.html.heex:75 +#: lib/mindwendel_web/live/idea_live/card_component.html.heex:74 #: lib/mindwendel_web/live/idea_live/form_component.html.heex:43 #: lib/mindwendel_web/live/idea_live/show_component.html.heex:27 #, elixir-autogen, elixir-format @@ -529,8 +529,8 @@ msgstr "" msgid "No comments available" msgstr "" -#: lib/mindwendel_web/live/idea_live/card_component.html.heex:33 -#: lib/mindwendel_web/live/idea_live/card_component.html.heex:140 +#: lib/mindwendel_web/live/idea_live/card_component.html.heex:32 +#: lib/mindwendel_web/live/idea_live/card_component.html.heex:137 #, elixir-autogen, elixir-format msgid "Show idea" msgstr "" diff --git a/test/mindwendel/brainstormings_test.exs b/test/mindwendel/brainstormings_test.exs index 16772359..174eacef 100644 --- a/test/mindwendel/brainstormings_test.exs +++ b/test/mindwendel/brainstormings_test.exs @@ -322,8 +322,8 @@ defmodule Mindwendel.BrainstormingsTest do like = Factory.insert!(:like, idea: idea) - {:ok, idea} = - IdeaLabels.add_idea_label_to_idea(idea, Enum.at(brainstorming.labels, 0)) + {:ok, _idea_idea_label} = + IdeaLabels.add_idea_label_to_idea(idea, Enum.at(brainstorming.labels, 0).id) idea = idea |> Repo.preload([:idea_labels]) diff --git a/test/mindwendel/idea_labels_test.exs b/test/mindwendel/idea_labels_test.exs index 83991037..075cefe5 100644 --- a/test/mindwendel/idea_labels_test.exs +++ b/test/mindwendel/idea_labels_test.exs @@ -9,7 +9,7 @@ defmodule Mindwendel.IdeaLabelsTest do setup do brainstorming = Factory.insert!(:brainstorming, %{labels: [Factory.build(:idea_label)]}) - idea_label = brainstorming.labels |> Enum.at(0) + [idea_label] = brainstorming.labels lane = Enum.at(brainstorming.lanes, 0) idea = Factory.insert!(:idea, %{brainstorming: brainstorming, lane: lane}) @@ -18,16 +18,16 @@ defmodule Mindwendel.IdeaLabelsTest do describe "#add_idea_label_to_idea" do test "adds IdeaLabel to Idea", %{idea_label: idea_label, idea: idea} do - {:ok, idea_changed} = IdeaLabels.add_idea_label_to_idea(idea, idea_label) + {:ok, _idea_idea_label} = IdeaLabels.add_idea_label_to_idea(idea, idea_label.id) - assert idea_changed.idea_labels |> Enum.count() == 1 - assert Repo.all(IdeaIdeaLabel) |> Enum.count() == 1 + assert [idea_label] == labels_of(idea) + assert Repo.count(IdeaIdeaLabel) == 1 end test "creates one IdeaIdeaLabel", %{idea_label: idea_label, idea: idea} do - {:ok, _idea_changed} = IdeaLabels.add_idea_label_to_idea(idea, idea_label) + {:ok, _idea_idea_label} = IdeaLabels.add_idea_label_to_idea(idea, idea_label.id) - assert Repo.all(IdeaIdeaLabel) |> Enum.count() == 1 + assert Repo.count(IdeaIdeaLabel) == 1 idea_idea_label = Repo.one(IdeaIdeaLabel) assert idea_idea_label.idea_label_id == idea_label.id @@ -35,26 +35,29 @@ defmodule Mindwendel.IdeaLabelsTest do end test "does not create additional IdeaLabel", %{idea_label: idea_label, idea: idea} do - assert Repo.all(IdeaLabel) |> Enum.count() == 1 + assert Repo.count(IdeaLabel) == 1 - {:ok, _idea_changed} = IdeaLabels.add_idea_label_to_idea(idea, idea_label) + {:ok, _idea_idea_label} = IdeaLabels.add_idea_label_to_idea(idea, idea_label.id) - assert Repo.all(IdeaLabel) |> Enum.count() == 1 + assert Repo.count(IdeaLabel) == 1 assert Repo.one(IdeaLabel) == idea_label end @tag :skip test "does not add the same IdeaLabel twice to Idea", %{idea_label: idea_label, idea: idea} do # Calling this method twice does not fail and does not create duplicates - {:ok, idea_after_method_call_1} = IdeaLabels.add_idea_label_to_idea(idea, idea_label) - {:ok, idea_after_method_call_2} = IdeaLabels.add_idea_label_to_idea(idea, idea_label) + {:ok, idea_idea_label_after_method_call_1} = + IdeaLabels.add_idea_label_to_idea(idea, idea_label.id) + + {:ok, idea_idea_label_after_method_call_2} = + IdeaLabels.add_idea_label_to_idea(idea, idea_label.id) # There should still be only one IdeaIdeaLabel - assert Repo.all(IdeaIdeaLabel) |> Enum.count() == 1 + assert Repo.count(IdeaIdeaLabel) == 1 - assert Repo.all(IdeaLabel) |> Enum.count() == 1 + assert Repo.count(IdeaLabel) == 1 - assert idea_after_method_call_1 == idea_after_method_call_2 + assert idea_idea_label_after_method_call_1 == idea_idea_label_after_method_call_2 end @tag :skip @@ -68,7 +71,7 @@ defmodule Mindwendel.IdeaLabelsTest do }) {:error, _changeset} = - IdeaLabels.add_idea_label_to_idea(idea, idea_label_from_another_brainstorming) + IdeaLabels.add_idea_label_to_idea(idea, idea_label_from_another_brainstorming.id) end @tag :skip @@ -88,16 +91,16 @@ defmodule Mindwendel.IdeaLabelsTest do @tag :skip test "does not create idea_labels without brainstorming", %{idea: idea} do - assert Repo.all(IdeaIdeaLabel) |> Enum.count() == 0 + assert Repo.count(IdeaIdeaLabel) == 0 idea = Repo.preload(idea, [:idea_labels, :idea_idea_labels]) idea_label = idea.brainstorming.labels |> Enum.at(0) - IdeaLabels.add_idea_label_to_idea(idea, idea_label) + IdeaLabels.add_idea_label_to_idea(idea, idea_label.id) - assert Repo.all(IdeaIdeaLabel) |> Enum.count() == 1 + assert Repo.count(IdeaIdeaLabel) == 1 assert Repo.one(IdeaIdeaLabel).idea_id == idea.id assert Repo.one(IdeaIdeaLabel).idea_label_id == idea_label.id - assert Repo.all(IdeaLabel) |> Enum.count() == 5 + assert Repo.count(IdeaLabel) == 5 assert Enum.empty?( Repo.all( @@ -110,13 +113,14 @@ defmodule Mindwendel.IdeaLabelsTest do describe "#delete_idea_label_from_idea" do setup %{idea_label: idea_label, idea: idea} do - {:ok, idea} = IdeaLabels.add_idea_label_to_idea(idea, idea_label) - assert Repo.all(IdeaIdeaLabel) |> Enum.count() == 1 + {:ok, _idea_idea_label} = IdeaLabels.add_idea_label_to_idea(idea, idea_label.id) + idea = idea |> Repo.reload!() |> Repo.preload(:idea_labels) + assert Repo.count(IdeaIdeaLabel) == 1 %{idea: idea} end test "removes successfully IdeaLabel from Idea", %{idea_label: idea_label, idea: idea} do - IdeaLabels.remove_idea_label_from_idea(idea, idea_label) + IdeaLabels.remove_idea_label_from_idea(idea, idea_label.id) assert Enum.empty?(Repo.all(IdeaIdeaLabel)) end @@ -125,10 +129,18 @@ defmodule Mindwendel.IdeaLabelsTest do idea: idea } do # Calling this method twice does not fail - IdeaLabels.remove_idea_label_from_idea(idea, idea_label) - IdeaLabels.remove_idea_label_from_idea(idea, idea_label) + IdeaLabels.remove_idea_label_from_idea(idea, idea_label.id) + IdeaLabels.remove_idea_label_from_idea(idea, idea_label.id) assert Enum.empty?(Repo.all(IdeaIdeaLabel)) end end + + defp labels_of(idea_record) do + Repo.all( + from idea_label in IdeaLabel, + join: idea in assoc(idea_label, :ideas), + where: idea.id == ^idea_record.id + ) + end end