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(%UnreadNotification{} = unread_notification) do Repo.delete(unread_notification) 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