diff --git a/lib/philomena/forums.ex b/lib/philomena/forums.ex index 374d0bab..e5dc83b9 100644 --- a/lib/philomena/forums.ex +++ b/lib/philomena/forums.ex @@ -7,6 +7,8 @@ defmodule Philomena.Forums do alias Philomena.Repo alias Philomena.Forums.Forum + alias Philomena.Forums.Subscription + alias Philomena.Notifications @doc """ Returns the list of forums. @@ -101,4 +103,41 @@ defmodule Philomena.Forums do def change_forum(%Forum{} = forum) do Forum.changeset(forum, %{}) end + + def subscribed?(_forum, nil), do: false + def subscribed?(forum, user) do + Subscription + |> where(forum_id: ^forum.id, user_id: ^user.id) + |> Repo.exists?() + end + + def create_subscription(_forum, nil), do: {:ok, nil} + def create_subscription(forum, user) do + %Subscription{forum_id: forum.id, user_id: user.id} + |> Subscription.changeset(%{}) + |> Repo.insert(on_conflict: :nothing) + end + + @doc """ + Deletes a Subscription. + + ## Examples + + iex> delete_subscription(subscription) + {:ok, %Subscription{}} + + iex> delete_subscription(subscription) + {:error, %Ecto.Changeset{}} + + """ + def delete_subscription(forum, user) do + clear_notification(forum, user) + + %Subscription{forum_id: forum.id, user_id: user.id} + |> Repo.delete() + end + + def clear_notification(forum, user) do + Notifications.delete_unread_notification("Forum", forum.id, user) + end end diff --git a/lib/philomena/images.ex b/lib/philomena/images.ex index 4eb53ffa..2cb68337 100644 --- a/lib/philomena/images.ex +++ b/lib/philomena/images.ex @@ -14,6 +14,7 @@ defmodule Philomena.Images do alias Philomena.Tags alias Philomena.Tags.Tag alias Philomena.Processors + alias Philomena.Notifications @doc """ Gets a single image. @@ -283,7 +284,13 @@ defmodule Philomena.Images do """ def delete_subscription(image, user) do + clear_notification(image, user) + %Subscription{image_id: image.id, user_id: user.id} |> Repo.delete() end + + def clear_notification(image, user) do + Notifications.delete_unread_notification("Image", image.id, user) + end end diff --git a/lib/philomena/notifications.ex b/lib/philomena/notifications.ex index d5e1e932..48d85ff9 100644 --- a/lib/philomena/notifications.ex +++ b/lib/philomena/notifications.ex @@ -158,8 +158,17 @@ defmodule Philomena.Notifications do {:error, %Ecto.Changeset{}} """ - def delete_unread_notification(%UnreadNotification{} = unread_notification) do - Repo.delete(unread_notification) + def delete_unread_notification(actor_type, actor_id, user) do + notification = + Notification + |> where(actor_type: ^actor_type, actor_id: ^actor_id) + |> Repo.one() + + if notification do + UnreadNotification + |> where(notification_id: ^notification.id, user_id: ^user.id) + |> Repo.delete_all() + end end @doc """ diff --git a/lib/philomena/topics.ex b/lib/philomena/topics.ex index 0960863f..f65f50e8 100644 --- a/lib/philomena/topics.ex +++ b/lib/philomena/topics.ex @@ -184,7 +184,13 @@ defmodule Philomena.Topics do """ def delete_subscription(topic, user) do + clear_notification(topic, user) + %Subscription{topic_id: topic.id, user_id: user.id} |> Repo.delete() end + + def clear_notification(topic, user) do + Notifications.delete_unread_notification("Topic", topic.id, user) + end end diff --git a/lib/philomena_web/controllers/forum/read_controller.ex b/lib/philomena_web/controllers/forum/read_controller.ex new file mode 100644 index 00000000..bdcb129d --- /dev/null +++ b/lib/philomena_web/controllers/forum/read_controller.ex @@ -0,0 +1,18 @@ +defmodule PhilomenaWeb.Forum.ReadController do + import Plug.Conn + use PhilomenaWeb, :controller + + alias Philomena.Forums.Forum + alias Philomena.Forums + + plug :load_and_authorize_resource, model: Forum, id_name: "forum_id", id_field: "short_name", persisted: true + + def create(conn, _params) do + forum = conn.assigns.forum + user = conn.assigns.current_user + + Forums.clear_notification(forum, user) + + send_resp(conn, :ok, "") + end +end \ No newline at end of file diff --git a/lib/philomena_web/controllers/forum/subscription_controller.ex b/lib/philomena_web/controllers/forum/subscription_controller.ex new file mode 100644 index 00000000..221feb7a --- /dev/null +++ b/lib/philomena_web/controllers/forum/subscription_controller.ex @@ -0,0 +1,35 @@ +defmodule PhilomenaWeb.Forum.SubscriptionController do + use PhilomenaWeb, :controller + + alias Philomena.Forums.Forum + alias Philomena.Forums + + plug PhilomenaWeb.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, _params) do + forum = conn.assigns.forum + user = conn.assigns.current_user + + case Forums.create_subscription(forum, user) do + {:ok, _subscription} -> + render(conn, "_subscription.html", forum: forum, watching: true, layout: false) + + {:error, _changeset} -> + render(conn, "_error.html", layout: false) + end + end + + def delete(conn, _params) do + forum = conn.assigns.forum + user = conn.assigns.current_user + + case Forums.delete_subscription(forum, user) do + {:ok, _subscription} -> + render(conn, "_subscription.html", forum: forum, watching: false, layout: false) + + {:error, _changeset} -> + render(conn, "_error.html", layout: false) + end + end +end \ No newline at end of file diff --git a/lib/philomena_web/controllers/forum_controller.ex b/lib/philomena_web/controllers/forum_controller.ex index 8a276355..4ae34a22 100644 --- a/lib/philomena_web/controllers/forum_controller.ex +++ b/lib/philomena_web/controllers/forum_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.ForumController do use PhilomenaWeb, :controller - alias Philomena.{Forums.Forum, Topics.Topic} + alias Philomena.{Forums, Forums.Forum, Topics.Topic} alias Philomena.Repo import Ecto.Query @@ -22,14 +22,19 @@ defmodule PhilomenaWeb.ForumController do end def show(conn, %{"id" => _id}) do + forum = conn.assigns.forum + user = conn.assigns.current_user + topics = Topic - |> where(forum_id: ^conn.assigns.forum.id) + |> where(forum_id: ^forum.id) |> where(hidden_from_users: false) |> order_by(desc: :sticky, desc: :last_replied_to_at) |> preload([:poll, :forum, :user, last_post: :user]) |> Repo.paginate(conn.assigns.scrivener) - render(conn, "show.html", forum: conn.assigns.forum, topics: topics) + watching = Forums.subscribed?(forum, user) + + render(conn, "show.html", forum: conn.assigns.forum, watching: watching, topics: topics) end end diff --git a/lib/philomena_web/controllers/image/read_controller.ex b/lib/philomena_web/controllers/image/read_controller.ex new file mode 100644 index 00000000..40f39478 --- /dev/null +++ b/lib/philomena_web/controllers/image/read_controller.ex @@ -0,0 +1,18 @@ +defmodule PhilomenaWeb.Image.ReadController do + import Plug.Conn + use PhilomenaWeb, :controller + + alias Philomena.Images.Image + alias Philomena.Images + + plug :load_resource, model: Image, id_name: "image_id", persisted: true + + def create(conn, _params) do + image = conn.assigns.image + user = conn.assigns.current_user + + Images.clear_notification(image, user) + + send_resp(conn, :ok, "") + end +end \ No newline at end of file diff --git a/lib/philomena_web/controllers/topic/read_controller.ex b/lib/philomena_web/controllers/topic/read_controller.ex new file mode 100644 index 00000000..01684c36 --- /dev/null +++ b/lib/philomena_web/controllers/topic/read_controller.ex @@ -0,0 +1,30 @@ +defmodule PhilomenaWeb.Topic.ReadController do + import Plug.Conn + use PhilomenaWeb, :controller + + alias Philomena.Forums.Forum + alias Philomena.Topics.Topic + alias Philomena.Topics + alias Philomena.Repo + import Ecto.Query + + 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 + + Topics.clear_notification(topic, user) + + send_resp(conn, :ok, "") + end + + defp load_topic(conn, slug) do + forum = conn.assigns.forum + + 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/router.ex b/lib/philomena_web/router.ex index 6c9ef269..eca4caf9 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -65,12 +65,17 @@ defmodule PhilomenaWeb.Router do resources "/fave", Image.FaveController, only: [:create, :delete], singleton: true resources "/hide", Image.HideController, only: [:create, :delete], singleton: true resources "/subscription", Image.SubscriptionController, only: [:create, :delete], singleton: true + resources "/read", Image.ReadController, only: [:create], singleton: true end resources "/forums", ForumController, only: [] do resources "/topics", TopicController, only: [:new, :create] do resources "/subscription", Topic.SubscriptionController, only: [:create, :delete], singleton: true + resources "/read", Topic.ReadController, only: [:create], singleton: true end + + resources "/subscription", Forum.SubscriptionController, only: [:create, :delete], singleton: true + resources "/read", Forum.ReadController, only: [:create], singleton: true end scope "/filters", Filter, as: :filter do diff --git a/lib/philomena_web/templates/forum/show.html.slime b/lib/philomena_web/templates/forum/show.html.slime index c0a43064..ecf5940a 100644 --- a/lib/philomena_web/templates/forum/show.html.slime +++ b/lib/philomena_web/templates/forum/show.html.slime @@ -17,10 +17,7 @@ h1 = @forum.name .block__header--sub.block__header--light = pagination span.block__header__title = @forum.description - /- if current_user - / = subscription_link(@forum, current_user) - /- else - / | Login to subscribe to new threads + = render PhilomenaWeb.Forum.SubscriptionView, "_subscription.html", forum: @forum, watching: @watching, conn: @conn .block__content table.table.table--communication-list thead diff --git a/lib/philomena_web/templates/forum/subscription/_subscription.html.slime b/lib/philomena_web/templates/forum/subscription/_subscription.html.slime new file mode 100644 index 00000000..a54ffca5 --- /dev/null +++ b/lib/philomena_web/templates/forum/subscription/_subscription.html.slime @@ -0,0 +1,23 @@ +elixir: + watch_path = Routes.forum_subscription_path(@conn, :create, @forum) + watch_class = if @watching, do: "hidden", else: "" + + unwatch_path = Routes.forum_subscription_path(@conn, :delete, @forum) + unwatch_class = if @watching, do: "", else: "hidden" + += if @conn.assigns.current_user do + span#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/templates/image/subscription/_subscription.html.slime b/lib/philomena_web/templates/image/subscription/_subscription.html.slime index 9386e7db..bd5b832d 100644 --- a/lib/philomena_web/templates/image/subscription/_subscription.html.slime +++ b/lib/philomena_web/templates/image/subscription/_subscription.html.slime @@ -6,7 +6,7 @@ elixir: unwatch_class = if @watching, do: "", else: "hidden" = if @conn.assigns.current_user do - #js-subscription-target + span#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 diff --git a/lib/philomena_web/templates/notification/_channel.html.slime b/lib/philomena_web/templates/notification/_channel.html.slime index 18c01f84..00ed7c1a 100644 --- a/lib/philomena_web/templates/notification/_channel.html.slime +++ b/lib/philomena_web/templates/notification/_channel.html.slime @@ -1,4 +1,8 @@ -strong> - = link @notification.actor.title, to: "#" - /= link @notification.actor.title, to: Routes.channel_path(@conn, :show, notification.actor) -=<> @notification.action +.flex.flex--centered.flex__grow + div + strong> + = link @notification.actor.title, to: "#" + /= link @notification.actor.title, to: Routes.channel_path(@conn, :show, notification.actor) + =<> @notification.action + + => pretty_time @notification.updated_at \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_forum.html.slime b/lib/philomena_web/templates/notification/_forum.html.slime index d62746ed..512c49ea 100644 --- a/lib/philomena_web/templates/notification/_forum.html.slime +++ b/lib/philomena_web/templates/notification/_forum.html.slime @@ -1,14 +1,25 @@ - forum = @notification.actor - topic = @notification.actor_child -=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: topic, conn: @conn -=> @notification.action +.flex.flex--centered.flex__grow + div + => render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: topic, conn: @conn + => @notification.action -' titled + ' titled -strong> - = link topic.title, to: Routes.forum_topic_path(@conn, :show, forum, topic) + strong> + = link topic.title, to: Routes.forum_topic_path(@conn, :show, forum, topic) -' in + ' in -=> link forum.name, to: Routes.forum_path(@conn, :show, forum) \ No newline at end of file + => link forum.name, to: Routes.forum_path(@conn, :show, forum) + + => pretty_time @notification.updated_at + +.flex.flex--centered.flex--no-wrap + a.button.button--separate-right title="Delete" href=Routes.forum_read_path(@conn, :create, forum) data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + i.fa.fa-trash + + a.button title="Unsubscribe" href=Routes.forum_subscription_path(@conn, :delete, forum) data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + i.fa.fa-bell-slash \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_gallery.html.slime b/lib/philomena_web/templates/notification/_gallery.html.slime index 3e2f9599..22ff6aa6 100644 --- a/lib/philomena_web/templates/notification/_gallery.html.slime +++ b/lib/philomena_web/templates/notification/_gallery.html.slime @@ -1,6 +1,10 @@ -=> render PhilomenaWeb.UserAttributionView, "_user.html", object: %{user: @notification.actor.creator}, conn: @conn -=> @notification.action +.flex.flex--centered.flex__grow + div + => render PhilomenaWeb.UserAttributionView, "_user.html", object: %{user: @notification.actor.creator}, conn: @conn + => @notification.action -strong> - = link @notification.actor.title, to: "#" - /= link @notification.actor.title, to: Routes.gallery_path(@conn, :show, @notification.actor) \ No newline at end of file + strong> + = link @notification.actor.title, to: "#" + /= link @notification.actor.title, to: Routes.gallery_path(@conn, :show, @notification.actor) + + => pretty_time @notification.updated_at \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_image.html.slime b/lib/philomena_web/templates/notification/_image.html.slime index 72d04b10..a731b078 100644 --- a/lib/philomena_web/templates/notification/_image.html.slime +++ b/lib/philomena_web/templates/notification/_image.html.slime @@ -1,5 +1,16 @@ -=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @notification.actor_child, conn: @conn -=> @notification.action +.flex.flex--centered.flex__grow + div + => render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @notification.actor_child, conn: @conn + => @notification.action -strong - = link "##{@notification.actor_id}", to: Routes.image_path(@conn, :show, @notification.actor) <> "#comments" \ No newline at end of file + strong> + = link "##{@notification.actor_id}", to: Routes.image_path(@conn, :show, @notification.actor) <> "#comments" + + => pretty_time @notification.updated_at + +.flex.flex--centered.flex--no-wrap + a.button.button--separate-right title="Delete" href=Routes.image_read_path(@conn, :create, @notification.actor) data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + i.fa.fa-trash + + a.button title="Unsubscribe" href=Routes.image_subscription_path(@conn, :delete, @notification.actor) data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + i.fa.fa-bell-slash \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_notification.html.slime b/lib/philomena_web/templates/notification/_notification.html.slime index b51180d2..688df590 100644 --- a/lib/philomena_web/templates/notification/_notification.html.slime +++ b/lib/philomena_web/templates/notification/_notification.html.slime @@ -1,14 +1,7 @@ = if @notification.actor do - .block.block--fixed.flex class="js-notification-id-#{@notification.id}" + .block.block--fixed.flex id="notification-#{@notification.id}" = if @notification.actor_type == "Image" and @notification.actor do .flex.flex--centered.flex__fixed.thumb-tiny-container.spacing-right = render PhilomenaWeb.ImageView, "_image_container.html", image: @notification.actor, size: :thumb_tiny, conn: @conn - .flex.flex--centered.flex__grow - div - => render PhilomenaWeb.NotificationView, notification_template_path(@notification.actor_type), notification: @notification, conn: @conn - => pretty_time @notification.updated_at - .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" data-click-markread=@notification.id - i.fa.fa-trash - a.button title="Unsubscribe" data-subscription-id=@notification.actor_id data-subscription-type=@notification.actor_type data-click-togglesubscription="unwatch" data-click-hide=".js-notification-id-#{@notification.id}" - .fa.fa-bell-slash \ No newline at end of file + + => render PhilomenaWeb.NotificationView, notification_template_path(@notification.actor_type), notification: @notification, conn: @conn diff --git a/lib/philomena_web/templates/notification/_topic.html.slime b/lib/philomena_web/templates/notification/_topic.html.slime index fa6a2eda..1a1c5ff6 100644 --- a/lib/philomena_web/templates/notification/_topic.html.slime +++ b/lib/philomena_web/templates/notification/_topic.html.slime @@ -1,8 +1,19 @@ - topic = @notification.actor - post = @notification.actor_child -=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: post, conn: @conn -=> @notification.action +.flex.flex--centered.flex__grow + div + => render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: post, conn: @conn + => @notification.action -strong - = link topic.title, to: Routes.forum_topic_path(@conn, :show, topic.forum, topic, post_id: post.id) <> "#post_#{post.id}" \ No newline at end of file + strong> + = link topic.title, to: Routes.forum_topic_path(@conn, :show, topic.forum, topic, post_id: post.id) <> "#post_#{post.id}" + + => pretty_time @notification.updated_at + +.flex.flex--centered.flex--no-wrap + a.button.button--separate-right title="Delete" href=Routes.forum_topic_read_path(@conn, :create, topic.forum, topic) data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + i.fa.fa-trash + + a.button title="Unsubscribe" href=Routes.forum_topic_subscription_path(@conn, :delete, topic.forum, topic) data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + i.fa.fa-bell-slash \ No newline at end of file diff --git a/lib/philomena_web/templates/topic/subscription/_subscription.html.slime b/lib/philomena_web/templates/topic/subscription/_subscription.html.slime index b6ca289d..7c5d9f6d 100644 --- a/lib/philomena_web/templates/topic/subscription/_subscription.html.slime +++ b/lib/philomena_web/templates/topic/subscription/_subscription.html.slime @@ -6,7 +6,7 @@ elixir: unwatch_class = if @watching, do: "", else: "hidden" = if @conn.assigns.current_user do - #js-subscription-target + span#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 diff --git a/lib/philomena_web/views/forum/subscription_view.ex b/lib/philomena_web/views/forum/subscription_view.ex new file mode 100644 index 00000000..839e6f7e --- /dev/null +++ b/lib/philomena_web/views/forum/subscription_view.ex @@ -0,0 +1,3 @@ +defmodule PhilomenaWeb.Forum.SubscriptionView do + use PhilomenaWeb, :view +end