commit: 367d5c65f6b5ad34833ff82104b69ac0dd1186d1
parent 0476cf42838dc84af568c89a550be2d8fb3e30f4
Author: nicole mikołajczyk <me@mkljczk.pl>
Date: Fri, 28 Nov 2025 16:36:40 +0100
Merge branch 'outgoing_follow_requests' into 'develop'
Add /api/v1/pleroma/outgoing_follow_requests
See merge request pleroma/pleroma!4310
Diffstat:
7 files changed, 99 insertions(+), 0 deletions(-)
diff --git a/changelog.d/outgoing-follow-requests.add b/changelog.d/outgoing-follow-requests.add
@@ -0,0 +1 @@
+Add /api/v1/pleroma/outgoing_follow_requests
diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex
@@ -157,6 +157,16 @@ defmodule Pleroma.FollowingRelationship do
|> Repo.all()
end
+ def get_outgoing_follow_requests(%User{id: id}) do
+ __MODULE__
+ |> join(:inner, [r], f in assoc(r, :following))
+ |> where([r], r.state == ^:follow_pending)
+ |> where([r], r.follower_id == ^id)
+ |> where([r, f], f.is_active == true)
+ |> select([r, f], f)
+ |> Repo.all()
+ end
+
def following?(%User{id: follower_id}, %User{id: followed_id}) do
__MODULE__
|> where(follower_id: ^follower_id, following_id: ^followed_id, state: ^:follow_accept)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
@@ -288,6 +288,7 @@ defmodule Pleroma.User do
defdelegate following?(follower, followed), to: FollowingRelationship
defdelegate following_ap_ids(user), to: FollowingRelationship
defdelegate get_follow_requests(user), to: FollowingRelationship
+ defdelegate get_outgoing_follow_requests(user), to: FollowingRelationship
defdelegate search(query, opts \\ []), to: User.Search
@doc """
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_follow_request_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_follow_request_operation.ex
@@ -0,0 +1,31 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaFollowRequestOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.Account
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def outgoing_operation do
+ %Operation{
+ tags: ["Follow requests"],
+ summary: "Retrieve outgoing follow requests",
+ security: [%{"oAuth" => ["read:follows", "follow"]}],
+ operationId: "PleromaFollowRequestController.outgoing",
+ responses: %{
+ 200 =>
+ Operation.response("Array of Account", "application/json", %Schema{
+ type: :array,
+ items: Account,
+ example: [Account.schema().example]
+ })
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/pleroma_api/controllers/follow_request_controller.ex b/lib/pleroma/web/pleroma_api/controllers/follow_request_controller.ex
@@ -0,0 +1,27 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.FollowRequestController do
+ use Pleroma.Web, :controller
+
+ alias Pleroma.User
+ alias Pleroma.Web.Plugs.OAuthScopesPlug
+
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
+
+ action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
+
+ plug(OAuthScopesPlug, %{scopes: ["follow", "read:follows"]})
+
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaFollowRequestOperation
+
+ @doc "GET /api/v1/pleroma/outgoing_follow_requests"
+ def outgoing(%{assigns: %{user: follower}} = conn, _params) do
+ follow_requests = User.get_outgoing_follow_requests(follower)
+
+ conn
+ |> put_view(Pleroma.Web.MastodonAPI.FollowRequestView)
+ |> render("index.json", for: follower, users: follow_requests, as: :user)
+ end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
@@ -603,6 +603,8 @@ defmodule Pleroma.Web.Router do
post("/bookmark_folders", BookmarkFolderController, :create)
patch("/bookmark_folders/:id", BookmarkFolderController, :update)
delete("/bookmark_folders/:id", BookmarkFolderController, :delete)
+
+ get("/outgoing_follow_requests", FollowRequestController, :outgoing)
end
scope [] do
diff --git a/test/pleroma/web/pleroma_api/controllers/follow_request_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/follow_request_controller_test.exs
@@ -0,0 +1,27 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.FollowRequestControllerTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ alias Pleroma.Web.CommonAPI
+
+ import Pleroma.Factory
+
+ test "/api/v1/pleroma/outgoing_follow_requests works" do
+ %{conn: conn, user: user} = oauth_access(["read:follows"])
+
+ other_user1 = insert(:user)
+ other_user2 = insert(:user, is_locked: true)
+ _other_user3 = insert(:user)
+
+ {:ok, _, _, _} = CommonAPI.follow(other_user1, user)
+ {:ok, _, _, _} = CommonAPI.follow(other_user2, user)
+
+ conn = get(conn, "/api/v1/pleroma/outgoing_follow_requests")
+
+ assert [relationship] = json_response_and_validate_schema(conn, 200)
+ assert to_string(other_user2.id) == relationship["id"]
+ end
+end