diff --git a/assets/js/boorujs.js b/assets/js/boorujs.js index 9d8a71c6..86d9901b 100644 --- a/assets/js/boorujs.js +++ b/assets/js/boorujs.js @@ -52,6 +52,13 @@ const actions = { addTag(document.querySelector(data.el.closest('[data-target]').dataset.target), data.el.dataset.tagName); }, + hideParent(data) { + const base = data.el.closest(data.value); + if (base) { + base.classList.add('hidden'); + } + }, + tab(data) { const block = data.el.parentNode.parentNode, newTab = $(`.block__tab[data-tab="${data.value}"]`), diff --git a/lib/philomena/channels.ex b/lib/philomena/channels.ex index 2ffd4ce4..efa6d47c 100644 --- a/lib/philomena/channels.ex +++ b/lib/philomena/channels.ex @@ -12,6 +12,7 @@ defmodule Philomena.Channels do alias Philomena.Tags use Philomena.Subscriptions, + on_delete: :clear_channel_notification, id_name: :channel_id @doc """ diff --git a/lib/philomena/comments.ex b/lib/philomena/comments.ex index d6a73806..33c7c9a7 100644 --- a/lib/philomena/comments.ex +++ b/lib/philomena/comments.ex @@ -74,14 +74,12 @@ defmodule Philomena.Comments do end def perform_notify(comment_id) do - comment = get_comment!(comment_id) - - image = - comment - |> Repo.preload(:image) - |> Map.fetch!(:image) + comment = + comment_id + |> get_comment!() + |> Repo.preload([:user, :image]) - Notifications.create_image_comment_notification(image, comment) + Notifications.create_image_comment_notification(comment.user, comment.image, comment) end @doc """ diff --git a/lib/philomena/galleries.ex b/lib/philomena/galleries.ex index 4c76df35..c553ad3e 100644 --- a/lib/philomena/galleries.ex +++ b/lib/philomena/galleries.ex @@ -19,6 +19,7 @@ defmodule Philomena.Galleries do alias Philomena.Images use Philomena.Subscriptions, + on_delete: :clear_gallery_notification, id_name: :gallery_id @doc """ diff --git a/lib/philomena/images.ex b/lib/philomena/images.ex index 43c769c2..c21d2685 100644 --- a/lib/philomena/images.ex +++ b/lib/philomena/images.ex @@ -40,6 +40,7 @@ defmodule Philomena.Images do alias Philomena.Games.{Player, Team} use Philomena.Subscriptions, + on_delete: :clear_image_notification, id_name: :image_id @doc """ diff --git a/lib/philomena/notifications.ex b/lib/philomena/notifications.ex index cbed7413..baf2f8be 100644 --- a/lib/philomena/notifications.ex +++ b/lib/philomena/notifications.ex @@ -78,7 +78,13 @@ defmodule Philomena.Notifications do """ def create_channel_live_notification(channel) do - Creator.create_single(ChannelSubscription, ChannelLiveNotification, :channel_id, channel) + Creator.create_single( + where(ChannelSubscription, channel_id: ^channel.id), + ChannelLiveNotification, + nil, + :channel_id, + channel + ) end @doc """ @@ -86,14 +92,15 @@ defmodule Philomena.Notifications do ## Examples - iex> create_forum_post_notification(topic, post) + iex> create_forum_post_notification(user, topic, post) {:ok, 2} """ - def create_forum_post_notification(topic, post) do + def create_forum_post_notification(user, topic, post) do Creator.create_double( - TopicSubscription, + where(TopicSubscription, topic_id: ^topic.id), ForumPostNotification, + user, :topic_id, topic, :post_id, @@ -106,12 +113,18 @@ defmodule Philomena.Notifications do ## Examples - iex> create_forum_topic_notification(topic) + iex> create_forum_topic_notification(user, topic) {:ok, 2} """ - def create_forum_topic_notification(topic) do - Creator.create_single(ForumSubscription, ForumTopicNotification, :topic_id, topic) + def create_forum_topic_notification(user, topic) do + Creator.create_single( + where(ForumSubscription, forum_id: ^topic.forum_id), + ForumTopicNotification, + user, + :topic_id, + topic + ) end @doc """ @@ -124,7 +137,13 @@ defmodule Philomena.Notifications do """ def create_gallery_image_notification(gallery) do - Creator.create_single(GallerySubscription, GalleryImageNotification, :gallery_id, gallery) + Creator.create_single( + where(GallerySubscription, gallery_id: ^gallery.id), + GalleryImageNotification, + nil, + :gallery_id, + gallery + ) end @doc """ @@ -132,14 +151,15 @@ defmodule Philomena.Notifications do ## Examples - iex> create_image_comment_notification(image, comment) + iex> create_image_comment_notification(user, image, comment) {:ok, 2} """ - def create_image_comment_notification(image, comment) do + def create_image_comment_notification(user, image, comment) do Creator.create_double( - ImageSubscription, + where(ImageSubscription, image_id: ^image.id), ImageCommentNotification, + user, :image_id, image, :comment_id, @@ -158,8 +178,9 @@ defmodule Philomena.Notifications do """ def create_image_merge_notification(target, source) do Creator.create_double( - ImageSubscription, + where(ImageSubscription, image_id: ^target.id), ImageMergeNotification, + nil, :target_id, target, :source_id, diff --git a/lib/philomena/notifications/creator.ex b/lib/philomena/notifications/creator.ex index 5a04b724..ee4fec6a 100644 --- a/lib/philomena/notifications/creator.ex +++ b/lib/philomena/notifications/creator.ex @@ -22,13 +22,19 @@ defmodule Philomena.Notifications.Creator do ## Example - iex> create_single(GallerySubscription, GalleryImageNotification, :gallery_id, gallery) + iex> create_single( + ...> where(GallerySubscription, gallery_id: ^gallery.id), + ...> GalleryImageNotification, + ...> nil, + ...> :gallery_id, + ...> gallery + ...> ) {:ok, 2} """ - def create_single(subscription, notification, name, object) do + def create_single(subscription, notification, user, name, object) do subscription - |> create_notification_query(name, object) + |> create_notification_query(user, name, object) |> create_notification(notification, name) end @@ -43,8 +49,9 @@ defmodule Philomena.Notifications.Creator do ## Example iex> create_double( - ...> ImageSubscription, + ...> where(ImageSubscription, image_id: ^image.id), ...> ImageCommentNotification, + ...> user, ...> :image_id, ...> image, ...> :comment_id, @@ -53,9 +60,9 @@ defmodule Philomena.Notifications.Creator do {:ok, 2} """ - def create_double(subscription, notification, name1, object1, name2, object2) do + def create_double(subscription, notification, user, name1, object1, name2, object2) do subscription - |> create_notification_query(name1, object1, name2, object2) + |> create_notification_query(user, name1, object1, name2, object2) |> create_notification(notification, name1) end @@ -80,11 +87,10 @@ defmodule Philomena.Notifications.Creator do # TODO: the following cannot be accomplished with a single query expression # due to this Ecto bug: https://github.com/elixir-ecto/ecto/issues/4430 - defp create_notification_query(subscription, name, object) do + defp create_notification_query(subscription, user, name, object) do now = DateTime.utc_now(:second) - from s in subscription, - where: field(s, ^name) == ^object.id, + from s in subscription_query(subscription, user), select: %{ ^name => type(^object.id, :integer), user_id: s.user_id, @@ -94,11 +100,10 @@ defmodule Philomena.Notifications.Creator do } end - defp create_notification_query(subscription, name1, object1, name2, object2) do + defp create_notification_query(subscription, user, name1, object1, name2, object2) do now = DateTime.utc_now(:second) - from s in subscription, - where: field(s, ^name1) == ^object1.id, + from s in subscription_query(subscription, user), select: %{ ^name1 => type(^object1.id, :integer), ^name2 => type(^object2.id, :integer), @@ -109,6 +114,19 @@ defmodule Philomena.Notifications.Creator do } end + defp subscription_query(subscription, user) do + case user do + %{id: user_id} -> + # Avoid sending notifications to the user which performed the action. + from s in subscription, + where: s.user_id != ^user_id + + _ -> + # When not created by a user, send notifications to all subscribers. + subscription + end + end + defp create_notification(query, notification, name) do {count, nil} = Repo.insert_all( diff --git a/lib/philomena/posts.ex b/lib/philomena/posts.ex index 645d3f68..17ed9485 100644 --- a/lib/philomena/posts.ex +++ b/lib/philomena/posts.ex @@ -123,14 +123,12 @@ defmodule Philomena.Posts do end def perform_notify(post_id) do - post = get_post!(post_id) + post = + post_id + |> get_post!() + |> Repo.preload([:user, :topic]) - topic = - post - |> Repo.preload(:topic) - |> Map.fetch!(:topic) - - Notifications.create_forum_post_notification(topic, post) + Notifications.create_forum_post_notification(post.user, post.topic, post) end @doc """ diff --git a/lib/philomena/subscriptions.ex b/lib/philomena/subscriptions.ex index 8e67183f..d0688107 100644 --- a/lib/philomena/subscriptions.ex +++ b/lib/philomena/subscriptions.ex @@ -25,6 +25,18 @@ defmodule Philomena.Subscriptions do # For Philomena.Images, this yields :image_id field_name = Keyword.fetch!(opts, :id_name) + # Deletion callback + on_delete = + case Keyword.get(opts, :on_delete) do + nil -> + [] + + callback when is_atom(callback) -> + quote do + apply(__MODULE__, unquote(callback), [object, user]) + end + end + # For Philomena.Images, this yields Philomena.Images.Subscription subscription_module = Module.concat(__CALLER__.module, Subscription) @@ -100,6 +112,8 @@ defmodule Philomena.Subscriptions do """ def delete_subscription(object, user) do + unquote(on_delete) + Philomena.Subscriptions.delete_subscription( unquote(subscription_module), unquote(field_name), diff --git a/lib/philomena/topics.ex b/lib/philomena/topics.ex index 3ff4aba5..e1e5af29 100644 --- a/lib/philomena/topics.ex +++ b/lib/philomena/topics.ex @@ -14,6 +14,7 @@ defmodule Philomena.Topics do alias Philomena.NotificationWorker use Philomena.Subscriptions, + on_delete: :clear_topic_notification, id_name: :topic_id @doc """ @@ -91,9 +92,12 @@ defmodule Philomena.Topics do end def perform_notify([topic_id, _post_id]) do - topic = get_topic!(topic_id) + topic = + topic_id + |> get_topic!() + |> Repo.preload(:user) - Notifications.create_forum_topic_notification(topic) + Notifications.create_forum_topic_notification(topic.user, topic) end @doc """ diff --git a/lib/philomena_web/templates/notification/_channel.html.slime b/lib/philomena_web/templates/notification/_channel.html.slime index 0c4c5b73..c22299db 100644 --- a/lib/philomena_web/templates/notification/_channel.html.slime +++ b/lib/philomena_web/templates/notification/_channel.html.slime @@ -7,8 +7,8 @@ => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=~p"/channels/#{@notification.channel}/read" data-method="post" data-remote="true" + a.button.button--separate-right title="Delete" href=~p"/channels/#{@notification.channel}/read" data-method="post" data-remote="true" data-click-hideparent=".notification" i.fa.fa-trash - a.button title="Unsubscribe" href=~p"/channels/#{@notification.channel}/subscription" data-method="delete" data-remote="true" + a.button title="Unsubscribe" href=~p"/channels/#{@notification.channel}/subscription" data-method="delete" data-remote="true" data-click-hideparent=".notification" i.fa.fa-bell-slash diff --git a/lib/philomena_web/templates/notification/_comment.html.slime b/lib/philomena_web/templates/notification/_comment.html.slime index 4e9efeb6..076ccb34 100644 --- a/lib/philomena_web/templates/notification/_comment.html.slime +++ b/lib/philomena_web/templates/notification/_comment.html.slime @@ -15,8 +15,8 @@ => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=~p"/images/#{image}/read" data-method="post" data-remote="true" + a.button.button--separate-right title="Delete" href=~p"/images/#{image}/read" data-method="post" data-remote="true" data-click-hideparent=".notification" i.fa.fa-trash - a.button title="Unsubscribe" href=~p"/images/#{image}/subscription" data-method="delete" data-remote="true" + a.button title="Unsubscribe" href=~p"/images/#{image}/subscription" data-method="delete" data-remote="true" data-click-hideparent=".notification" i.fa.fa-bell-slash diff --git a/lib/philomena_web/templates/notification/_gallery.html.slime b/lib/philomena_web/templates/notification/_gallery.html.slime index 0192b449..8ef024d0 100644 --- a/lib/philomena_web/templates/notification/_gallery.html.slime +++ b/lib/philomena_web/templates/notification/_gallery.html.slime @@ -11,8 +11,8 @@ => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=~p"/galleries/#{gallery}/read" data-method="post" data-remote="true" + a.button.button--separate-right title="Delete" href=~p"/galleries/#{gallery}/read" data-method="post" data-remote="true" data-click-hideparent=".notification" i.fa.fa-trash - a.button title="Unsubscribe" href=~p"/galleries/#{gallery}/subscription" data-method="delete" data-remote="true" + a.button title="Unsubscribe" href=~p"/galleries/#{gallery}/subscription" data-method="delete" data-remote="true" data-click-hideparent=".notification" i.fa.fa-bell-slash diff --git a/lib/philomena_web/templates/notification/_image.html.slime b/lib/philomena_web/templates/notification/_image.html.slime index 01f72dd9..dcfad4eb 100644 --- a/lib/philomena_web/templates/notification/_image.html.slime +++ b/lib/philomena_web/templates/notification/_image.html.slime @@ -17,8 +17,8 @@ => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=~p"/images/#{target}/read" data-method="post" data-remote="true" + a.button.button--separate-right title="Delete" href=~p"/images/#{target}/read" data-method="post" data-remote="true" data-click-hideparent=".notification" i.fa.fa-trash - a.button title="Unsubscribe" href=~p"/images/#{target}/subscription" data-method="delete" data-remote="true" + a.button title="Unsubscribe" href=~p"/images/#{target}/subscription" data-method="delete" data-remote="true" data-click-hideparent=".notification" i.fa.fa-bell-slash diff --git a/lib/philomena_web/templates/notification/_post.html.slime b/lib/philomena_web/templates/notification/_post.html.slime index bac4acb9..f0dc0b66 100644 --- a/lib/philomena_web/templates/notification/_post.html.slime +++ b/lib/philomena_web/templates/notification/_post.html.slime @@ -12,8 +12,8 @@ => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=~p"/forums/#{topic.forum}/topics/#{topic}/read" data-method="post" data-remote="true" + a.button.button--separate-right title="Delete" href=~p"/forums/#{topic.forum}/topics/#{topic}/read" data-method="post" data-remote="true" data-click-hideparent=".notification" i.fa.fa-trash - a.button title="Unsubscribe" href=~p"/forums/#{topic.forum}/topics/#{topic}/subscription" data-method="delete" data-remote="true" + a.button title="Unsubscribe" href=~p"/forums/#{topic.forum}/topics/#{topic}/subscription" data-method="delete" data-remote="true" data-click-hideparent=".notification" i.fa.fa-bell-slash diff --git a/lib/philomena_web/templates/notification/_topic.html.slime b/lib/philomena_web/templates/notification/_topic.html.slime index cf2bd5df..37f6786d 100644 --- a/lib/philomena_web/templates/notification/_topic.html.slime +++ b/lib/philomena_web/templates/notification/_topic.html.slime @@ -16,8 +16,5 @@ => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=~p"/forums/#{forum}/topics/#{topic}/read" data-method="post" data-remote="true" + a.button.button--separate-right title="Delete" href=~p"/forums/#{forum}/topics/#{topic}/read" data-method="post" data-remote="true" data-click-hideparent=".notification" i.fa.fa-trash - - a.button title="Unsubscribe" href=~p"/forums/#{forum}/subscription" data-method="delete" data-remote="true" - i.fa.fa-bell-slash