90 lines
2.3 KiB
Elixir
90 lines
2.3 KiB
Elixir
defmodule Clacks.Actor do
|
|
require Logger
|
|
use Ecto.Schema
|
|
import Ecto.Changeset
|
|
import Ecto.Query
|
|
alias Clacks.Repo
|
|
|
|
@type t() :: %__MODULE__{
|
|
ap_id: String.t(),
|
|
nickname: String.t(),
|
|
local: boolean(),
|
|
data: map(),
|
|
followers: [String.t()],
|
|
user: Clacks.User.t()
|
|
}
|
|
|
|
@primary_key {:id, FlakeId.Ecto.Type, autogenerate: true}
|
|
|
|
schema "actors" do
|
|
field :ap_id, :string
|
|
field :nickname, :string
|
|
field :local, :boolean
|
|
field :data, :map
|
|
field :followers, {:array, :string}, default: []
|
|
|
|
belongs_to :user, Clacks.User
|
|
|
|
timestamps()
|
|
end
|
|
|
|
def changeset(%__MODULE__{} = schema, attrs) do
|
|
schema
|
|
|> cast(attrs, [:ap_id, :nickname, :local, :data, :followers])
|
|
|> validate_required([:ap_id, :nickname, :local, :data])
|
|
end
|
|
|
|
@spec get_by_nickname(nickname :: String.t()) :: t() | nil
|
|
def get_by_nickname(nickname) do
|
|
Repo.get_by(__MODULE__, nickname: nickname)
|
|
end
|
|
|
|
@spec get_by_ap_id(ap_id :: String.t(), force_refetch :: boolean()) :: t() | nil
|
|
def get_by_ap_id(ap_id, force_refetch \\ false) do
|
|
if force_refetch do
|
|
fetch(ap_id)
|
|
else
|
|
get_cached_by_ap_id(ap_id) || fetch(ap_id)
|
|
end
|
|
end
|
|
|
|
@spec get_cached_by_ap_id(ap_id :: String.t()) :: t() | nil
|
|
def get_cached_by_ap_id(ap_id) do
|
|
Repo.get_by(__MODULE__, ap_id: ap_id)
|
|
end
|
|
|
|
@spec fetch(ap_id :: String.t()) :: t() | nil
|
|
def fetch(ap_id) do
|
|
case Clacks.ActivityPub.Fetcher.fetch_actor(ap_id) do
|
|
nil ->
|
|
nil
|
|
|
|
data ->
|
|
ap_id = data["id"]
|
|
existing = get_cached_by_ap_id(ap_id) |> Repo.preload(:user)
|
|
|
|
changeset =
|
|
changeset(existing || %__MODULE__{}, %{
|
|
ap_id: ap_id,
|
|
nickname: data["preferredUsername"] <> "@" <> URI.parse(ap_id).host,
|
|
local: false,
|
|
data: data
|
|
})
|
|
|
|
case Repo.insert_or_update(changeset) do
|
|
{:ok, actor} ->
|
|
actor
|
|
|
|
{:error, changeset} ->
|
|
Logger.error("Couldn't store remote actor #{ap_id}: #{inspect(changeset)}")
|
|
nil
|
|
end
|
|
end
|
|
end
|
|
|
|
@spec get_all_following(actor :: t()) :: [t()]
|
|
def get_all_following(actor) do
|
|
Repo.all(from a in __MODULE__, where: ^actor.ap_id in a.followers)
|
|
end
|
|
end
|