164 lines
4.3 KiB
Elixir
164 lines
4.3 KiB
Elixir
defmodule Nulla.Models.Actor do
|
|
use Ecto.Schema
|
|
import Ecto.Changeset
|
|
alias Nulla.Repo
|
|
alias Nulla.Snowflake
|
|
alias Nulla.Models.Note
|
|
|
|
@primary_key {:id, :integer, autogenerate: false}
|
|
schema "actors" do
|
|
field :domain, :string
|
|
field :ap_id, :string
|
|
field :type, :string
|
|
field :following, :string
|
|
field :followers, :string
|
|
field :inbox, :string
|
|
field :outbox, :string
|
|
field :featured, :string
|
|
field :featuredTags, :string
|
|
field :preferredUsername, :string
|
|
field :name, :string
|
|
field :summary, :string
|
|
field :url, :string
|
|
field :manuallyApprovesFollowers, :boolean
|
|
field :discoverable, :boolean, default: true
|
|
field :indexable, :boolean, default: true
|
|
field :published, :utc_datetime
|
|
field :memorial, :boolean, default: false
|
|
field :publicKey, :map
|
|
field :tag, {:array, :map}, default: []
|
|
field :attachment, {:array, :map}, default: []
|
|
field :endpoints, :map
|
|
field :icon, :map
|
|
field :image, :map
|
|
field :vcard_bday, :date
|
|
field :vcard_Address, :string
|
|
|
|
has_many :notes, Note
|
|
has_many :media_attachments, through: [:notes, :media_attachments]
|
|
end
|
|
|
|
@doc false
|
|
def changeset(actor, attrs) do
|
|
actor
|
|
|> cast(attrs, [
|
|
:id,
|
|
:domain,
|
|
:ap_id,
|
|
:type,
|
|
:following,
|
|
:followers,
|
|
:inbox,
|
|
:outbox,
|
|
:featured,
|
|
:featuredTags,
|
|
:preferredUsername,
|
|
:name,
|
|
:summary,
|
|
:url,
|
|
:manuallyApprovesFollowers,
|
|
:discoverable,
|
|
:indexable,
|
|
:published,
|
|
:memorial,
|
|
:publicKey,
|
|
:tag,
|
|
:attachment,
|
|
:endpoints,
|
|
:icon,
|
|
:image,
|
|
:vcard_bday,
|
|
:vcard_Address
|
|
])
|
|
|> validate_required([
|
|
:domain,
|
|
:ap_id,
|
|
:type,
|
|
:following,
|
|
:followers,
|
|
:inbox,
|
|
:outbox,
|
|
:preferredUsername,
|
|
:url,
|
|
:publicKey,
|
|
:endpoints
|
|
])
|
|
|> unique_constraint([:preferredUsername, :domain])
|
|
|> unique_constraint(:ap_id)
|
|
end
|
|
|
|
def create_actor(attrs) when is_map(attrs) do
|
|
id = Map.get(attrs, :id, Snowflake.next_id())
|
|
|
|
%__MODULE__{}
|
|
|> changeset(attrs)
|
|
|> put_change(:id, id)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def create_actor_minimal(username, domain, publicKeyPem) do
|
|
id = Snowflake.next_id()
|
|
|
|
attrs = %{
|
|
id: id,
|
|
domain: domain,
|
|
ap_id: "https://#{domain}/users/#{username}",
|
|
type: "Person",
|
|
following: "https://#{domain}/users/#{username}/following",
|
|
followers: "https://#{domain}/users/#{username}/followers",
|
|
inbox: "https://#{domain}/users/#{username}/inbox",
|
|
outbox: "https://#{domain}/users/#{username}/outbox",
|
|
featured: "https://#{domain}/users/#{username}/collections/featured",
|
|
featuredTags: "https://#{domain}/users/#{username}/collections/tags",
|
|
preferredUsername: username,
|
|
url: "https://#{domain}/@#{username}",
|
|
manuallyApprovesFollowers: false,
|
|
discoverable: true,
|
|
indexable: true,
|
|
published: DateTime.utc_now(),
|
|
memorial: false,
|
|
publicKey:
|
|
Jason.OrderedObject.new(
|
|
id: "https://#{domain}/users/#{username}#main-key",
|
|
owner: "https://#{domain}/users/#{username}",
|
|
publicKeyPem: publicKeyPem
|
|
),
|
|
endpoints: Jason.OrderedObject.new(sharedInbox: "https://#{domain}/inbox")
|
|
}
|
|
|
|
%__MODULE__{}
|
|
|> changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def get_actor(by) when is_map(by) or is_list(by) do
|
|
Repo.get_by(__MODULE__, by)
|
|
end
|
|
|
|
def get_or_create_actor(%{"id" => ap_id} = actor_json) when is_binary(ap_id) do
|
|
case get_actor(ap_id: ap_id) do
|
|
nil ->
|
|
params =
|
|
actor_json
|
|
|> Map.put("ap_id", ap_id)
|
|
|> Map.delete("id")
|
|
|> Map.put("domain", URI.parse(ap_id).host)
|
|
|
|
case create_actor(params) do
|
|
{:ok, actor} -> {:ok, actor}
|
|
{:error, changeset} -> {:error, {:actor_creation_failed, changeset}}
|
|
end
|
|
|
|
actor ->
|
|
updates =
|
|
actor_json
|
|
|> Map.delete("id")
|
|
|> Map.put("domain", URI.parse(ap_id).host)
|
|
|
|
case changeset(actor, updates) |> Repo.update() do
|
|
{:ok, updated_actor} -> {:ok, updated_actor}
|
|
{:error, changeset} -> {:error, {:actor_update_failed, changeset}}
|
|
end
|
|
end
|
|
end
|
|
end
|