190 lines
4.9 KiB
Elixir
190 lines
4.9 KiB
Elixir
defmodule Clacks.ActivityPub do
|
|
@context ["https://www.w3.org/ns/activitystreams"]
|
|
@public "https://www.w3.org/ns/activitystreams#Public"
|
|
|
|
@spec actor(
|
|
id :: String.t(),
|
|
username :: String.t(),
|
|
display_name :: String.t(),
|
|
pem :: String.t()
|
|
) :: map()
|
|
def actor(id, username, display_name, pem) do
|
|
%{
|
|
"@context" => @context,
|
|
"type" => "Person",
|
|
"id" => id,
|
|
"url" => id,
|
|
"preferredUsername" => username,
|
|
"name" => display_name,
|
|
"followers" => Path.join(id, "followers"),
|
|
"following" => Path.join(id, "following"),
|
|
"inbox" => Path.join(id, "inbox"),
|
|
"outbox" => Path.join(id, "outbox"),
|
|
"publicKey" => %{
|
|
"id" => id <> "#main-key",
|
|
"owner" => id,
|
|
"publicKeyPem" => pem
|
|
}
|
|
}
|
|
end
|
|
|
|
@spec note(
|
|
actor :: String.t(),
|
|
html :: String.t(),
|
|
context :: String.t() | nil,
|
|
in_reply_to :: String.t() | nil,
|
|
mentions :: [{String.t(), Clacks.Actor.t()}],
|
|
id :: String.t() | nil,
|
|
published :: DateTime.t(),
|
|
to :: [String.t()],
|
|
cc :: [String.t()]
|
|
) :: map()
|
|
def note(
|
|
actor,
|
|
html,
|
|
context \\ nil,
|
|
in_reply_to \\ nil,
|
|
mentions \\ [],
|
|
id \\ nil,
|
|
published \\ DateTime.utc_now(),
|
|
to \\ [@public],
|
|
cc \\ []
|
|
) do
|
|
id = id || object_id(Ecto.UUID.generate())
|
|
context = context || context_id(Ecto.UUID.generate())
|
|
|
|
%{
|
|
"@context" => @context,
|
|
"id" => id,
|
|
"url" => id,
|
|
"type" => "Note",
|
|
"actor" => actor,
|
|
"attributedTo" => actor,
|
|
"to" => to,
|
|
"cc" => cc,
|
|
"content" => html,
|
|
"conversation" => context,
|
|
"context" => context,
|
|
"inReplyTo" => in_reply_to,
|
|
"published" => published |> DateTime.to_iso8601(),
|
|
"tag" =>
|
|
Enum.map(mentions, fn {name, actor} ->
|
|
%{
|
|
"href" => actor.ap_id,
|
|
"name" => name,
|
|
"type" => "Mention"
|
|
}
|
|
end)
|
|
}
|
|
end
|
|
|
|
@spec create(
|
|
object :: map(),
|
|
id :: String.t() | nil,
|
|
actor :: String.t() | nil,
|
|
to :: [String.t()] | nil,
|
|
cc :: [String.t()] | nil
|
|
) :: map()
|
|
def create(object, id \\ nil, actor \\ nil, to \\ nil, cc \\ nil) do
|
|
%{
|
|
"@context" => @context,
|
|
"id" => id || activity_id(Ecto.UUID.generate()),
|
|
"actor" => actor || object["actor"],
|
|
"type" => "Create",
|
|
"object" => object,
|
|
"to" => to || object["to"],
|
|
"cc" => cc || object["cc"]
|
|
}
|
|
end
|
|
|
|
@spec synthesized_create(object :: map()) :: map()
|
|
def synthesized_create(object) do
|
|
# todo: does this need to have an id field?
|
|
%{
|
|
"@context" => @context,
|
|
"type" => "Create",
|
|
"object" => object,
|
|
"actor" => object["actor"] || object["attributedTo"],
|
|
"to" => object["to"],
|
|
"cc" => object["cc"]
|
|
}
|
|
end
|
|
|
|
@spec accept_follow(follow_activity :: map()) :: map()
|
|
def accept_follow(%{"type" => "Follow", "object" => followed} = follow_activity) do
|
|
%{
|
|
"@context" => @context,
|
|
"type" => "Accept",
|
|
"id" => activity_id(Ecto.UUID.generate()),
|
|
"actor" => followed,
|
|
"object" => follow_activity
|
|
}
|
|
end
|
|
|
|
@spec follow(
|
|
actor :: String.t(),
|
|
followee :: String.t(),
|
|
published :: DateTime.t(),
|
|
state :: String.t()
|
|
) ::
|
|
map()
|
|
def follow(actor, followee, published \\ DateTime.utc_now(), state \\ "pending") do
|
|
%{
|
|
"@context" => @context,
|
|
"type" => "Follow",
|
|
"id" => activity_id(Ecto.UUID.generate()),
|
|
"actor" => actor,
|
|
"object" => followee,
|
|
"context" => context_id(Ecto.UUID.generate()),
|
|
"to" => [followee],
|
|
"cc" => [@public],
|
|
"published" => published |> DateTime.to_iso8601(),
|
|
"state" => state
|
|
}
|
|
end
|
|
|
|
@spec undo_follow(actor :: String.t(), follow_activity :: map()) :: map()
|
|
def undo_follow(actor, %{"object" => followee} = follow_activity) do
|
|
%{
|
|
"@context" => @context,
|
|
"type" => "Undo",
|
|
"id" => activity_id(Ecto.UUID.generate()),
|
|
"actor" => actor,
|
|
"object" => follow_activity,
|
|
"to" => [followee],
|
|
"cc" => []
|
|
}
|
|
end
|
|
|
|
@spec object_id(id :: String.t()) :: String.t()
|
|
def object_id(id) do
|
|
url = Application.get_env(:clacks, ClacksWeb.Endpoint)[:url]
|
|
|
|
%URI{
|
|
scheme: url[:scheme],
|
|
host: url[:host],
|
|
port: url[:port],
|
|
path: Path.join("/objects", id)
|
|
}
|
|
|> URI.to_string()
|
|
end
|
|
|
|
@spec activity_id(id :: String.t()) :: String.t()
|
|
def activity_id(id) do
|
|
url = Application.get_env(:clacks, ClacksWeb.Endpoint)[:url]
|
|
|
|
%URI{
|
|
scheme: url[:scheme],
|
|
host: url[:host],
|
|
port: url[:port],
|
|
path: Path.join("/activities", id)
|
|
}
|
|
|> URI.to_string()
|
|
end
|
|
|
|
@spec context_id(id :: String.t()) :: String.t()
|
|
def context_id(id) do
|
|
"data:,clickityclack/" <> id
|
|
end
|
|
end
|