philomena/lib/philomena/notifications.ex
2020-01-10 23:20:19 -05:00

219 lines
4.9 KiB
Elixir

defmodule Philomena.Notifications do
@moduledoc """
The Notifications context.
"""
import Ecto.Query, warn: false
alias Philomena.Repo
alias Philomena.Notifications.Notification
@doc """
Returns the list of notifications.
## Examples
iex> list_notifications()
[%Notification{}, ...]
"""
def list_notifications do
Repo.all(Notification)
end
@doc """
Gets a single notification.
Raises `Ecto.NoResultsError` if the Notification does not exist.
## Examples
iex> get_notification!(123)
%Notification{}
iex> get_notification!(456)
** (Ecto.NoResultsError)
"""
def get_notification!(id), do: Repo.get!(Notification, id)
@doc """
Creates a notification.
## Examples
iex> create_notification(%{field: value})
{:ok, %Notification{}}
iex> create_notification(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_notification(attrs \\ %{}) do
%Notification{}
|> Notification.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a notification.
## Examples
iex> update_notification(notification, %{field: new_value})
{:ok, %Notification{}}
iex> update_notification(notification, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_notification(%Notification{} = notification, attrs) do
notification
|> Notification.changeset(attrs)
|> Repo.insert_or_update()
end
@doc """
Deletes a Notification.
## Examples
iex> delete_notification(notification)
{:ok, %Notification{}}
iex> delete_notification(notification)
{:error, %Ecto.Changeset{}}
"""
def delete_notification(%Notification{} = notification) do
Repo.delete(notification)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking notification changes.
## Examples
iex> change_notification(notification)
%Ecto.Changeset{source: %Notification{}}
"""
def change_notification(%Notification{} = notification) do
Notification.changeset(notification, %{})
end
alias Philomena.Notifications.UnreadNotification
def count_unread_notifications(user) do
UnreadNotification
|> where(user_id: ^user.id)
|> Repo.aggregate(:count, :notification_id)
end
@doc """
Creates a unread_notification.
## Examples
iex> create_unread_notification(%{field: value})
{:ok, %UnreadNotification{}}
iex> create_unread_notification(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_unread_notification(attrs \\ %{}) do
%UnreadNotification{}
|> UnreadNotification.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a unread_notification.
## Examples
iex> update_unread_notification(unread_notification, %{field: new_value})
{:ok, %UnreadNotification{}}
iex> update_unread_notification(unread_notification, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_unread_notification(%UnreadNotification{} = unread_notification, attrs) do
unread_notification
|> UnreadNotification.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a UnreadNotification.
## Examples
iex> delete_unread_notification(unread_notification)
{:ok, %UnreadNotification{}}
iex> delete_unread_notification(unread_notification)
{:error, %Ecto.Changeset{}}
"""
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 """
Returns an `%Ecto.Changeset{}` for tracking unread_notification changes.
## Examples
iex> change_unread_notification(unread_notification)
%Ecto.Changeset{source: %UnreadNotification{}}
"""
def change_unread_notification(%UnreadNotification{} = unread_notification) do
UnreadNotification.changeset(unread_notification, %{})
end
def notify(_actor_child, [], _params), do: nil
def notify(actor_child, subscriptions, params) do
# Don't push to the user that created the notification
subscriptions =
case actor_child do
%{user_id: id} ->
subscriptions
|> Enum.reject(&(&1.user_id == id))
_ ->
subscriptions
end
Repo.transaction(fn ->
notification =
Notification
|> Repo.get_by(actor_id: params.actor_id, actor_type: params.actor_type)
{:ok, notification} =
(notification || %Notification{})
|> update_notification(params)
# Insert the notification to any watchers who do not have it
unreads =
subscriptions
|> Enum.map(&%{user_id: &1.user_id, notification_id: notification.id})
UnreadNotification
|> Repo.insert_all(unreads, on_conflict: :nothing)
end)
end
end