123 lines
3.0 KiB
Elixir
123 lines
3.0 KiB
Elixir
defmodule ClacksWeb.ActorController do
|
|
use ClacksWeb, :controller
|
|
alias Clacks.{Actor, User, Repo}
|
|
|
|
@context "https://www.w3.org/ns/activitystreams"
|
|
|
|
plug :get_actor
|
|
|
|
defp get_actor(%Plug.Conn{path_params: %{"username" => username}} = conn, _opts) do
|
|
case User.get_by_username(username) |> Repo.preload(:actor) do
|
|
nil ->
|
|
conn
|
|
|> put_status(404)
|
|
|> halt()
|
|
|
|
%User{actor: actor} ->
|
|
assign(conn, :actor, actor)
|
|
end
|
|
end
|
|
|
|
defp get_actor(conn, _opts), do: conn
|
|
|
|
def get(%Plug.Conn{assigns: %{format: "activity+json"}} = conn, _params) do
|
|
actor = conn.assigns[:actor]
|
|
|
|
conn
|
|
|> put_resp_header("content-type", "application/activity+json")
|
|
|> json(actor.data)
|
|
end
|
|
|
|
def get(%Plug.Conn{assigns: %{format: "html"}} = conn, _params) do
|
|
conn
|
|
|> put_view(ClacksWeb.FrontendView)
|
|
|> ClacksWeb.FrontendController.call(:profile)
|
|
end
|
|
|
|
def followers(conn, %{"page" => page}) do
|
|
{page, _} = Integer.parse(page)
|
|
|
|
followers = conn.assigns[:actor].followers
|
|
|
|
data =
|
|
collection_page(conn, followers, page)
|
|
|> Map.put("@context", @context)
|
|
|
|
conn
|
|
|> put_resp_header("content-type", "application/activity+json")
|
|
|> json(data)
|
|
end
|
|
|
|
def followers(conn, _params) do
|
|
%Actor{followers: followers} = conn.assigns[:actor]
|
|
|
|
data = %{
|
|
"@context" => @context,
|
|
"type" => "OrderedCollection",
|
|
"id" => current_url(conn, %{}),
|
|
"totalItems" => length(followers),
|
|
"first" => collection_page(conn, followers, 1)
|
|
}
|
|
|
|
conn
|
|
|> put_resp_header("content-type", "application/activity+json")
|
|
|> json(data)
|
|
end
|
|
|
|
def following(conn, %{"page" => page}) do
|
|
actor = conn.assigns[:actor]
|
|
|
|
following =
|
|
Actor.get_all_following(actor)
|
|
|> Enum.map(fn actor -> actor.ap_id end)
|
|
|
|
data =
|
|
collection_page(conn, following, page)
|
|
|> Map.put("@context", @context)
|
|
|
|
conn
|
|
|> put_resp_header("content-type", "application/activity+json")
|
|
|> json(data)
|
|
end
|
|
|
|
def following(conn, _params) do
|
|
actor = conn.assigns[:actor]
|
|
|
|
following =
|
|
Actor.get_all_following(actor)
|
|
|> Enum.map(fn actor -> actor.ap_id end)
|
|
|
|
data = %{
|
|
"@context" => @context,
|
|
"type" => "OrderedCollection",
|
|
"id" => current_url(conn, %{}),
|
|
"totalItems" => length(following),
|
|
"first" => collection_page(conn, following, 1)
|
|
}
|
|
|
|
conn
|
|
|> put_resp_header("content-type", "application/activity+json")
|
|
|> json(data)
|
|
end
|
|
|
|
defp collection_page(conn, collection, page) do
|
|
chunks = Enum.chunk_every(collection, 20)
|
|
# page is 1 indexed, so subtract 1 to get the current chunk
|
|
current_chunk = Enum.at(chunks, page - 1)
|
|
|
|
data = %{
|
|
"type" => "OrderedCollectionPage",
|
|
"totalItems" => length(collection),
|
|
"partOf" => current_url(conn, %{}),
|
|
"id" => current_url(conn, %{page: page}),
|
|
"orderedItems" => current_chunk || []
|
|
}
|
|
|
|
if page < length(chunks) do
|
|
Map.put(data, "next", current_url(conn, %{page: page + 1}))
|
|
else
|
|
data
|
|
end
|
|
end
|
|
end
|