Skip to content

Commit

Permalink
chore: refactoring opportunities (#275)
Browse files Browse the repository at this point in the history
* chore: move session service to mindwendel.services, instead of mindwendel_service
* chore: split brainstorming repository into multipler smaller repositories
  • Loading branch information
nwittstruck authored Mar 28, 2024
1 parent 7e773ea commit 6ccd5b7
Show file tree
Hide file tree
Showing 26 changed files with 590 additions and 516 deletions.
284 changes: 1 addition & 283 deletions lib/mindwendel/brainstormings.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ defmodule Mindwendel.Brainstormings do
alias Mindwendel.Brainstormings.Idea
alias Mindwendel.Accounts.User
alias Mindwendel.Brainstormings.IdeaLabel
alias Mindwendel.Brainstormings.IdeaIdeaLabel
alias Mindwendel.Brainstormings.Brainstorming
alias Mindwendel.Brainstormings.BrainstormingModeratingUser
alias Mindwendel.Brainstormings.Like

require Logger

Expand Down Expand Up @@ -41,220 +39,6 @@ defmodule Mindwendel.Brainstormings do
|> Repo.insert()
end

@doc """
Returns the list of ideas.
## Examples
iex> list_ideas()
[%Idea{}, ...]
"""
def list_ideas do
Repo.all(Idea)
end

@doc """
Returns the list of ideas depending on the brainstorming id.
## Examples
iex> list_ideas(3)
[%Idea{}, ...]
"""
def list_ideas_for_brainstorming(id) do
idea_count_query =
from like in Like,
group_by: like.idea_id,
select: %{idea_id: like.idea_id, like_count: count(1)}

idea_query =
from idea in Idea,
left_join: idea_count in subquery(idea_count_query),
on: idea_count.idea_id == idea.id,
where: idea.brainstorming_id == ^id,
order_by: [desc_nulls_last: idea_count.like_count, desc: idea.inserted_at]

Repo.all(idea_query)
|> Repo.preload([
:link,
:likes,
:label,
:idea_labels
])
end

def sort_ideas_by_labels(brainstorming_id) do
from(
idea in Idea,
left_join: l in assoc(idea, :idea_labels),
where: idea.brainstorming_id == ^brainstorming_id,
preload: [
:link,
:likes,
:idea_labels
],
order_by: [
asc_nulls_last: l.position_order,
desc: idea.inserted_at
]
)
|> Repo.all()
|> Enum.uniq()
end

@doc """
Gets a single idea.
Raises `Ecto.NoResultsError` if the Idea does not exist.
## Examples
iex> get_idea!(123)
%Idea{}
iex> get_idea!(456)
** (Ecto.NoResultsError)
"""
def get_idea!(id), do: Repo.get!(Idea, id) |> Repo.preload([:label, :idea_labels])

@doc """
Count likes for an idea.
## Examples
iex> count_likes_for_idea(idea)
5
"""
def count_likes_for_idea(idea), do: idea |> Ecto.assoc(:likes) |> Repo.aggregate(:count, :id)

@doc """
Creates a idea.
## Examples
iex> create_idea(%{field: value})
{:ok, %Idea{}}
iex> create_idea(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_idea(attrs \\ %{}) do
%Idea{}
|> Idea.changeset(attrs)
|> Repo.insert()
|> case do
{:ok, result} -> scan_for_link_in_idea(result)
{_, result} -> {:error, result}
end
|> broadcast(:idea_added)
end

@doc """
Scans for links in the idea body and adds a link entity if present.
## Examples
iex> scan_for_link_in_idea(idea)
{:ok, idea}
"""
def scan_for_link_in_idea(idea) do
Task.start(fn ->
Repo.preload(idea, :link)
|> Idea.build_link()
|> Repo.update()
|> broadcast(:idea_updated)
end)

{:ok, idea}
end

@doc """
Updates a idea.
## Examples
iex> update_idea(idea, %{field: new_value})
{:ok, %Idea{}}
iex> update_idea(idea, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_idea(%Idea{} = idea, attrs) do
idea
|> Idea.changeset(attrs)
|> Repo.update()
|> broadcast(:idea_updated)
end

def update_idea_label(%Idea{} = idea, label) do
idea
|> Idea.changeset_update_label(label)
|> Repo.update()
|> broadcast(:idea_updated)
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)

idea
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_assoc(:idea_labels, idea_labels)
|> Repo.update()
|> broadcast(:idea_updated)
end

def remove_idea_label_from_idea(%Idea{} = idea, %IdeaLabel{} = idea_label) do
from(idea_idea_label in IdeaIdeaLabel,
where:
idea_idea_label.idea_id == ^idea.id and
idea_idea_label.idea_label_id == ^idea_label.id
)
|> Repo.delete_all()

{:ok, get_idea!(idea.id)} |> broadcast(:idea_updated)
end

@doc """
Deletes a idea.
## Examples
iex> delete_idea(idea)
{:ok, %Idea{}}
iex> delete_idea(idea)
{:error, %Ecto.Changeset{}}
"""
def delete_idea(%Idea{} = idea) do
Repo.delete(idea)
broadcast({:ok, idea}, :idea_removed)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking idea changes.
## Examples
iex> change_idea(idea)
%Ecto.Changeset{data: %Idea{}}
"""
def change_idea(%Idea{} = idea, attrs \\ %{}) do
Repo.preload(idea, [:link, :idea_labels]) |> Idea.changeset(attrs)
end

@doc """
Returns the list of brainstormings.
Expand Down Expand Up @@ -308,20 +92,6 @@ defmodule Mindwendel.Brainstormings do
Repo.get_by!(Brainstorming, admin_url_id: admin_url_id)
end

def get_idea_label!(id) do
Repo.get!(IdeaLabel, id)
end

def get_idea_label(id) when not is_nil(id) do
Repo.get(IdeaLabel, id)
rescue
Ecto.Query.CastError -> nil
end

def get_idea_label(id) when is_nil(id) do
nil
end

@doc """
Creates a brainstorming and associates a user as creating_user, moderatoring user (also called brainstorming admin) and user.
Expand All @@ -330,7 +100,7 @@ defmodule Mindwendel.Brainstormings do
## Examples
current_user =
MindwendelService.SessionService.get_current_user_id(conn)
Mindwendel.Services.SessionService.get_current_user_id(conn)
|> Accounts.get_or_create_user()
{:ok, %Brainstorming{ ... }} =
Expand Down Expand Up @@ -442,58 +212,6 @@ defmodule Mindwendel.Brainstormings do
Brainstorming.changeset(brainstorming, attrs)
end

@doc """
Returns a Boolean if a like for the given idea and user exists.
## Examples
iex> exists_like_for_idea?(1, 2)
true
"""
def exists_like_for_idea?(idea_id, user_id) do
Repo.exists?(from like in Like, where: like.user_id == ^user_id and like.idea_id == ^idea_id)
end

@doc """
Returns a broadcast tuple of the idea update.
## Examples
iex> add_like(1, 2)
{:ok, %Idea{}}
"""
def add_like(idea_id, user_id) do
{status, result} =
%Like{}
|> Like.changeset(%{idea_id: idea_id, user_id: user_id})
|> Repo.insert()

case status do
:ok -> {:ok, get_idea!(idea_id)} |> broadcast(:idea_updated)
:error -> {:error, result}
end
end

@doc """
Deletes a like for an idea by a given user
## Examples
iex> delete_like(1, 2)
{:ok, %Idea{}}
"""
def delete_like(idea_id, user_id) do
# we ignore the result, delete_all returns the count of deleted items. We'll reload and broadcast the idea either way:
Repo.delete_all(
from like in Like, where: like.user_id == ^user_id and like.idea_id == ^idea_id
)

{:ok, get_idea!(idea_id)} |> broadcast(:idea_updated)
end

@doc """
Returns a subscibe result.
Expand Down
4 changes: 2 additions & 2 deletions lib/mindwendel/csv_formatter.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule Mindwendel.CSVFormatter do
alias Mindwendel.Brainstormings
alias Mindwendel.Likes

def ideas_to_csv(ideas) do
[["idea", "username", "likes"]]
Expand All @@ -9,7 +9,7 @@ defmodule Mindwendel.CSVFormatter do
&[
&1.body,
Gettext.gettext(MindwendelWeb.Gettext, &1.username),
Brainstormings.count_likes_for_idea(&1)
Likes.count_likes_for_idea(&1)
]
)
)
Expand Down
51 changes: 51 additions & 0 deletions lib/mindwendel/idea_labels.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
defmodule Mindwendel.IdeaLabels do
@moduledoc """
The Brainstormings context.
"""

import Ecto.Query, warn: false
alias Mindwendel.Repo

alias Mindwendel.Brainstormings.Idea
alias Mindwendel.Brainstormings
alias Mindwendel.Ideas
alias Mindwendel.Brainstormings.IdeaLabel
alias Mindwendel.Brainstormings.IdeaIdeaLabel

require Logger

def get_idea_label(id) when not is_nil(id) do
Repo.get(IdeaLabel, id)
rescue
Ecto.Query.CastError -> nil
end

def get_idea_label(id) when is_nil(id) 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)

idea
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_assoc(:idea_labels, idea_labels)
|> Repo.update()
|> Brainstormings.broadcast(:idea_updated)
end

def remove_idea_label_from_idea(%Idea{} = idea, %IdeaLabel{} = idea_label) do
from(idea_idea_label in IdeaIdeaLabel,
where:
idea_idea_label.idea_id == ^idea.id and
idea_idea_label.idea_label_id == ^idea_label.id
)
|> Repo.delete_all()

{:ok, Ideas.get_idea!(idea.id)} |> Brainstormings.broadcast(:idea_updated)
end
end
Loading

0 comments on commit 6ccd5b7

Please sign in to comment.