Skip to content

Commit

Permalink
add comments (#454)
Browse files Browse the repository at this point in the history
  • Loading branch information
JannikStreek authored Nov 11, 2024
1 parent 5213ae2 commit 8441f3f
Show file tree
Hide file tree
Showing 30 changed files with 1,160 additions and 89 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ Create a challenge. Ready? Brainstorm. mindwendel helps you to easily brainstorm
## Features

- 5 minute setup (It is not a joke)
- Anonymously invite people to your brainstormings - no registration needed. Usernames are optional
- Anonymously invite people to your brainstormings - no registration needed. Usernames are optional!
- Easily create and upvote ideas, with live updates from your mindwendel members
- Cluster or filter your ideas with custom labels
- Preview of links to ease URL sharing
- Add automatically encrypted file attachments which are uploaded to an S3 compatible storage backend
- Add lanes, use drag & drop to order ideas
- Add comments to ideas
- Export your generated ideas to html or csv (currently comma separated)
- German & English Translation files
- By default, brainstormings are deleted after 30 days to ensure GDPR compliancy
Expand Down
2 changes: 1 addition & 1 deletion assets/scss/_bootstrap_custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
padding: 0.5rem 0.5rem;
}

.card-footer-mindwendel-idea {
.card-footer-mindwendel {
@extend .card-footer;
padding: 0.5rem 0.5rem;
background-color: inherit;
Expand Down
3 changes: 2 additions & 1 deletion lib/mindwendel/brainstormings.ex
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ defmodule Mindwendel.Brainstormings do
:link,
:likes,
:idea_labels,
:files
:files,
:comments
])
}
)
Expand Down
23 changes: 23 additions & 0 deletions lib/mindwendel/brainstormings/comment.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Mindwendel.Brainstormings.Comment do
use Mindwendel.Schema

import Ecto.Changeset
alias Mindwendel.Brainstormings.Idea
alias Mindwendel.Accounts.User

schema "idea_comments" do
belongs_to :idea, Idea
belongs_to :user, User
field :body, :string
field :username, :string, default: "Anonymous"

timestamps()
end

@doc false
def changeset(comment, attrs) do
comment
|> cast(attrs, [:idea_id, :user_id, :body, :username])
|> validate_required([:idea_id, :body, :username])
end
end
6 changes: 5 additions & 1 deletion lib/mindwendel/brainstormings/idea.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ defmodule Mindwendel.Brainstormings.Idea do
alias Mindwendel.Brainstormings.IdeaIdeaLabel
alias Mindwendel.Brainstormings.Like
alias Mindwendel.Brainstormings.Lane
alias Mindwendel.Brainstormings.Comment
alias Mindwendel.Ideas
alias Mindwendel.Attachments
alias Mindwendel.Attachments.Link
Expand All @@ -21,10 +22,12 @@ defmodule Mindwendel.Brainstormings.Idea do
field :body, :string
field :position_order, :integer
field :username, :string, default: "Anonymous"
field :comments_count, :integer
field :deprecated_label, Ecto.Enum, source: :label, values: @label_values
has_one :link, Link
belongs_to :user, User
has_many :likes, Like
has_many :comments, Comment, preload_order: [desc: :inserted_at]
has_many :files, File
belongs_to :brainstorming, Brainstorming
belongs_to :label, IdeaLabel, on_replace: :nilify
Expand All @@ -45,7 +48,8 @@ defmodule Mindwendel.Brainstormings.Idea do
:deprecated_label,
:label_id,
:user_id,
:position_order
:position_order,
:comments_count
])
|> validate_required([:username, :body, :brainstorming_id])
|> maybe_put_idea_labels(attrs)
Expand Down
122 changes: 122 additions & 0 deletions lib/mindwendel/comments.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
defmodule Mindwendel.Comments do
import Ecto.Query, warn: false
alias Mindwendel.Repo
alias Mindwendel.Brainstormings.Comment
alias Mindwendel.Brainstormings
alias Mindwendel.Ideas

