mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
Merge pull request #310 from philomena-dev/subscriptions-cleanup
Deduplicate common subscription logic
This commit is contained in:
commit
3c0c12602f
8 changed files with 254 additions and 321 deletions
|
@ -8,7 +8,10 @@ defmodule Philomena.Channels do
|
||||||
|
|
||||||
alias Philomena.Channels.AutomaticUpdater
|
alias Philomena.Channels.AutomaticUpdater
|
||||||
alias Philomena.Channels.Channel
|
alias Philomena.Channels.Channel
|
||||||
alias Philomena.Notifications
|
|
||||||
|
use Philomena.Subscriptions,
|
||||||
|
actor_types: ~w(Channel LivestreamChannel),
|
||||||
|
id_name: :channel_id
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Updates all the tracked channels for which an update scheme is known.
|
Updates all the tracked channels for which an update scheme is known.
|
||||||
|
@ -115,69 +118,4 @@ defmodule Philomena.Channels do
|
||||||
def change_channel(%Channel{} = channel) do
|
def change_channel(%Channel{} = channel) do
|
||||||
Channel.changeset(channel, %{})
|
Channel.changeset(channel, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
alias Philomena.Channels.Subscription
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Creates a subscription.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> create_subscription(%{field: value})
|
|
||||||
{:ok, %Subscription{}}
|
|
||||||
|
|
||||||
iex> create_subscription(%{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
|
||||||
def create_subscription(_channel, nil), do: {:ok, nil}
|
|
||||||
|
|
||||||
def create_subscription(channel, user) do
|
|
||||||
%Subscription{channel_id: channel.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(channel, user) do
|
|
||||||
clear_notification(channel, user)
|
|
||||||
|
|
||||||
%Subscription{channel_id: channel.id, user_id: user.id}
|
|
||||||
|> Repo.delete()
|
|
||||||
end
|
|
||||||
|
|
||||||
def subscribed?(_channel, nil), do: false
|
|
||||||
|
|
||||||
def subscribed?(channel, user) do
|
|
||||||
Subscription
|
|
||||||
|> where(channel_id: ^channel.id, user_id: ^user.id)
|
|
||||||
|> Repo.exists?()
|
|
||||||
end
|
|
||||||
|
|
||||||
def subscriptions(_channels, nil), do: %{}
|
|
||||||
|
|
||||||
def subscriptions(channels, user) do
|
|
||||||
channel_ids = Enum.map(channels, & &1.id)
|
|
||||||
|
|
||||||
Subscription
|
|
||||||
|> where([s], s.channel_id in ^channel_ids and s.user_id == ^user.id)
|
|
||||||
|> Repo.all()
|
|
||||||
|> Map.new(&{&1.channel_id, true})
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_notification(channel, user) do
|
|
||||||
Notifications.delete_unread_notification("Channel", channel.id, user)
|
|
||||||
Notifications.delete_unread_notification("LivestreamChannel", channel.id, user)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,7 +19,6 @@ defmodule Philomena.Comments do
|
||||||
alias Philomena.NotificationWorker
|
alias Philomena.NotificationWorker
|
||||||
alias Philomena.Versions
|
alias Philomena.Versions
|
||||||
alias Philomena.Reports
|
alias Philomena.Reports
|
||||||
alias Philomena.Users.User
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Gets a single comment.
|
Gets a single comment.
|
||||||
|
@ -58,24 +57,17 @@ defmodule Philomena.Comments do
|
||||||
Image
|
Image
|
||||||
|> where(id: ^image.id)
|
|> where(id: ^image.id)
|
||||||
|
|
||||||
|
image_lock_query =
|
||||||
|
lock(image_query, "FOR UPDATE")
|
||||||
|
|
||||||
Multi.new()
|
Multi.new()
|
||||||
|
|> Multi.one(:image, image_lock_query)
|
||||||
|> Multi.insert(:comment, comment)
|
|> Multi.insert(:comment, comment)
|
||||||
|> Multi.update_all(:image, image_query, inc: [comments_count: 1])
|
|> Multi.update_all(:update_image, image_query, inc: [comments_count: 1])
|
||||||
|> maybe_create_subscription_on_reply(image, attribution[:user])
|
|> Images.maybe_subscribe_on(:image, attribution[:user], :watch_on_reply)
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_create_subscription_on_reply(multi, image, %User{watch_on_reply: true} = user) do
|
|
||||||
multi
|
|
||||||
|> Multi.run(:subscribe, fn _repo, _changes ->
|
|
||||||
Images.create_subscription(image, user)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp maybe_create_subscription_on_reply(multi, _image, _user) do
|
|
||||||
multi
|
|
||||||
end
|
|
||||||
|
|
||||||
def notify_comment(comment) do
|
def notify_comment(comment) do
|
||||||
Exq.enqueue(Exq, "notifications", NotificationWorker, ["Comments", comment.id])
|
Exq.enqueue(Exq, "notifications", NotificationWorker, ["Comments", comment.id])
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,8 +7,10 @@ defmodule Philomena.Forums do
|
||||||
alias Philomena.Repo
|
alias Philomena.Repo
|
||||||
|
|
||||||
alias Philomena.Forums.Forum
|
alias Philomena.Forums.Forum
|
||||||
alias Philomena.Forums.Subscription
|
|
||||||
alias Philomena.Notifications
|
use Philomena.Subscriptions,
|
||||||
|
actor_types: ~w(Forum),
|
||||||
|
id_name: :forum_id
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Returns the list of forums.
|
Returns the list of forums.
|
||||||
|
@ -103,45 +105,4 @@ defmodule Philomena.Forums do
|
||||||
def change_forum(%Forum{} = forum) do
|
def change_forum(%Forum{} = forum) do
|
||||||
Forum.changeset(forum, %{})
|
Forum.changeset(forum, %{})
|
||||||
end
|
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, nil), do: nil
|
|
||||||
|
|
||||||
def clear_notification(forum, user) do
|
|
||||||
Notifications.delete_unread_notification("Forum", forum.id, user)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,6 +18,10 @@ defmodule Philomena.Galleries do
|
||||||
alias Philomena.Notifications.{Notification, UnreadNotification}
|
alias Philomena.Notifications.{Notification, UnreadNotification}
|
||||||
alias Philomena.Images
|
alias Philomena.Images
|
||||||
|
|
||||||
|
use Philomena.Subscriptions,
|
||||||
|
actor_types: ~w(Gallery),
|
||||||
|
id_name: :gallery_id
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Gets a single gallery.
|
Gets a single gallery.
|
||||||
|
|
||||||
|
@ -356,55 +360,4 @@ defmodule Philomena.Galleries do
|
||||||
|
|
||||||
defp position_order(%{order_position_asc: true}), do: [asc: :position]
|
defp position_order(%{order_position_asc: true}), do: [asc: :position]
|
||||||
defp position_order(_gallery), do: [desc: :position]
|
defp position_order(_gallery), do: [desc: :position]
|
||||||
|
|
||||||
alias Philomena.Galleries.Subscription
|
|
||||||
|
|
||||||
def subscribed?(_gallery, nil), do: false
|
|
||||||
|
|
||||||
def subscribed?(gallery, user) do
|
|
||||||
Subscription
|
|
||||||
|> where(gallery_id: ^gallery.id, user_id: ^user.id)
|
|
||||||
|> Repo.exists?()
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Creates a subscription.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> create_subscription(%{field: value})
|
|
||||||
{:ok, %Subscription{}}
|
|
||||||
|
|
||||||
iex> create_subscription(%{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
|
||||||
def create_subscription(gallery, user) do
|
|
||||||
%Subscription{gallery_id: gallery.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(gallery, user) do
|
|
||||||
%Subscription{gallery_id: gallery.id, user_id: user.id}
|
|
||||||
|> Repo.delete()
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_notification(_gallery, nil), do: nil
|
|
||||||
|
|
||||||
def clear_notification(gallery, user) do
|
|
||||||
Notifications.delete_unread_notification("Gallery", gallery.id, user)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,6 +37,10 @@ defmodule Philomena.Images do
|
||||||
alias Philomena.Galleries.Interaction
|
alias Philomena.Galleries.Interaction
|
||||||
alias Philomena.Users.User
|
alias Philomena.Users.User
|
||||||
|
|
||||||
|
use Philomena.Subscriptions,
|
||||||
|
actor_types: ~w(Image),
|
||||||
|
id_name: :image_id
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Gets a single image.
|
Gets a single image.
|
||||||
|
|
||||||
|
@ -103,7 +107,7 @@ defmodule Philomena.Images do
|
||||||
|
|
||||||
{:ok, count}
|
{:ok, count}
|
||||||
end)
|
end)
|
||||||
|> maybe_create_subscription_on_upload(attribution[:user])
|
|> maybe_subscribe_on(:image, attribution[:user], :watch_on_upload)
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, %{image: image}} = result ->
|
{:ok, %{image: image}} = result ->
|
||||||
|
@ -157,17 +161,6 @@ defmodule Philomena.Images do
|
||||||
Logger.error("Aborting upload of #{image.id} after #{retry_count} retries")
|
Logger.error("Aborting upload of #{image.id} after #{retry_count} retries")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_create_subscription_on_upload(multi, %User{watch_on_upload: true} = user) do
|
|
||||||
multi
|
|
||||||
|> Multi.run(:subscribe, fn _repo, %{image: image} ->
|
|
||||||
create_subscription(image, user)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp maybe_create_subscription_on_upload(multi, _user) do
|
|
||||||
multi
|
|
||||||
end
|
|
||||||
|
|
||||||
def approve_image(image) do
|
def approve_image(image) do
|
||||||
image
|
image
|
||||||
|> Repo.preload(:user)
|
|> Repo.preload(:user)
|
||||||
|
@ -868,53 +861,6 @@ defmodule Philomena.Images do
|
||||||
|
|
||||||
alias Philomena.Images.Subscription
|
alias Philomena.Images.Subscription
|
||||||
|
|
||||||
def subscribed?(_image, nil), do: false
|
|
||||||
|
|
||||||
def subscribed?(image, user) do
|
|
||||||
Subscription
|
|
||||||
|> where(image_id: ^image.id, user_id: ^user.id)
|
|
||||||
|> Repo.exists?()
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Creates a subscription.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> create_subscription(%{field: value})
|
|
||||||
{:ok, %Subscription{}}
|
|
||||||
|
|
||||||
iex> create_subscription(%{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
|
||||||
def create_subscription(_image, nil), do: {:ok, nil}
|
|
||||||
|
|
||||||
def create_subscription(image, user) do
|
|
||||||
%Subscription{image_id: image.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(image, user) do
|
|
||||||
clear_notification(image, user)
|
|
||||||
|
|
||||||
%Subscription{image_id: image.id, user_id: user.id}
|
|
||||||
|> Repo.delete()
|
|
||||||
end
|
|
||||||
|
|
||||||
def migrate_subscriptions(source, target) do
|
def migrate_subscriptions(source, target) do
|
||||||
subscriptions =
|
subscriptions =
|
||||||
Subscription
|
Subscription
|
||||||
|
@ -968,10 +914,4 @@ defmodule Philomena.Images do
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear_notification(_image, nil), do: nil
|
|
||||||
|
|
||||||
def clear_notification(image, user) do
|
|
||||||
Notifications.delete_unread_notification("Image", image.id, user)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,6 @@ defmodule Philomena.Posts do
|
||||||
alias Philomena.Versions
|
alias Philomena.Versions
|
||||||
alias Philomena.Reports
|
alias Philomena.Reports
|
||||||
alias Philomena.Reports.Report
|
alias Philomena.Reports.Report
|
||||||
alias Philomena.Users.User
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Gets a single post.
|
Gets a single post.
|
||||||
|
@ -66,7 +65,7 @@ defmodule Philomena.Posts do
|
||||||
|> where(id: ^topic.forum_id)
|
|> where(id: ^topic.forum_id)
|
||||||
|
|
||||||
Multi.new()
|
Multi.new()
|
||||||
|> Multi.all(:topic_lock, topic_lock_query)
|
|> Multi.one(:topic, topic_lock_query)
|
||||||
|> Multi.run(:post, fn repo, _ ->
|
|> Multi.run(:post, fn repo, _ ->
|
||||||
last_position =
|
last_position =
|
||||||
Post
|
Post
|
||||||
|
@ -95,7 +94,7 @@ defmodule Philomena.Posts do
|
||||||
|
|
||||||
{:ok, count}
|
{:ok, count}
|
||||||
end)
|
end)
|
||||||
|> maybe_create_subscription_on_reply(topic, attributes[:user])
|
|> Topics.maybe_subscribe_on(:topic, attributes[:user], :watch_on_reply)
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, %{post: post}} = result ->
|
{:ok, %{post: post}} = result ->
|
||||||
|
@ -108,17 +107,6 @@ defmodule Philomena.Posts do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_create_subscription_on_reply(multi, topic, %User{watch_on_reply: true} = user) do
|
|
||||||
multi
|
|
||||||
|> Multi.run(:subscribe, fn _repo, _changes ->
|
|
||||||
Topics.create_subscription(topic, user)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp maybe_create_subscription_on_reply(multi, _topic, _user) do
|
|
||||||
multi
|
|
||||||
end
|
|
||||||
|
|
||||||
def notify_post(post) do
|
def notify_post(post) do
|
||||||
Exq.enqueue(Exq, "notifications", NotificationWorker, ["Posts", post.id])
|
Exq.enqueue(Exq, "notifications", NotificationWorker, ["Posts", post.id])
|
||||||
end
|
end
|
||||||
|
|
224
lib/philomena/subscriptions.ex
Normal file
224
lib/philomena/subscriptions.ex
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
defmodule Philomena.Subscriptions do
|
||||||
|
@moduledoc """
|
||||||
|
Common subscription logic.
|
||||||
|
|
||||||
|
`use Philomena.Subscriptions` requires the following properties:
|
||||||
|
|
||||||
|
- `:actor_types`
|
||||||
|
This is the "actor_type" in the notifications table.
|
||||||
|
For `Philomena.Images`, this would be `["Image"]`.
|
||||||
|
|
||||||
|
- `:id_name`
|
||||||
|
This is the name of the object field in the subscription table.
|
||||||
|
For `Philomena.Images`, this would be `:image_id`.
|
||||||
|
|
||||||
|
The following functions and documentation are produced in the calling module:
|
||||||
|
- `subscribed?/2`
|
||||||
|
- `subscriptions/2`
|
||||||
|
- `create_subscription/2`
|
||||||
|
- `delete_subscription/2`
|
||||||
|
- `clear_notification/2`
|
||||||
|
- `maybe_subscribe_on/4`
|
||||||
|
"""
|
||||||
|
|
||||||
|
import Ecto.Query, warn: false
|
||||||
|
alias Ecto.Multi
|
||||||
|
|
||||||
|
alias Philomena.Notifications
|
||||||
|
alias Philomena.Repo
|
||||||
|
|
||||||
|
defmacro __using__(opts) do
|
||||||
|
# For Philomena.Images, this yields ["Image"]
|
||||||
|
actor_types = Keyword.fetch!(opts, :actor_types)
|
||||||
|
|
||||||
|
# For Philomena.Images, this yields :image_id
|
||||||
|
field_name = Keyword.fetch!(opts, :id_name)
|
||||||
|
|
||||||
|
# For Philomena.Images, this yields Philomena.Images.Subscription
|
||||||
|
subscription_module = Module.concat(__CALLER__.module, Subscription)
|
||||||
|
|
||||||
|
quote do
|
||||||
|
@doc """
|
||||||
|
Returns whether the user is currently subscribed to this object.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> subscribed?(object, user)
|
||||||
|
false
|
||||||
|
|
||||||
|
"""
|
||||||
|
def subscribed?(object, user) do
|
||||||
|
Philomena.Subscriptions.subscribed?(
|
||||||
|
unquote(subscription_module),
|
||||||
|
unquote(field_name),
|
||||||
|
object,
|
||||||
|
user
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns a map containing whether the user is currently subscribed to any of
|
||||||
|
the provided objects.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> subscriptions([%{id: 1}, %{id: 2}], user)
|
||||||
|
%{2 => true}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def subscriptions(objects, user) do
|
||||||
|
Philomena.Subscriptions.subscriptions(
|
||||||
|
unquote(subscription_module),
|
||||||
|
unquote(field_name),
|
||||||
|
objects,
|
||||||
|
user
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Creates a subscription.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> create_subscription(object, user)
|
||||||
|
{:ok, %Subscription{}}
|
||||||
|
|
||||||
|
iex> create_subscription(object, user)
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def create_subscription(object, user) do
|
||||||
|
Philomena.Subscriptions.create_subscription(
|
||||||
|
unquote(subscription_module),
|
||||||
|
unquote(field_name),
|
||||||
|
object,
|
||||||
|
user
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Deletes a subscription and removes notifications for it.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> delete_subscription(object, user)
|
||||||
|
{:ok, %Subscription{}}
|
||||||
|
|
||||||
|
iex> delete_subscription(object, user)
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def delete_subscription(object, user) do
|
||||||
|
clear_notification(object, user)
|
||||||
|
|
||||||
|
Philomena.Subscriptions.delete_subscription(
|
||||||
|
unquote(subscription_module),
|
||||||
|
unquote(field_name),
|
||||||
|
object,
|
||||||
|
user
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Deletes any active notifications for a subscription.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> clear_notification(object, user)
|
||||||
|
:ok
|
||||||
|
|
||||||
|
"""
|
||||||
|
def clear_notification(object, user) do
|
||||||
|
for type <- unquote(actor_types) do
|
||||||
|
Philomena.Subscriptions.clear_notification(type, object, user)
|
||||||
|
end
|
||||||
|
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Creates a subscription inside the `m:Ecto.Multi` flow if `user` is not nil
|
||||||
|
and `field` in `user` is `true`.
|
||||||
|
|
||||||
|
Valid values for field are `:watch_on_reply`, `:watch_on_upload`, `:watch_on_new_topic`.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> maybe_subscribe_on(multi, :image, user, :watch_on_reply)
|
||||||
|
%Ecto.Multi{}
|
||||||
|
|
||||||
|
iex> maybe_subscribe_on(multi, :topic, nil, :watch_on_reply)
|
||||||
|
%Ecto.Multi{}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def maybe_subscribe_on(multi, change_name, user, field) do
|
||||||
|
Philomena.Subscriptions.maybe_subscribe_on(multi, __MODULE__, change_name, user, field)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def subscribed?(subscription_module, field_name, object, user) do
|
||||||
|
case user do
|
||||||
|
nil ->
|
||||||
|
false
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
subscription_module
|
||||||
|
|> where([s], field(s, ^field_name) == ^object.id and s.user_id == ^user.id)
|
||||||
|
|> Repo.exists?()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def subscriptions(subscription_module, field_name, objects, user) do
|
||||||
|
case user do
|
||||||
|
nil ->
|
||||||
|
%{}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
object_ids = Enum.map(objects, & &1.id)
|
||||||
|
|
||||||
|
subscription_module
|
||||||
|
|> where([s], field(s, ^field_name) in ^object_ids and s.user_id == ^user.id)
|
||||||
|
|> Repo.all()
|
||||||
|
|> Map.new(&{Map.fetch!(&1, field_name), true})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def create_subscription(subscription_module, field_name, object, user) do
|
||||||
|
struct!(subscription_module, [{field_name, object.id}, {:user_id, user.id}])
|
||||||
|
|> subscription_module.changeset(%{})
|
||||||
|
|> Repo.insert(on_conflict: :nothing)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def delete_subscription(subscription_module, field_name, object, user) do
|
||||||
|
struct!(subscription_module, [{field_name, object.id}, {:user_id, user.id}])
|
||||||
|
|> Repo.delete()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def clear_notification(type, object, user) do
|
||||||
|
case user do
|
||||||
|
nil -> nil
|
||||||
|
_ -> Notifications.delete_unread_notification(type, object.id, user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def maybe_subscribe_on(multi, module, change_name, user, field)
|
||||||
|
when field in [:watch_on_reply, :watch_on_upload, :watch_on_new_topic] do
|
||||||
|
case user do
|
||||||
|
%{^field => true} ->
|
||||||
|
Multi.run(multi, :subscribe, fn _repo, changes ->
|
||||||
|
object = Map.fetch!(changes, change_name)
|
||||||
|
module.create_subscription(object, user)
|
||||||
|
end)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
multi
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,7 +12,10 @@ defmodule Philomena.Topics do
|
||||||
alias Philomena.Posts
|
alias Philomena.Posts
|
||||||
alias Philomena.Notifications
|
alias Philomena.Notifications
|
||||||
alias Philomena.NotificationWorker
|
alias Philomena.NotificationWorker
|
||||||
alias Philomena.Users.User
|
|
||||||
|
use Philomena.Subscriptions,
|
||||||
|
actor_types: ~w(Topic),
|
||||||
|
id_name: :topic_id
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Gets a single topic.
|
Gets a single topic.
|
||||||
|
@ -70,7 +73,7 @@ defmodule Philomena.Topics do
|
||||||
|
|
||||||
{:ok, count}
|
{:ok, count}
|
||||||
end)
|
end)
|
||||||
|> maybe_create_subscription_on_new_topic(attribution[:user])
|
|> maybe_subscribe_on(:topic, attribution[:user], :watch_on_new_topic)
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, %{topic: topic}} = result ->
|
{:ok, %{topic: topic}} = result ->
|
||||||
|
@ -84,17 +87,6 @@ defmodule Philomena.Topics do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_create_subscription_on_new_topic(multi, %User{watch_on_new_topic: true} = user) do
|
|
||||||
multi
|
|
||||||
|> Multi.run(:subscribe, fn _repo, %{topic: topic} ->
|
|
||||||
create_subscription(topic, user)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp maybe_create_subscription_on_new_topic(multi, _user) do
|
|
||||||
multi
|
|
||||||
end
|
|
||||||
|
|
||||||
def notify_topic(topic, post) do
|
def notify_topic(topic, post) do
|
||||||
Exq.enqueue(Exq, "notifications", NotificationWorker, ["Topics", [topic.id, post.id]])
|
Exq.enqueue(Exq, "notifications", NotificationWorker, ["Topics", [topic.id, post.id]])
|
||||||
end
|
end
|
||||||
|
@ -173,55 +165,6 @@ defmodule Philomena.Topics do
|
||||||
Topic.changeset(topic, %{})
|
Topic.changeset(topic, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
alias Philomena.Topics.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 """
|
|
||||||
Creates a subscription.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> create_subscription(%{field: value})
|
|
||||||
{:ok, %Subscription{}}
|
|
||||||
|
|
||||||
iex> create_subscription(%{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
|
||||||
def create_subscription(_topic, nil), do: {:ok, nil}
|
|
||||||
|
|
||||||
def create_subscription(topic, user) do
|
|
||||||
%Subscription{topic_id: topic.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(topic, user) do
|
|
||||||
clear_notification(topic, user)
|
|
||||||
|
|
||||||
%Subscription{topic_id: topic.id, user_id: user.id}
|
|
||||||
|> Repo.delete()
|
|
||||||
end
|
|
||||||
|
|
||||||
def stick_topic(topic) do
|
def stick_topic(topic) do
|
||||||
Topic.stick_changeset(topic)
|
Topic.stick_changeset(topic)
|
||||||
|> Repo.update()
|
|> Repo.update()
|
||||||
|
@ -299,10 +242,4 @@ defmodule Philomena.Topics do
|
||||||
|> Topic.title_changeset(attrs)
|
|> Topic.title_changeset(attrs)
|
||||||
|> Repo.update()
|
|> Repo.update()
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear_notification(_topic, nil), do: nil
|
|
||||||
|
|
||||||
def clear_notification(topic, user) do
|
|
||||||
Notifications.delete_unread_notification("Topic", topic.id, user)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue