From f9bdda08a7309a4b0753b45db7bc6b99c9e0014c Mon Sep 17 00:00:00 2001 From: "byte[]" Date: Sun, 17 Nov 2019 13:05:50 -0500 Subject: [PATCH] add topic subscriptions --- lib/philomena/topics.ex | 76 +++---------------- .../topic/subscription_controller.ex | 45 +++++++++++ .../controllers/topic_controller.ex | 7 +- lib/philomena_web/router.ex | 6 ++ .../templates/topic/show.html.slime | 5 +- .../subscription/_subscription.html.slime | 23 ++++++ .../views/topic/subscription_view.ex | 3 + 7 files changed, 95 insertions(+), 70 deletions(-) create mode 100644 lib/philomena_web/controllers/topic/subscription_controller.ex create mode 100644 lib/philomena_web/templates/topic/subscription/_subscription.html.slime create mode 100644 lib/philomena_web/views/topic/subscription_view.ex diff --git a/lib/philomena/topics.ex b/lib/philomena/topics.ex index dff0de19..6ef51b34 100644 --- a/lib/philomena/topics.ex +++ b/lib/philomena/topics.ex @@ -104,35 +104,13 @@ defmodule Philomena.Topics do alias Philomena.Topics.Subscription - @doc """ - Returns the list of topic_subscriptions. - - ## Examples - - iex> list_topic_subscriptions() - [%Subscription{}, ...] - - """ - def list_topic_subscriptions do - Repo.all(Subscription) + def subscribed?(topic, nil), do: false + def subscribed?(topic, user) do + Subscription + |> where(topic_id: ^topic.id, user_id: ^user.id) + |> Repo.exists?() end - @doc """ - Gets a single subscription. - - Raises `Ecto.NoResultsError` if the Subscription does not exist. - - ## Examples - - iex> get_subscription!(123) - %Subscription{} - - iex> get_subscription!(456) - ** (Ecto.NoResultsError) - - """ - def get_subscription!(id), do: Repo.get!(Subscription, id) - @doc """ Creates a subscription. @@ -145,28 +123,10 @@ defmodule Philomena.Topics do {:error, %Ecto.Changeset{}} """ - def create_subscription(attrs \\ %{}) do - %Subscription{} - |> Subscription.changeset(attrs) - |> Repo.insert() - end - - @doc """ - Updates a subscription. - - ## Examples - - iex> update_subscription(subscription, %{field: new_value}) - {:ok, %Subscription{}} - - iex> update_subscription(subscription, %{field: bad_value}) - {:error, %Ecto.Changeset{}} - - """ - def update_subscription(%Subscription{} = subscription, attrs) do - subscription - |> Subscription.changeset(attrs) - |> Repo.update() + def create_subscription(topic, user) do + %Subscription{topic_id: topic.id, user_id: user.id} + |> Subscription.changeset(%{}) + |> Repo.insert(on_conflict: :nothing) end @doc """ @@ -181,20 +141,8 @@ defmodule Philomena.Topics do {:error, %Ecto.Changeset{}} """ - def delete_subscription(%Subscription{} = subscription) do - Repo.delete(subscription) - end - - @doc """ - Returns an `%Ecto.Changeset{}` for tracking subscription changes. - - ## Examples - - iex> change_subscription(subscription) - %Ecto.Changeset{source: %Subscription{}} - - """ - def change_subscription(%Subscription{} = subscription) do - Subscription.changeset(subscription, %{}) + def delete_subscription(topic, user) do + %Subscription{topic_id: topic.id, user_id: user.id} + |> Repo.delete() end end diff --git a/lib/philomena_web/controllers/topic/subscription_controller.ex b/lib/philomena_web/controllers/topic/subscription_controller.ex new file mode 100644 index 00000000..d399bf82 --- /dev/null +++ b/lib/philomena_web/controllers/topic/subscription_controller.ex @@ -0,0 +1,45 @@ +defmodule PhilomenaWeb.Topic.SubscriptionController do + use PhilomenaWeb, :controller + + alias Philomena.{Topics, Topics.Topic, Forums.Forum} + alias Philomena.Repo + import Ecto.Query + + plug PhilomenaWeb.Plugs.CanaryMapPlug, create: :show, delete: :show + plug :load_and_authorize_resource, model: Forum, id_name: "forum_id", id_field: "short_name", persisted: true + + def create(conn, %{"topic_id" => slug}) do + topic = load_topic(conn, slug) + user = conn.assigns.current_user + + case Topics.create_subscription(topic, user) do + {:ok, _subscription} -> + render(conn, "_subscription.html", forum: conn.assigns.forum, topic: topic, watching: true, layout: false) + + {:error, _changeset} -> + render(conn, "_error.html", layout: false) + end + end + + def delete(conn, %{"topic_id" => slug}) do + topic = load_topic(conn, slug) + user = conn.assigns.current_user + + case Topics.delete_subscription(topic, user) do + {:ok, _subscription} -> + render(conn, "_subscription.html", forum: conn.assigns.forum, topic: topic, watching: false, layout: false) + + {:error, _changeset} -> + render(conn, "_error.html", layout: false) + end + end + + defp load_topic(conn, slug) do + forum = conn.assigns.forum + topic = + Topic + |> where(forum_id: ^forum.id, slug: ^slug, hidden_from_users: false) + |> preload(:user) + |> Repo.one() + end +end \ No newline at end of file diff --git a/lib/philomena_web/controllers/topic_controller.ex b/lib/philomena_web/controllers/topic_controller.ex index 16d9d7a7..c2f227bb 100644 --- a/lib/philomena_web/controllers/topic_controller.ex +++ b/lib/philomena_web/controllers/topic_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.TopicController do use PhilomenaWeb, :controller - alias Philomena.{Forums.Forum, Topics.Topic, Posts.Post, Textile.Renderer} + alias Philomena.{Forums.Forum, Topics, Topics.Topic, Posts.Post, Textile.Renderer} alias Philomena.Repo import Ecto.Query @@ -51,6 +51,9 @@ defmodule PhilomenaWeb.TopicController do total_pages: div(topic.post_count + 25 - 1, 25) } - render(conn, "show.html", posts: posts) + watching = + Topics.subscribed?(topic, conn.assigns.current_user) + + render(conn, "show.html", posts: posts, watching: watching) end end diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index 8a7b3619..cb7d8435 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -60,6 +60,12 @@ defmodule PhilomenaWeb.Router do resources "/hide", Image.HideController, only: [:create, :delete], singleton: true resources "/subscription", Image.SubscriptionController, only: [:create, :delete], singleton: true end + + resources "/forums", ForumController, only: [] do + resources "/topics", TopicController, only: [] do + resources "/subscription", Topic.SubscriptionController, only: [:create, :delete], singleton: true + end + end end scope "/", PhilomenaWeb do diff --git a/lib/philomena_web/templates/topic/show.html.slime b/lib/philomena_web/templates/topic/show.html.slime index f2349d4c..33ef648d 100644 --- a/lib/philomena_web/templates/topic/show.html.slime +++ b/lib/philomena_web/templates/topic/show.html.slime @@ -24,10 +24,7 @@ h1 = @topic.title .flex--fixed.block__header__item => @topic.post_count - 1 ' replies - /= if current_user - / = subscription_link(@topic, current_user) - /- else - ' Login to subscribe to responses + = render PhilomenaWeb.Topic.SubscriptionView, "_subscription.html", forum: @forum, topic: @topic, watching: @watching, conn: @conn / Display the poll, if any /= render partial: 'polls/display', locals: { poll: @topic.poll } diff --git a/lib/philomena_web/templates/topic/subscription/_subscription.html.slime b/lib/philomena_web/templates/topic/subscription/_subscription.html.slime new file mode 100644 index 00000000..b6ca289d --- /dev/null +++ b/lib/philomena_web/templates/topic/subscription/_subscription.html.slime @@ -0,0 +1,23 @@ +elixir: + watch_path = Routes.forum_topic_subscription_path(@conn, :create, @forum, @topic) + watch_class = if @watching, do: "hidden", else: "" + + unwatch_path = Routes.forum_topic_subscription_path(@conn, :delete, @forum, @topic) + unwatch_class = if @watching, do: "", else: "hidden" + += if @conn.assigns.current_user do + #js-subscription-target + a.js-subscription-link href=watch_path class=watch_class data-remote="true" data-method="post" + i.fa.fa-bell> + span.hide-mobile + ' Subscribe + + a.js-subscription-link href=unwatch_path class=unwatch_class data-remote="true" data-method="delete" + i.fa.fa-bell-slash> + span.hide-mobile + ' Unsubscribe +- else + a href=Routes.pow_session_path(@conn, :new) + i.fa.fa-bell> + span.hide-mobile + ' Subscribe \ No newline at end of file diff --git a/lib/philomena_web/views/topic/subscription_view.ex b/lib/philomena_web/views/topic/subscription_view.ex new file mode 100644 index 00000000..2133f1e6 --- /dev/null +++ b/lib/philomena_web/views/topic/subscription_view.ex @@ -0,0 +1,3 @@ +defmodule PhilomenaWeb.Topic.SubscriptionView do + use PhilomenaWeb, :view +end \ No newline at end of file