require Logger

@doc """
Gets a single comment
## Examples
iex> get_comment!("0323906b-b496-4778-ae67-1dd779d3de3c")
%Comment{ ... }
"""
def get_comment!(id) do
Repo.get!(Comment, id)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking comment changes.
## Examples
iex> change_comment(comment)
%Ecto.Changeset(data: %Comment{})
"""
def change_comment(%Comment{} = comment, attrs \\ %{}) do
Comment.changeset(comment, attrs)
end

@doc """
Creates a comment.
## Examples
iex> create_comment(%{field: value})
{:ok, %Comment{}}
iex> create_comment(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_comment(attrs \\ %{}) do
result =
%Comment{}
|> Comment.changeset(attrs)
|> Repo.insert()

case result do
{:ok, comment} -> Ideas.increment_comment_count(comment.idea_id)
{:error, _} -> nil
end

handle_result_for_broadcast(result)
result
end

@doc """
Updates a comment.
## Examples
iex> update_comment(comment, %{field: new_value})
{:ok, %Comment{}}
iex> update_comment(comment, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_comment(%Comment{} = comment, attrs) do
result =
comment
|> Comment.changeset(attrs)
|> Repo.update()

handle_result_for_broadcast(result)
result
end

@doc """
Deletes a comment.
## Examples
iex> delete_comment(comment)
{:ok, %Comment{}}
iex> delete_comment(comment)
{:error, %Ecto.Changeset{}}
"""
def delete_comment(%Comment{} = comment) do
result = Repo.delete(comment)

case result do
{:ok, comment} -> Ideas.decrement_comment_count(comment.idea_id)
end

handle_result_for_broadcast(result)
result
end

defp handle_result_for_broadcast(result) do
case result do
{:ok, comment} ->
idea = Ideas.get_idea!(comment.idea_id)

Brainstormings.broadcast(
{:ok, idea},
:idea_updated
)

{:error, changeset} ->
{:error, changeset}
end
end
end
44 changes: 41 additions & 3 deletions lib/mindwendel/ideas.ex
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ defmodule Mindwendel.Ideas do
:link,
:likes,
:label,
:idea_labels
:idea_labels,
:comments
])
end

Expand Down Expand Up @@ -283,7 +284,8 @@ defmodule Mindwendel.Ideas do
** (Ecto.NoResultsError)
"""
def get_idea!(id), do: Repo.get!(Idea, id) |> Repo.preload([:idea_labels, :files])
def get_idea!(id),
do: Repo.get!(Idea, id) |> Repo.preload([:idea_labels, :files, :link, :comments])

@doc """
Creates a idea.
Expand Down Expand Up @@ -355,6 +357,42 @@ defmodule Mindwendel.Ideas do
result
end

@doc """
Increments the comment count of an idea.
## Examples
iex> increment_comment_count(idea_id)
{:ok, %Idea{}}
iex> increment_comment_count(idea_id)
{:error, %Ecto.Changeset{}}
"""
def increment_comment_count(idea_id) do
idea = Repo.get!(Idea, idea_id)
changeset = Idea.changeset(idea, %{comments_count: idea.comments_count + 1})
Repo.update(changeset)
end

@doc """
Decrements the comment count of an idea.
## Examples
iex> decrement_comment_count(idea_id)
{:ok, %Idea{}}
iex> decrement_comment_count(idea_id)
{:error, %Ecto.Changeset{}}
"""
def decrement_comment_count(idea_id) do
idea = Repo.get!(Idea, idea_id)
changeset = Idea.changeset(idea, %{comments_count: idea.comments_count - 1})
Repo.update(changeset)
end

@doc """
Deletes a idea.
Expand Down Expand Up @@ -389,6 +427,6 @@ defmodule Mindwendel.Ideas do
"""
def change_idea(%Idea{} = idea, attrs \\ %{}) do
Repo.preload(idea, [:link, :idea_labels]) |> Idea.changeset(attrs)
Repo.preload(idea, [:link, :idea_labels, :comments, :files]) |> Idea.changeset(attrs)
end
end
29 changes: 29 additions & 0 deletions lib/mindwendel_web/live/brainstorming_live/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ defmodule MindwendelWeb.BrainstormingLive.Show do
{:noreply, assign(socket, :lanes, lanes)}
end

def handle_info({:lane_updated, lane}, socket) do
new_lanes =
Enum.map(socket.assigns.lanes, fn existing_lane ->
if lane.id == existing_lane.id, do: lane, else: existing_lane
end)

{:noreply, assign(socket, :lanes, new_lanes)}
end

# idea updated - only relevant if the show modal of the idea is opened
def handle_info({:idea_updated, idea}, socket) do
if socket.assigns.live_action == :show_idea and socket.assigns.idea.id == idea.id do
# update the idea modal with new content
send_update(MindwendelWeb.IdeaLive.ShowComponent, id: :show, idea: idea)
{:noreply, socket}
else
{:noreply, socket}
end
end

def handle_info({:brainstorming_filter_updated, brainstorming, lanes}, socket) do
{:noreply,
push_patch(
Expand Down Expand Up @@ -102,6 +122,15 @@ defmodule MindwendelWeb.BrainstormingLive.Show do
|> assign(:idea, Ideas.get_idea!(idea_id))
end

defp apply_action(
socket,
:show_idea,
%{"brainstorming_id" => _brainstorming_id, "idea_id" => idea_id}
) do
socket
|> assign(:idea, Ideas.get_idea!(idea_id))
end

defp apply_action(
socket,
:edit_lane,
Expand Down
28 changes: 15 additions & 13 deletions lib/mindwendel_web/live/brainstorming_live/show.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<div class="d-flex justify-content-end flex-wrap">
<%= if has_moderating_permission(@brainstorming, @current_user) do %>
<.link
patch={~p"/brainstormings/#{@brainstorming.id}/show/new_lane"}
patch={~p"/brainstormings/#{@brainstorming.id}/new_lane"}
class="btn btn-primary m-1 d-inline-flex align-items-center"
title={gettext("New lane")}
>
Expand All @@ -30,7 +30,7 @@
<% end %>

<.link
patch={~p"/brainstormings/#{@brainstorming.id}/show/share"}
patch={~p"/brainstormings/#{@brainstorming.id}/share"}
class="btn btn-secondary m-1"
title={gettext("Share")}
>
Expand Down Expand Up @@ -73,31 +73,33 @@
/>

<.modal
:if={@live_action in [:edit]}
id="brainstorming-modal"
:if={@live_action in [:new_idea]}
id="idea-modal"
show
on_cancel={JS.patch(~p"/brainstormings/#{@brainstorming.id}")}
title={@page_title}
title={gettext("New idea")}
>
<.live_component
module={MindwendelWeb.BrainstormingLive.FormComponent}
id={@brainstorming.id}
action={@live_action}
module={MindwendelWeb.IdeaLive.FormComponent}
id={:new}
action={:new}
brainstorming={@brainstorming}
current_user={@current_user}
idea={@idea}
/>
</.modal>

<.modal
:if={@live_action in [:new_idea]}
:if={@live_action in [:show_idea]}
id="idea-modal"
show
on_cancel={JS.patch(~p"/brainstormings/#{@brainstorming.id}")}
title={gettext("New idea")}
title={gettext("Show idea")}
>
<.live_component
module={MindwendelWeb.IdeaLive.FormComponent}
id={:new}
action={:new}
module={MindwendelWeb.IdeaLive.ShowComponent}
id={:show}
action={:show}
brainstorming={@brainstorming}
current_user={@current_user}
idea={@idea}
Expand Down
Loading

0 comments on commit 8441f3f

Please sign in to comment.