diff --git a/lib/philomena/conversations.ex b/lib/philomena/conversations.ex index 7b5d4e9d..b87c5e91 100644 --- a/lib/philomena/conversations.ex +++ b/lib/philomena/conversations.ex @@ -105,17 +105,33 @@ defmodule Philomena.Conversations do |> Repo.aggregate(:count, :id) end - def mark_conversation_read(%Conversation{to_id: user_id} = conversation, %{id: user_id}) do + def mark_conversation_read(conversation, user, read \\ true) + def mark_conversation_hidden(conversation, user, hidden \\ true) + + def mark_conversation_read(%Conversation{to_id: user_id} = conversation, %{id: user_id}, read) do conversation - |> Conversation.read_changeset(%{to_read: true}) + |> Conversation.read_changeset(%{to_read: read}) |> Repo.update() end - def mark_conversation_read(%Conversation{from_id: user_id} = conversation, %{id: user_id}) do + def mark_conversation_read(%Conversation{from_id: user_id} = conversation, %{id: user_id}, read) do conversation - |> Conversation.read_changeset(%{from_read: true}) + |> Conversation.read_changeset(%{from_read: read}) |> Repo.update() end - def mark_conversation_read(_conversation, _user), do: {:ok, nil} + def mark_conversation_read(_conversation, _user, _read), do: {:ok, nil} + + + def mark_conversation_hidden(%Conversation{to_id: user_id} = conversation, %{id: user_id}, hidden) do + conversation + |> Conversation.hidden_changeset(%{to_hidden: hidden}) + |> Repo.update() + end + def mark_conversation_hidden(%Conversation{from_id: user_id} = conversation, %{id: user_id}, hidden) do + conversation + |> Conversation.hidden_changeset(%{from_hidden: hidden}) + |> Repo.update() + end + def mark_conversation_hidden(_conversation, _user, _read), do: {:ok, nil} alias Philomena.Conversations.Message diff --git a/lib/philomena/conversations/conversation.ex b/lib/philomena/conversations/conversation.ex index 19f05266..bb3625b8 100644 --- a/lib/philomena/conversations/conversation.ex +++ b/lib/philomena/conversations/conversation.ex @@ -37,6 +37,11 @@ defmodule Philomena.Conversations.Conversation do |> cast(attrs, [:from_read, :to_read]) end + def hidden_changeset(conversation, attrs) do + conversation + |> cast(attrs, [:from_hidden, :to_hidden]) + end + @doc false def creation_changeset(conversation, from, attrs) do conversation diff --git a/lib/philomena_web/controllers/conversation/hide_controller.ex b/lib/philomena_web/controllers/conversation/hide_controller.ex new file mode 100644 index 00000000..3abae311 --- /dev/null +++ b/lib/philomena_web/controllers/conversation/hide_controller.ex @@ -0,0 +1,31 @@ +defmodule PhilomenaWeb.Conversation.HideController do + use PhilomenaWeb, :controller + + alias Philomena.Conversations.Conversation + alias Philomena.Conversations + + plug PhilomenaWeb.CanaryMapPlug, create: :show, delete: :show + plug :load_and_authorize_resource, model: Conversation, id_field: "slug", id_name: "conversation_id", persisted: true + + def create(conn, _params) do + conversation = conn.assigns.conversation + user = conn.assigns.current_user + + {:ok, _conversation} = Conversations.mark_conversation_hidden(conversation, user) + + conn + |> put_flash(:info, "Conversation hidden.") + |> redirect(to: Routes.conversation_path(conn, :index)) + end + + def delete(conn, _params) do + conversation = conn.assigns.conversation + user = conn.assigns.current_user + + {:ok, _conversation} = Conversations.mark_conversation_hidden(conversation, user, false) + + conn + |> put_flash(:info, "Conversation restored.") + |> redirect(to: Routes.conversation_path(conn, :show, conversation)) + end +end \ No newline at end of file diff --git a/lib/philomena_web/controllers/conversation/read_controller.ex b/lib/philomena_web/controllers/conversation/read_controller.ex new file mode 100644 index 00000000..d5b5166e --- /dev/null +++ b/lib/philomena_web/controllers/conversation/read_controller.ex @@ -0,0 +1,31 @@ +defmodule PhilomenaWeb.Conversation.ReadController do + use PhilomenaWeb, :controller + + alias Philomena.Conversations.Conversation + alias Philomena.Conversations + + plug PhilomenaWeb.CanaryMapPlug, create: :show, delete: :show + plug :load_and_authorize_resource, model: Conversation, id_field: "slug", id_name: "conversation_id", persisted: true + + def create(conn, _params) do + conversation = conn.assigns.conversation + user = conn.assigns.current_user + + {:ok, _conversation} = Conversations.mark_conversation_read(conversation, user) + + conn + |> put_flash(:info, "Conversation marked as read.") + |> redirect(to: Routes.conversation_path(conn, :show, conversation)) + end + + def delete(conn, _params) do + conversation = conn.assigns.conversation + user = conn.assigns.current_user + + {:ok, _conversation} = Conversations.mark_conversation_read(conversation, user, false) + + conn + |> put_flash(:info, "Conversation marked as unread.") + |> redirect(to: Routes.conversation_path(conn, :index)) + end +end \ No newline at end of file diff --git a/lib/philomena_web/controllers/conversation_controller.ex b/lib/philomena_web/controllers/conversation_controller.ex index 7fcccc7a..71e2edd6 100644 --- a/lib/philomena_web/controllers/conversation_controller.ex +++ b/lib/philomena_web/controllers/conversation_controller.ex @@ -16,8 +16,10 @@ defmodule PhilomenaWeb.ConversationController do conversations = Conversation |> where([c], (c.from_id == ^user.id and not c.from_hidden) or (c.to_id == ^user.id and not c.to_hidden)) + |> join(:inner_lateral, [c], _ in fragment("SELECT COUNT(*) FROM messages m WHERE m.conversation_id = ?", c.id)) |> order_by(desc: :last_message_at) |> preload([:to, :from]) + |> select([c, cnt], {c, cnt.count}) |> Repo.paginate(conn.assigns.scrivener) render(conn, "index.html", conversations: conversations) diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index cbc41d71..2990d9e9 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -95,6 +95,8 @@ defmodule PhilomenaWeb.Router do resources "/conversations", ConversationController, only: [:index, :show, :new, :create] do resources "/reports", Conversation.ReportController, only: [:new, :create] resources "/messages", Conversation.MessageController, only: [:create] + resources "/read", Conversation.ReadController, only: [:create, :delete], singleton: true + resources "/hide", Conversation.HideController, only: [:create, :delete], singleton: true end resources "/images", ImageController, only: [] do resources "/vote", Image.VoteController, only: [:create, :delete], singleton: true diff --git a/lib/philomena_web/templates/conversation/index.html.slime b/lib/philomena_web/templates/conversation/index.html.slime index 0cbc991c..98d3af50 100644 --- a/lib/philomena_web/templates/conversation/index.html.slime +++ b/lib/philomena_web/templates/conversation/index.html.slime @@ -19,7 +19,7 @@ h1 My Conversations th.table--communication-list__stats With th.table--communication-list__options Options tbody - = for c <- @conversations do + = for {c, count} <- @conversations do tr class=conversation_class(@conn.assigns.current_user, c) td.table--communication-list__name => link c.title, to: Routes.conversation_path(@conn, :show, c) @@ -33,7 +33,9 @@ h1 My Conversations td.table--communication-list__stats = render PhilomenaWeb.UserAttributionView, "_user.html", object: %{user: other_party(@current_user.id, c)}, conn: @conn td.table--communication-list__options - | Last message + => link "Last message", to: last_message_path(@conn, c, count) + ' • + => link "Hide", to: Routes.conversation_hide_path(@conn, :create, c), data: [method: "post"], data: [confirm: "Are you really, really sure?"] .block__header.block__header--light = pagination \ No newline at end of file diff --git a/lib/philomena_web/templates/conversation/show.html.slime b/lib/philomena_web/templates/conversation/show.html.slime index dc979864..9c979bea 100644 --- a/lib/philomena_web/templates/conversation/show.html.slime +++ b/lib/philomena_web/templates/conversation/show.html.slime @@ -13,7 +13,9 @@ h1 = @conversation.title => render PhilomenaWeb.UserAttributionView, "_user.html", object: %{user: other}, conn: @conn .block__header--sub.block__header--light = pagination + = link "Remove conversation", to: Routes.conversation_hide_path(@conn, :create, @conversation), data: [method: "post", confirm: "Are you really, really sure?"] = link "Report conversation", to: Routes.conversation_report_path(@conn, :new, @conversation) + = link "Mark as unread", to: Routes.conversation_read_path(@conn, :delete, @conversation), data: [method: "delete"] = for {message, body} <- @messages do = render PhilomenaWeb.MessageView, "_message.html", message: message, body: body, conn: @conn diff --git a/lib/philomena_web/views/conversation_view.ex b/lib/philomena_web/views/conversation_view.ex index 973656de..66024381 100644 --- a/lib/philomena_web/views/conversation_view.ex +++ b/lib/philomena_web/views/conversation_view.ex @@ -24,4 +24,10 @@ defmodule PhilomenaWeb.ConversationView do _ -> nil end end + + def last_message_path(conn, conversation, count) do + page = trunc(Float.ceil(count / 25)) + + Routes.conversation_path(conn, :show, conversation, page: page) + end end \ No newline at end of file