paginate follow requests (#460)
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending
matches https://docs.joinmastodon.org/methods/follow_requests/#get mostly Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk> Reviewed-on: #460
This commit is contained in:
parent
56c37dc6b3
commit
aeb68a0ad1
9 changed files with 69 additions and 10 deletions
|
@ -37,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- Simplified HTTP signature processing
|
||||
- Rich media will now hard-exit after 5 seconds, to prevent timeline hangs
|
||||
- HTTP Content Security Policy is now far more strict to prevent any potential XSS/CSS leakages
|
||||
- Follow requests are now paginated, matches mastodon API spec, so use the Link header to paginate.
|
||||
|
||||
### Fixed
|
||||
- /api/v1/accounts/lookup will now respect restrict\_unauthenticated
|
||||
|
|
|
@ -155,14 +155,13 @@ def following_count(%User{} = user) 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
|
||||
|
|
|
@ -273,7 +273,13 @@ def cached_muted_users_ap_ids(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 """
|
||||
|
|
|
@ -19,6 +19,7 @@ def index_operation 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{
|
||||
|
@ -62,4 +63,22 @@ defp id_param 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
|
||||
|
|
|
@ -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)
|
||||
plug(:assign_follower when action != :index)
|
||||
|
@ -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"
|
||||
|
|
|
@ -334,7 +334,8 @@ defp maybe_put_follow_requests_count(
|
|||
%User{id: user_id}
|
||||
) do
|
||||
count =
|
||||
User.get_follow_requests(user)
|
||||
user
|
||||
|> User.get_follow_requests()
|
||||
|> length()
|
||||
|
||||
data
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ test "it posts a poll" 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
|
||||
|
|
|
@ -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)
|
||||
|
@ -31,6 +36,23 @@ test "/api/v1/follow_requests works", %{user: user, conn: conn} 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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue