Browse Source

Add AP followers endpoint

master
Shadowfacts 2 years ago
parent
commit
7c03d2627f
Signed by: shadowfacts GPG Key ID: 94A5AB95422746E5
4 changed files with 75 additions and 9 deletions
  1. +2
    -2
      lib/clacks/actor.ex
  2. +70
    -6
      lib/clacks_web/controllers/actor_controller.ex
  3. +1
    -1
      lib/clacks_web/controllers/web_finger_controller.ex
  4. +2
    -0
      lib/clacks_web/router.ex

+ 2
- 2
lib/clacks/actor.ex View File

@ -27,8 +27,8 @@ defmodule Clacks.Actor do
|> validate_required([:ap_id, :nickname, :local, :data])
end
@spec get_by_nickanme(nickname :: String.t()) :: t() | nil
def get_by_nickanme(nickname) do
@spec get_by_nickname(nickname :: String.t()) :: t() | nil
def get_by_nickname(nickname) do
Repo.one(from a in __MODULE__, where: a.nickname == ^nickname)
end


+ 70
- 6
lib/clacks_web/controllers/actor_controller.ex View File

@ -1,10 +1,28 @@
defmodule ClacksWeb.ActorController do
use ClacksWeb, :controller
alias Clacks.{Repo, Actor}
alias Clacks.Actor
import Ecto.Query
def get(conn, %{"nickname" => nickname}) do
case Actor.get_by_nickanme(nickname) do
@context "https://www.w3.org/ns/activitystreams"
plug :get_actor
defp get_actor(%Plug.Conn{path_params: %{"nickname" => nickname}} = conn, _opts) do
case Actor.get_by_nickname(nickname) do
nil ->
conn
|> put_status(404)
|> halt()
actor ->
assign(conn, :actor, actor)
end
end
defp get_actor(conn, _opts), do: conn
def get(conn, _params) do
case conn.assigns[:actor] do
%Actor{local: true, data: data} ->
conn
|> put_resp_header("content-type", "application/activity+json")
@ -13,10 +31,56 @@ defmodule ClacksWeb.ActorController do
%Actor{local: false, ap_id: ap_id} ->
conn
|> redirect(external: ap_id)
end
end
_ ->
conn
|> put_status(404)
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
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

+ 1
- 1
lib/clacks_web/controllers/web_finger_controller.ex View File

@ -6,7 +6,7 @@ defmodule ClacksWeb.WebFingerController do
def get(conn, %{"resource" => resource}) do
with [_, nickname] <- Regex.run(@acct_regex, resource),
%Actor{local: true} = actor <- Actor.get_by_nickanme(nickname) do
%Actor{local: true} = actor <- Actor.get_by_nickname(nickname) do
url = Application.get_env(:clacks, ClacksWeb.Endpoint)[:url]
host = url[:host]
port = url[:port]


+ 2
- 0
lib/clacks_web/router.ex View File

@ -21,7 +21,9 @@ defmodule ClacksWeb.Router do
pipe_through :activitypub
get "/objects/:id", ObjectsController, :get
get "/users/:nickname", ActorController, :get
get "/users/:nickname/followers", ActorController, :followers
post "/inbox", InboxController, :shared
post "/users/:nickname/inbox", InboxController, :user_specific


Loading…
Cancel
Save