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