Skip to content

Commit

Permalink
paginate follow requests (#460)
Browse files Browse the repository at this point in the history
matches https://docs.joinmastodon.org/methods/follow_requests/#get mostly

Co-authored-by: FloatingGhost <[email protected]>
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/460
Signed-off-by: marcin mikołajczak <[email protected]>
  • Loading branch information
FloatingGhost authored and mkljczk committed Aug 29, 2024
1 parent 23b2e04 commit 6e440d6
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 10 deletions.
9 changes: 4 additions & 5 deletions lib/pleroma/following_relationship.ex
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,13 @@ defmodule Pleroma.FollowingRelationship do
|> Repo.aggregate(:count, :id)
end

def get_follow_requests(%User{id: id}) do
def get_follow_requests_query(%User{id: id}) do
__MODULE__
|> join(:inner, [r], f in assoc(r, :follower))
|> join(:inner, [r], f in assoc(r, :follower), as: :follower)
|> where([r], r.state == ^:follow_pending)
|> where([r], r.following_id == ^id)
|> where([r, f], f.is_active == true)
|> select([r, f], f)
|> Repo.all()
|> where([r, follower: f], f.is_active == true)
|> select([r, follower: f], f)
end

def following?(%User{id: follower_id}, %User{id: followed_id}) do
Expand Down
8 changes: 7 additions & 1 deletion lib/pleroma/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,13 @@ defmodule Pleroma.User do
defdelegate following(user), to: FollowingRelationship
defdelegate following?(follower, followed), to: FollowingRelationship
defdelegate following_ap_ids(user), to: FollowingRelationship
defdelegate get_follow_requests(user), to: FollowingRelationship
defdelegate get_follow_requests_query(user), to: FollowingRelationship

def get_follow_requests(user) do
get_follow_requests_query(user)
|> Repo.all()
end

defdelegate search(query, opts \\ []), to: User.Search

@doc """
Expand Down
19 changes: 19 additions & 0 deletions lib/pleroma/web/api_spec/operations/follow_request_operation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ defmodule Pleroma.Web.ApiSpec.FollowRequestOperation do
summary: "Retrieve follow requests",
security: [%{"oAuth" => ["read:follows", "follow"]}],
operationId: "FollowRequestController.index",
parameters: pagination_params(),
responses: %{
200 =>
Operation.response("Array of Account", "application/json", %Schema{
Expand Down Expand Up @@ -62,4 +63,22 @@ defmodule Pleroma.Web.ApiSpec.FollowRequestOperation do
required: true
)
end

defp pagination_params do
[
Operation.parameter(:max_id, :query, :string, "Return items older than this ID"),
Operation.parameter(
:since_id,
:query,
:string,
"Return the oldest items newer than this ID"
),
Operation.parameter(
:limit,
:query,
%Schema{type: :integer, default: 20},
"Maximum number of items to return. Will be ignored if it's more than 40"
)
]
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
defmodule Pleroma.Web.MastodonAPI.FollowRequestController do
use Pleroma.Web, :controller

import Pleroma.Web.ControllerHelper,
only: [add_link_headers: 2]

alias Pleroma.User
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Plugs.OAuthScopesPlug
alias Pleroma.Pagination

plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(:assign_follower when action != :index)
Expand All @@ -24,10 +28,15 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.FollowRequestOperation

@doc "GET /api/v1/follow_requests"
def index(%{assigns: %{user: followed}} = conn, _params) do
follow_requests = User.get_follow_requests(followed)
def index(%{assigns: %{user: followed}} = conn, params) do
follow_requests =
followed
|> User.get_follow_requests_query()
|> Pagination.fetch_paginated(params, :keyset, :follower)

render(conn, "index.json", for: followed, users: follow_requests, as: :user)
conn
|> add_link_headers(follow_requests)
|> render("index.json", for: followed, users: follow_requests, as: :user)
end

@doc "POST /api/v1/follow_requests/:id/authorize"
Expand Down
3 changes: 2 additions & 1 deletion lib/pleroma/web/mastodon_api/views/account_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
%User{id: user_id}
) do
count =
User.get_follow_requests(user)
user
|> User.get_follow_requests()
|> length()

data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidationTest do

describe "blocks" do
setup do
clear_config([:activitypub, :outgoing_blocks], true)
user = insert(:user, local: false)
blocked = insert(:user)

Expand Down
1 change: 1 addition & 0 deletions test/pleroma/web/common_api_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ defmodule Pleroma.Web.CommonAPITest do

test "it blocks and federates", %{blocker: blocker, blocked: blocked} do
clear_config([:instance, :federating], true)
clear_config([:activitypub, :outgoing_blocks], true)

with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do

import Pleroma.Factory

defp extract_next_link_header(header) do
[_, next_link] = Regex.run(~r{<(?<next_link>.*)>; rel="next"}, header)
next_link
end

describe "locked accounts" do
setup do
user = insert(:user, is_locked: true)
Expand All @@ -31,6 +36,23 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
assert to_string(other_user.id) == relationship["id"]
end

test "/api/v1/follow_requests paginates", %{user: user, conn: conn} do
for _ <- 1..21 do
other_user = insert(:user)
{:ok, _, _, _activity} = CommonAPI.follow(other_user, user)
{:ok, _, _} = User.follow(other_user, user, :follow_pending)
end

conn = get(conn, "/api/v1/follow_requests")
assert length(json_response_and_validate_schema(conn, 200)) == 20
assert [link_header] = get_resp_header(conn, "link")
assert link_header =~ "rel=\"next\""
next_link = extract_next_link_header(link_header)
assert next_link =~ "/api/v1/follow_requests"
conn = get(conn, next_link)
assert length(json_response_and_validate_schema(conn, 200)) == 1
end

test "/api/v1/follow_requests/:id/authorize works", %{user: user, conn: conn} do
other_user = insert(:user)

Expand Down

0 comments on commit 6e440d6

Please sign in to comment.