logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://anongit.hacktivis.me/git/pleroma.git/
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:

Achangelog.d/outgoing-follow-requests.add1+
Mlib/pleroma/following_relationship.ex10++++++++++
Mlib/pleroma/user.ex1+
Alib/pleroma/web/api_spec/operations/pleroma_follow_request_operation.ex31+++++++++++++++++++++++++++++++
Alib/pleroma/web/pleroma_api/controllers/follow_request_controller.ex27+++++++++++++++++++++++++++
Mlib/pleroma/web/router.ex2++
Atest/pleroma/web/pleroma_api/controllers/follow_request_controller_test.exs27+++++++++++++++++++++++++++
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