Update
This commit is contained in:
parent
188bc08494
commit
4af88f3e1d
44 changed files with 1041 additions and 34 deletions
21
lib/nulla_web/controllers/activitypub/activity_json.ex
Normal file
21
lib/nulla_web/controllers/activitypub/activity_json.ex
Normal file
|
@ -0,0 +1,21 @@
|
|||
defmodule NullaWeb.ActivityPub.ActivityJSON do
|
||||
alias Nulla.Activities.Activity
|
||||
|
||||
@doc """
|
||||
Renders a single activity.
|
||||
"""
|
||||
def show(activity) do
|
||||
data(activity)
|
||||
end
|
||||
|
||||
defp data(%Activity{} = activity) do
|
||||
Jason.OrderedObject.new(
|
||||
id: activity.ap_id,
|
||||
type: activity.type,
|
||||
actor: activity.actor,
|
||||
object: activity.object,
|
||||
to: activity.to,
|
||||
cc: activity.cc
|
||||
)
|
||||
end
|
||||
end
|
22
lib/nulla_web/controllers/activitypub/actor_controller.ex
Normal file
22
lib/nulla_web/controllers/activitypub/actor_controller.ex
Normal file
|
@ -0,0 +1,22 @@
|
|||
defmodule NullaWeb.ActivityPub.ActorController do
|
||||
use NullaWeb, :controller
|
||||
alias NullaWeb.ActivityPub.ActorJSON
|
||||
alias Nulla.Actors
|
||||
alias Nulla.Actors.Actor
|
||||
|
||||
def show(conn, %{"username" => username}) do
|
||||
domain = NullaWeb.Endpoint.host()
|
||||
|
||||
case Actors.get_actor_by(acct: "#{username}@#{domain}") do
|
||||
nil ->
|
||||
conn
|
||||
|> put_status(:not_found)
|
||||
|> json(%{error: "Not Found"})
|
||||
|
||||
%Actor{} = actor ->
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> send_resp(200, Jason.encode!(ActorJSON.show(actor)))
|
||||
end
|
||||
end
|
||||
end
|
54
lib/nulla_web/controllers/activitypub/actor_json.ex
Normal file
54
lib/nulla_web/controllers/activitypub/actor_json.ex
Normal file
|
@ -0,0 +1,54 @@
|
|||
defmodule NullaWeb.ActivityPub.ActorJSON do
|
||||
alias Nulla.Actors.Actor
|
||||
|
||||
@doc """
|
||||
Renders a single actor.
|
||||
"""
|
||||
def show(actor) do
|
||||
data(actor)
|
||||
end
|
||||
|
||||
defp data(%Actor{} = actor) do
|
||||
Jason.OrderedObject.new(
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
Jason.OrderedObject.new(
|
||||
manuallyApprovesFollowers: "as:manuallyApprovesFollowers",
|
||||
alsoKnownAs: %{"@id" => "as:alsoKnownAs", "@type" => "@id"},
|
||||
movedTo: %{"@id" => "as:movedTo", "@type" => "@id"},
|
||||
schema: "http://schema.org#",
|
||||
PropertyValue: "schema:PropertyValue",
|
||||
value: "schema:value",
|
||||
Hashtag: "as:Hashtag",
|
||||
vcard: "http://www.w3.org/2006/vcard/ns#"
|
||||
)
|
||||
],
|
||||
ap_id: actor.ap_id,
|
||||
type: actor.type,
|
||||
following: actor.following,
|
||||
followers: actor.followers,
|
||||
inbox: actor.inbox,
|
||||
outbox: actor.outbox,
|
||||
featured: actor.featured,
|
||||
featuredTags: actor.featuredTags,
|
||||
preferredUsername: actor.preferredUsername,
|
||||
name: actor.name,
|
||||
summary: actor.summary,
|
||||
url: actor.url,
|
||||
manuallyApprovesFollowers: actor.manuallyApprovesFollowers,
|
||||
discoverable: actor.discoverable,
|
||||
indexable: actor.indexable,
|
||||
published: actor.published,
|
||||
memorial: actor.memorial,
|
||||
publicKey: actor.publicKey,
|
||||
tag: actor.tag,
|
||||
attachment: actor.attachment,
|
||||
endpoints: actor.endpoints,
|
||||
icon: actor.icon,
|
||||
image: actor.image,
|
||||
"vcard:bday": actor.vcard_bday,
|
||||
"vcard:Address": actor.vcard_Address
|
||||
)
|
||||
end
|
||||
end
|
64
lib/nulla_web/controllers/activitypub/follow_controller.ex
Normal file
64
lib/nulla_web/controllers/activitypub/follow_controller.ex
Normal file
|
@ -0,0 +1,64 @@
|
|||
defmodule NullaWeb.ActivityPub.FollowController do
|
||||
use NullaWeb, :controller
|
||||
alias NullaWeb.ActivityPub.FollowJSON
|
||||
alias Nulla.Actors
|
||||
alias Nulla.Relations
|
||||
|
||||
def following(conn, %{"username" => username, "page" => page_param}) do
|
||||
domain = NullaWeb.Endpoint.host()
|
||||
limit = Application.get_env(:nulla, :instance)[:api_limit]
|
||||
actor = Actors.get_actor_by(acct: "#{username}@#{domain}")
|
||||
total = Relations.count_following(actor.id)
|
||||
|
||||
page =
|
||||
case Integer.parse(page_param) do
|
||||
{int, _} when int > 0 -> int
|
||||
_ -> 1
|
||||
end
|
||||
|
||||
following_list = Enum.map(Relations.get_following(actor.id, page, limit), & &1.ap_id)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(FollowJSON.following(actor, total, following_list, page, limit))
|
||||
end
|
||||
|
||||
def following(conn, %{"username" => username}) do
|
||||
domain = NullaWeb.Endpoint.host()
|
||||
actor = Actors.get_actor_by(acct: "#{username}@#{domain}")
|
||||
total = Relations.count_following(actor.id)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(FollowJSON.following(actor, total))
|
||||
end
|
||||
|
||||
def followers(conn, %{"username" => username, "page" => page_param}) do
|
||||
domain = NullaWeb.Endpoint.host()
|
||||
limit = Application.get_env(:nulla, :instance)[:api_limit]
|
||||
actor = Actors.get_actor_by(acct: "#{username}@#{domain}")
|
||||
total = Relations.count_followers(actor.id)
|
||||
|
||||
page =
|
||||
case Integer.parse(page_param) do
|
||||
{int, _} when int > 0 -> int
|
||||
_ -> 1
|
||||
end
|
||||
|
||||
followers_list = Enum.map(Relations.get_followers(actor.id, page, limit), & &1.ap_id)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(FollowJSON.followers(actor, total, followers_list, page, limit))
|
||||
end
|
||||
|
||||
def followers(conn, %{"username" => username}) do
|
||||
domain = NullaWeb.Endpoint.host()
|
||||
actor = Actors.get_actor_by(acct: "#{username}@#{domain}")
|
||||
total = Relations.count_followers(actor.id)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(FollowJSON.followers(actor, total))
|
||||
end
|
||||
end
|
84
lib/nulla_web/controllers/activitypub/follow_json.ex
Normal file
84
lib/nulla_web/controllers/activitypub/follow_json.ex
Normal file
|
@ -0,0 +1,84 @@
|
|||
defmodule NullaWeb.ActivityPub.FollowJSON do
|
||||
def following(actor, total) do
|
||||
Jason.OrderedObject.new(
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
id: "#{actor.ap_id}/following",
|
||||
type: "OrderedCollection",
|
||||
totalItems: total,
|
||||
first: "#{actor.ap_id}/following?page=1"
|
||||
)
|
||||
end
|
||||
|
||||
def following(actor, total, following_list, page, limit) when is_integer(page) and page > 0 do
|
||||
data = [
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
id: "#{actor.ap_id}/following?page=#{page}",
|
||||
type: "OrderedCollectionPage",
|
||||
totalItems: total,
|
||||
next: "#{actor.ap_id}/following?page=#{page + 1}",
|
||||
prev: "#{actor.ap_id}/following?page=#{page - 1}",
|
||||
partOf: "#{actor.ap_id}/following",
|
||||
orderedItems: following_list
|
||||
]
|
||||
|
||||
data =
|
||||
if page <= 1 do
|
||||
Keyword.delete(data, :prev)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
data =
|
||||
if page * limit > total do
|
||||
data
|
||||
|> Keyword.delete(:next)
|
||||
|> Keyword.delete(:prev)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
Jason.OrderedObject.new(data)
|
||||
end
|
||||
|
||||
def followers(actor, total) do
|
||||
Jason.OrderedObject.new(
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
id: "#{actor.ap_id}/followers",
|
||||
type: "OrderedCollection",
|
||||
totalItems: total,
|
||||
first: "#{actor.ap_id}/followers?page=1"
|
||||
)
|
||||
end
|
||||
|
||||
def followers(actor, total, followers_list, page, limit)
|
||||
when is_integer(page) and page > 0 do
|
||||
data = [
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
id: "#{actor.ap_id}/followers?page=#{page}",
|
||||
type: "OrderedCollectionPage",
|
||||
totalItems: total,
|
||||
next: "#{actor.ap_id}/followers?page=#{page + 1}",
|
||||
prev: "#{actor.ap_id}/followers?page=#{page - 1}",
|
||||
partOf: "#{actor.ap_id}/followers",
|
||||
orderedItems: followers_list
|
||||
]
|
||||
|
||||
data =
|
||||
if page <= 1 do
|
||||
Keyword.delete(data, :prev)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
data =
|
||||
if page * limit > total do
|
||||
data
|
||||
|> Keyword.delete(:next)
|
||||
|> Keyword.delete(:prev)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
Jason.OrderedObject.new(data)
|
||||
end
|
||||
end
|
243
lib/nulla_web/controllers/activitypub/inbox_controller.ex
Normal file
243
lib/nulla_web/controllers/activitypub/inbox_controller.ex
Normal file
|
@ -0,0 +1,243 @@
|
|||
defmodule NullaWeb.ActivityPub.InboxController do
|
||||
use NullaWeb, :controller
|
||||
alias Nulla.Snowflake
|
||||
alias Nulla.HTTPSignature
|
||||
alias Nulla.Sender
|
||||
alias Nulla.Utils
|
||||
alias Nulla.Actors
|
||||
alias Nulla.Relations
|
||||
alias Nulla.Activities
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _create_id,
|
||||
"type" => "Create",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _read_id,
|
||||
"type" => "Read",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _update_id,
|
||||
"type" => "Update",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _delete_id,
|
||||
"type" => "Delete",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _add_id,
|
||||
"type" => "Add",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _view_id,
|
||||
"type" => "View",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _move_id,
|
||||
"type" => "Move",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _undo_id,
|
||||
"type" => "Undo",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => follow_id,
|
||||
"type" => "Follow",
|
||||
"actor" => actor_uri,
|
||||
"object" => target_uri
|
||||
}) do
|
||||
accept_id = Snowflake.next_id()
|
||||
|
||||
with local_actor <- Actors.get_actor_by(ap_id: target_uri),
|
||||
{:ok, remote_actor_json} <- Utils.fetch_remote_actor(actor_uri),
|
||||
:ok <- HTTPSignature.verify(conn, remote_actor_json["publicKey"]["publicKeyPem"]) do
|
||||
remote_actor =
|
||||
case Actors.get_actor_by(ap_id: remote_actor_json["id"]) do
|
||||
nil ->
|
||||
case Actors.create_actor(remote_actor_json) do
|
||||
{:ok, actor} -> actor
|
||||
{:error, error} -> {:error, error}
|
||||
end
|
||||
|
||||
actor ->
|
||||
actor
|
||||
end
|
||||
|
||||
with {:ok, follow_activity} <-
|
||||
Activities.create_activity(%{
|
||||
ap_id: follow_id,
|
||||
type: "Follow",
|
||||
actor: remote_actor.ap_id,
|
||||
object: target_uri
|
||||
}),
|
||||
{:ok, accept_activity} <-
|
||||
Activities.create_activity(%{
|
||||
id: accept_id,
|
||||
ap_id: "https://#{local_actor.domain}/activities/accept/#{accept_id}",
|
||||
type: "Accept",
|
||||
actor: local_actor.ap_id,
|
||||
object: Jason.encode!(follow_activity)
|
||||
}) do
|
||||
{:ok, _relation} =
|
||||
case Relations.get_relation_by(%{
|
||||
local_actor_id: local_actor.id,
|
||||
remote_actor_id: remote_actor.id
|
||||
}) do
|
||||
nil ->
|
||||
case Relations.create_relation(%{
|
||||
local_actor_id: local_actor.id,
|
||||
remote_actor_id: remote_actor.id,
|
||||
followed_by: true
|
||||
}) do
|
||||
{:ok, relation} -> relation
|
||||
{:error, changeset} -> {:error, {:relation_creation_failed, changeset}}
|
||||
end
|
||||
|
||||
relation ->
|
||||
Relations.update_relation(relation, %{followed_by: true})
|
||||
end
|
||||
|
||||
Sender.send_activity(
|
||||
:post,
|
||||
remote_actor.inbox,
|
||||
accept_activity,
|
||||
local_actor.publicKey["id"],
|
||||
local_actor.privateKeyPem
|
||||
)
|
||||
|
||||
send_resp(conn, 200, "")
|
||||
else
|
||||
error ->
|
||||
json(conn, %{"error" => "Failed to process Follow: #{error}"})
|
||||
end
|
||||
else
|
||||
error ->
|
||||
json(conn, %{"error" => "Failed to process Follow: #{error}"})
|
||||
end
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _accept_id,
|
||||
"type" => "Accept",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _reject_id,
|
||||
"type" => "Reject",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _block_id,
|
||||
"type" => "Block",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _join_id,
|
||||
"type" => "Join",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _leave_id,
|
||||
"type" => "Leave",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _like_id,
|
||||
"type" => "Like",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _dislike_id,
|
||||
"type" => "Dislike",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _announce_id,
|
||||
"type" => "Announce",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, %{
|
||||
"id" => _question_id,
|
||||
"type" => "Question",
|
||||
"actor" => _actor_uri,
|
||||
"object" => _target_uri
|
||||
}) do
|
||||
send_resp(conn, 200, "")
|
||||
end
|
||||
|
||||
def inbox(conn, _params) do
|
||||
send_resp(conn, 400, "")
|
||||
end
|
||||
end
|
38
lib/nulla_web/controllers/activitypub/note_controller.ex
Normal file
38
lib/nulla_web/controllers/activitypub/note_controller.ex
Normal file
|
@ -0,0 +1,38 @@
|
|||
defmodule NullaWeb.ActivityPub.NoteController do
|
||||
use NullaWeb, :controller
|
||||
alias Nulla.Repo
|
||||
alias NullaWeb.ActivityPub.NoteJSON
|
||||
alias Nulla.Notes
|
||||
|
||||
def show(conn, %{"username" => username, "id" => id}) do
|
||||
case Integer.parse(id) do
|
||||
{int_id, ""} ->
|
||||
note = Notes.get_note!(int_id) |> Repo.preload([:actor, :media_attachments])
|
||||
|
||||
cond do
|
||||
is_nil(note) ->
|
||||
conn
|
||||
|> put_status(:not_found)
|
||||
|> json(%{error: "Not Found"})
|
||||
|> halt()
|
||||
|
||||
username != note.actor.preferredUsername ->
|
||||
conn
|
||||
|> put_status(:not_found)
|
||||
|> json(%{error: "Not Found"})
|
||||
|> halt()
|
||||
|
||||
true ->
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(NoteJSON.show(note))
|
||||
end
|
||||
|
||||
_ ->
|
||||
conn
|
||||
|> put_status(:not_found)
|
||||
|> json(%{error: "Not Found"})
|
||||
|> halt()
|
||||
end
|
||||
end
|
||||
end
|
50
lib/nulla_web/controllers/activitypub/note_json.ex
Normal file
50
lib/nulla_web/controllers/activitypub/note_json.ex
Normal file
|
@ -0,0 +1,50 @@
|
|||
defmodule NullaWeb.ActivityPub.NoteJSON do
|
||||
alias Nulla.Notes.Note
|
||||
|
||||
@doc """
|
||||
Renders a single note.
|
||||
"""
|
||||
def show(note) do
|
||||
data(note)
|
||||
end
|
||||
|
||||
defp data(%Note{} = 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://#{note.actor.domain}/files/#{att.file}"
|
||||
)
|
||||
end)
|
||||
]
|
||||
end
|
||||
|
||||
Jason.OrderedObject.new(
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
Jason.OrderedObject.new(sensitive: "as:sensitive")
|
||||
],
|
||||
id: "#{note.actor.ap_id}/notes/#{note.id}",
|
||||
type: "Note",
|
||||
summary: nil,
|
||||
inReplyTo: note.inReplyTo,
|
||||
published: note.published,
|
||||
url: note.url,
|
||||
attributedTo: note.actor.ap_id,
|
||||
to: note.to,
|
||||
cc: note.cc,
|
||||
sensitive: note.sensitive,
|
||||
content: note.content,
|
||||
contentMap: Jason.OrderedObject.new("#{note.language}": note.content),
|
||||
attachment: attachment
|
||||
)
|
||||
end
|
||||
end
|
57
lib/nulla_web/controllers/activitypub/outbox_controller.ex
Normal file
57
lib/nulla_web/controllers/activitypub/outbox_controller.ex
Normal file
|
@ -0,0 +1,57 @@
|
|||
defmodule NullaWeb.ActivityPub.OutboxController do
|
||||
use NullaWeb, :controller
|
||||
alias NullaWeb.ActivityPub.OutboxJSON
|
||||
alias Nulla.Actors
|
||||
alias Nulla.Activities
|
||||
alias Nulla.Actors.Actor
|
||||
|
||||
def index(conn, %{"username" => username, "page" => "true"} = params) do
|
||||
domain = NullaWeb.Endpoint.host()
|
||||
actor = Actors.get_actor_by(acct: "#{username}@#{domain}")
|
||||
|
||||
max_id = params["max_id"] && String.to_integer(params["max_id"])
|
||||
|
||||
activities =
|
||||
if max_id do
|
||||
Activities.get_before_activities(actor.ap_id, max_id)
|
||||
else
|
||||
Activities.get_latest_activities(actor.ap_id)
|
||||
end
|
||||
|
||||
next_max_id =
|
||||
case List.last(activities) do
|
||||
nil -> 0
|
||||
last -> last.id
|
||||
end
|
||||
|
||||
min_id =
|
||||
case List.first(activities) do
|
||||
nil -> 0
|
||||
first -> first.id
|
||||
end
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> send_resp(
|
||||
200,
|
||||
Jason.encode!(OutboxJSON.show(actor, activities, next_max_id, min_id))
|
||||
)
|
||||
end
|
||||
|
||||
def index(conn, %{"username" => username}) do
|
||||
domain = NullaWeb.Endpoint.host()
|
||||
actor = Actors.get_actor_by(acct: "#{username}@#{domain}")
|
||||
|
||||
case actor do
|
||||
%Actor{} = actor ->
|
||||
total = Activities.get_total_activities_count(actor.ap_id)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> send_resp(200, Jason.encode!(OutboxJSON.index(actor, total)))
|
||||
|
||||
_ ->
|
||||
send_resp(conn, 404, "")
|
||||
end
|
||||
end
|
||||
end
|
44
lib/nulla_web/controllers/activitypub/outbox_json.ex
Normal file
44
lib/nulla_web/controllers/activitypub/outbox_json.ex
Normal file
|
@ -0,0 +1,44 @@
|
|||
defmodule NullaWeb.ActivityPub.OutboxJSON do
|
||||
@doc """
|
||||
Renders an outbox.
|
||||
"""
|
||||
def index(actor, total) do
|
||||
Jason.OrderedObject.new(
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
id: actor.outbox,
|
||||
type: "OrderedCollection",
|
||||
totalItems: total,
|
||||
first: "#{actor.outbox}?page=true",
|
||||
last: "#{actor.outbox}?min_id=0&page=true"
|
||||
)
|
||||
end
|
||||
|
||||
def show(actor, activities, max_id, min_id) do
|
||||
Jason.OrderedObject.new(
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
Jason.OrderedObject.new(
|
||||
sensitive: "as:sensitive",
|
||||
Hashtag: "as:Hashtag"
|
||||
)
|
||||
],
|
||||
id: "#{actor.outbox}?page=true",
|
||||
type: "OrderedCollectionPage",
|
||||
next: "#{actor.outbox}?max_id=#{max_id}&page=true",
|
||||
prev: "#{actor.outbox}?min_id=#{min_id}&page=true",
|
||||
partOf: actor.outbox,
|
||||
orderedItems: Enum.map(activities, &data/1)
|
||||
)
|
||||
end
|
||||
|
||||
defp data(activity) do
|
||||
Jason.OrderedObject.new(
|
||||
id: activity.ap_id,
|
||||
type: activity.type,
|
||||
actor: activity.actor,
|
||||
object: activity.object,
|
||||
to: activity.to,
|
||||
cc: activity.cc
|
||||
)
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue