clacks/lib/clacks/notification.ex

101 lines
2.7 KiB
Elixir

defmodule Clacks.Notification do
use Ecto.Schema
import Ecto.Changeset
alias Clacks.{Activity, Actor, Repo}
@type t() :: %__MODULE__{}
@valid_types ["follow", "mention", "announce", "like"]
schema "notifications" do
field :type, :string
belongs_to :user, Clacks.User
belongs_to :activity, Clacks.Activity, type: FlakeId.Ecto.Type
belongs_to :referenced_activity, Clacks.Activity, type: FlakeId.Ecto.Type
timestamps()
end
def changeset(%__MODULE__{} = schema, attrs) do
schema
|> cast(attrs, [:type, :user_id, :activity_id, :referenced_activity_id])
|> validate_required([:type, :user_id, :activity_id])
|> validate_inclusion(:type, @valid_types)
end
@spec create(
type :: String.t(),
activity :: Activity.t(),
actor :: Actor.t(),
referenced_activity :: Activity.t() | nil
) ::
{:ok, Notification.t()} | {:error, any()}
def create(type, _, _, _) when not (type in @valid_types) do
{:error, "invalid notification type '#{type}'"}
end
def create(type, activity, actor, referenced_activity) do
changeset =
changeset(%__MODULE__{}, %{
type: type,
user_id: actor.user_id,
activity_id: activity.id,
referenced_activity_id: if(referenced_activity, do: referenced_activity.id, else: nil)
})
Repo.insert(changeset)
end
def process_notifications_for_incoming(
%Activity{
data: %{"type" => "Follow", "object" => followee_ap_id}
} = activity
) do
case Actor.get_cached_by_ap_id(followee_ap_id) do
%Actor{local: true} = followee ->
create("follow", activity, followee, nil)
_ ->
:ok
end
end
def process_notifications_for_incoming(
%Activity{data: %{"type" => "Create", "object" => %{"type" => "Note", "tag" => tags}}} =
activity
) do
Enum.each(tags, fn %{"href" => mentioned_actor_id} ->
case Actor.get_cached_by_ap_id(mentioned_actor_id) do
%Actor{local: true} = mentioned_actor ->
create("mention", activity, mentioned_actor, nil)
_ ->
:ok
end
end)
end
def process_notifications_for_incoming(
%Activity{data: %{"type" => type, "object" => original_object_ap_id}} = activity
)
when type in ["Announce", "Like"] do
with %Activity{local: true, actor: %Actor{local: true} = original_activity_actor} =
original_activity <-
Activity.get_by_object_ap_id(original_object_ap_id, "Create") do
create(
String.downcase(type),
activity,
original_activity_actor,
original_activity
)
else
_ ->
:ok
end
end
def process_notifications_for_incoming(_), do: :ok
end