246 lines
7.7 KiB
Elixir
246 lines
7.7 KiB
Elixir
defmodule Nulla.ActivityPub do
|
|
@spec context() :: list()
|
|
defp context do
|
|
[
|
|
"https://www.w3.org/ns/activitystreams",
|
|
"https://w3id.org/security/v1",
|
|
Jason.OrderedObject.new(
|
|
manuallyApprovesFollowers: "as:manuallyApprovesFollowers",
|
|
toot: "http://joinmastodon.org/ns#",
|
|
featured: %{"@id" => "toot:featured", "@type" => "@id"},
|
|
featuredTags: %{"@id" => "toot:featuredTags", "@type" => "@id"},
|
|
alsoKnownAs: %{"@id" => "as:alsoKnownAs", "@type" => "@id"},
|
|
movedTo: %{"@id" => "as:movedTo", "@type" => "@id"},
|
|
schema: "http://schema.org#",
|
|
PropertyValue: "schema:PropertyValue",
|
|
value: "schema:value",
|
|
discoverable: "toot:discoverable",
|
|
suspended: "toot:suspended",
|
|
memorial: "toot:memorial",
|
|
indexable: "toot:indexable",
|
|
attributionDomains: %{"@id" => "toot:attributionDomains", "@type" => "@id"},
|
|
Hashtag: "as:Hashtag",
|
|
vcard: "http://www.w3.org/2006/vcard/ns#"
|
|
)
|
|
]
|
|
end
|
|
|
|
@spec user(String.t(), Nulla.Models.User.t()) :: Jason.OrderedObject.t()
|
|
def user(domain, user) do
|
|
Jason.OrderedObject.new(
|
|
"@context": context(),
|
|
id: "https://#{domain}/@#{user.username}",
|
|
type: "Person",
|
|
following: "https://#{domain}/@#{user.username}/following",
|
|
followers: "https://#{domain}/@#{user.username}/followers",
|
|
inbox: "https://#{domain}/@#{user.username}/inbox",
|
|
outbox: "https://#{domain}/@#{user.username}/outbox",
|
|
featured: "https://#{domain}/@#{user.username}/collections/featured",
|
|
preferredUsername: user.username,
|
|
name: user.realname,
|
|
summary: user.bio,
|
|
url: "https://#{domain}/@#{user.username}",
|
|
manuallyApprovesFollowers: user.follow_approval,
|
|
discoverable: user.is_discoverable,
|
|
indexable: user.is_indexable,
|
|
published: DateTime.to_iso8601(user.inserted_at),
|
|
memorial: user.is_memorial,
|
|
publicKey:
|
|
Jason.OrderedObject.new(
|
|
id: "https://#{domain}/@#{user.username}#main-key",
|
|
owner: "https://#{domain}/@#{user.username}",
|
|
publicKeyPem: user.public_key
|
|
),
|
|
tag:
|
|
Enum.map(user.tags, fn tag ->
|
|
Jason.OrderedObject.new(
|
|
type: "Hashtag",
|
|
href: "https://#{domain}/tags/#{tag}",
|
|
name: "##{tag}"
|
|
)
|
|
end),
|
|
attachment:
|
|
Enum.map(user.fields, fn {name, value} ->
|
|
Jason.OrderedObject.new(
|
|
type: "PropertyValue",
|
|
name: name,
|
|
value: value
|
|
)
|
|
end),
|
|
endpoints: Jason.OrderedObject.new(sharedInbox: "https://#{domain}/inbox"),
|
|
icon:
|
|
Jason.OrderedObject.new(
|
|
type: "Image",
|
|
mediaType: MIME.from_path(user.avatar),
|
|
url: "https://#{domain}/files/#{user.avatar}"
|
|
),
|
|
image:
|
|
Jason.OrderedObject.new(
|
|
type: "Image",
|
|
mediaType: MIME.from_path(user.banner),
|
|
url: "https://#{domain}/files/#{user.banner}"
|
|
),
|
|
"vcard:bday": user.birthday,
|
|
"vcard:Address": user.location
|
|
)
|
|
end
|
|
|
|
@spec note(String.t(), Nulla.Models.Note.t()) :: Jason.OrderedObject.t()
|
|
def note(domain, note) do
|
|
attachment =
|
|
case note.media_attachments do
|
|
[] ->
|
|
[]
|
|
|
|
attachments ->
|
|
[
|
|
attachment:
|
|
Enum.map(attachments, fn att ->
|
|
Jason.OrderedObject.new(
|
|
type: "Document",
|
|
mediaType: att.mime_type,
|
|
url: "https://#{domain}/files/#{att.file}"
|
|
)
|
|
end)
|
|
]
|
|
end
|
|
|
|
Jason.OrderedObject.new(
|
|
"@context": [
|
|
"https://www.w3.org/ns/activitystreams",
|
|
Jason.OrderedObject.new(sensitive: "as:sensitive")
|
|
],
|
|
id: "https://#{domain}/@#{note.user.username}/#{note.id}",
|
|
type: "Note",
|
|
summary: nil,
|
|
inReplyTo: nil,
|
|
published: note.inserted_at,
|
|
url: "https://#{domain}/@#{note.user.username}/#{note.id}",
|
|
attributedTo: "https://#{domain}/@#{note.user.username}",
|
|
to: [
|
|
"https://www.w3.org/ns/activitystreams#Public"
|
|
],
|
|
cc: [
|
|
"https://#{domain}/@#{note.user.username}/followers"
|
|
],
|
|
sensetive: false,
|
|
content: note.content,
|
|
contentMap: Jason.OrderedObject.new("#{note.language}": note.content),
|
|
attachment: attachment
|
|
)
|
|
end
|
|
|
|
@spec activity(String.t(), Nulla.Models.Activity.t()) :: Jason.OrderedObject.t()
|
|
def activity(domain, activity) do
|
|
Jason.OrderedObject.new(
|
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
id: "https://#{domain}/activities/#{activity.id}",
|
|
type: activity.type,
|
|
actor: activity.actor,
|
|
object: activity.object,
|
|
to: activity.to
|
|
)
|
|
end
|
|
|
|
@spec following(String.t(), Nulla.Models.User.t(), Integer.t()) :: Jason.OrderedObject.t()
|
|
def following(domain, user, total) do
|
|
Jason.OrderedObject.new(
|
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
id: "https://#{domain}/@#{user.username}/following",
|
|
type: "OrderedCollection",
|
|
totalItems: total,
|
|
first: "https://#{domain}/@#{user.username}/following?page=1"
|
|
)
|
|
end
|
|
|
|
@spec following(
|
|
String.t(),
|
|
Nulla.Models.User.t(),
|
|
Integer.t(),
|
|
List.t(),
|
|
Integer.t(),
|
|
Integer.t()
|
|
) :: Jason.OrderedObject.t()
|
|
def following(domain, user, total, following_list, page, offset)
|
|
when is_integer(page) and page > 0 do
|
|
data = [
|
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
id: "https://#{domain}/@#{user.username}/following?page=#{page}",
|
|
type: "OrderedCollectionPage",
|
|
totalItems: total,
|
|
next: "https://#{domain}/@#{user.username}/following?page=#{page + 1}",
|
|
prev: "https://#{domain}/@#{user.username}/following?page=#{page - 1}",
|
|
partOf: "https://#{domain}/@#{user.username}/following",
|
|
orderedItems: following_list
|
|
]
|
|
|
|
data =
|
|
if page <= 1 do
|
|
Keyword.delete(data, :prev)
|
|
else
|
|
data
|
|
end
|
|
|
|
data =
|
|
if page * offset > total do
|
|
data
|
|
|> Keyword.delete(:next)
|
|
|> Keyword.delete(:prev)
|
|
else
|
|
data
|
|
end
|
|
|
|
Jason.OrderedObject.new(data)
|
|
end
|
|
|
|
@spec followers(String.t(), Nulla.Models.User.t(), Integer.t()) :: Jason.OrderedObject.t()
|
|
def followers(domain, user, total) do
|
|
Jason.OrderedObject.new(
|
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
id: "https://#{domain}/@#{user.username}/followers",
|
|
type: "OrderedCollection",
|
|
totalItems: total,
|
|
first: "https://#{domain}/@#{user.username}/followers?page=1"
|
|
)
|
|
end
|
|
|
|
@spec followers(
|
|
String.t(),
|
|
Nulla.Models.User.t(),
|
|
Integer.t(),
|
|
List.t(),
|
|
Integer.t(),
|
|
Integer.t()
|
|
) :: Jason.OrderedObject.t()
|
|
def followers(domain, user, total, followers_list, page, offset)
|
|
when is_integer(page) and page > 0 do
|
|
data = [
|
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
id: "https://#{domain}/@#{user.username}/followers?page=#{page}",
|
|
type: "OrderedCollectionPage",
|
|
totalItems: total,
|
|
next: "https://#{domain}/@#{user.username}/followers?page=#{page + 1}",
|
|
prev: "https://#{domain}/@#{user.username}/followers?page=#{page - 1}",
|
|
partOf: "https://#{domain}/@#{user.username}/followers",
|
|
orderedItems: followers_list
|
|
]
|
|
|
|
data =
|
|
if page <= 1 do
|
|
Keyword.delete(data, :prev)
|
|
else
|
|
data
|
|
end
|
|
|
|
data =
|
|
if page * offset > total do
|
|
data
|
|
|> Keyword.delete(:next)
|
|
|> Keyword.delete(:prev)
|
|
else
|
|
data
|
|
end
|
|
|
|
Jason.OrderedObject.new(data)
|
|
end
|
|
end
|