From 66810cf49b211ceb5d9140ff2926089700a57864 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 18 Feb 2021 18:16:23 +0300 Subject: [PATCH] changes for admin status endpoints - docs fix, that status endpoints accept `page` parameter - added total to /api/pleroma/admin/instances/:instance/statuses - godmode for /api/pleroma/admin/instances/:instance/statuses --- CHANGELOG.md | 2 + docs/development/API/admin_api.md | 30 ++++++++++- .../admin_api/controllers/admin_api_controller.ex | 13 +++-- .../web/admin_api/controllers/status_controller.ex | 20 +++++++- .../api_spec/operations/admin/status_operation.ex | 59 +++++++++++++++++++++- lib/pleroma/web/router.ex | 6 +++ .../controllers/admin_api_controller_test.exs | 20 ++++++++ .../controllers/status_controller_test.exs | 56 ++++++++++++++++++++ 8 files changed, 196 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43927fe6e..79e250df7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: `/api/v1/accounts/:id` & `/api/v1/mutes` endpoints accept `with_relationships` parameter and return filled `pleroma.relationship` field. - Mastodon API: Endpoint to remove a conversation (`DELETE /api/v1/conversations/:id`). - Mastodon API: `expires_in` in the scheduled post `params` field on `/api/v1/statuses` and `/api/v1/scheduled_statuses/:id` endpoints. +- Admin API: Added `GET /api/v2/pleroma/admin/statuses` endpoint, differs from `/api/pleroma/admin/statuses` only in response format. ### Fixed @@ -98,6 +99,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Fixed own_votes being not returned with poll data. - Mastodon API: Fixed creation of scheduled posts with polls. - Mastodon API: Support for expires_in/expires_at in the Filters. + - Admin API: `godmode` parameter in `/api/pleroma/admin/instances/:instance/statuses` endpoint. ## Unreleased (Patch) diff --git a/docs/development/API/admin_api.md b/docs/development/API/admin_api.md index 8f855d251..5efa8281e 100644 --- a/docs/development/API/admin_api.md +++ b/docs/development/API/admin_api.md @@ -278,11 +278,12 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - Params: - `nickname` or `id` - *optional* `page_size`: number of statuses to return (default is `20`) + - *optional* `page`: **integer** page number - *optional* `godmode`: `true`/`false` – allows to see private statuses - *optional* `with_reblogs`: `true`/`false` – allows to see reblogs (default is false) - Response: - On failure: `Not found` - - On success: JSON, where: + - On success: JSON, where: - `total`: total count of the statuses for the user - `activities`: list of the statuses for the user @@ -302,6 +303,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - Params: - `instance`: instance name - *optional* `page_size`: number of statuses to return (default is `20`) + - *optional* `page`: **integer** page number - *optional* `godmode`: `true`/`false` – allows to see private statuses - *optional* `with_reblogs`: `true`/`false` – allows to see reblogs (default is false) - Response: @@ -325,6 +327,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - Params: - *optional* `page_size`: number of statuses to return (default is `20`) + - *optional* `page`: **integer** page number - *optional* `local_only`: excludes remote statuses - *optional* `godmode`: `true`/`false` – allows to see private statuses - *optional* `with_reblogs`: `true`/`false` – allows to see reblogs (default is false) @@ -332,6 +335,31 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - On failure: `Not found` - On success: JSON array of user's latest statuses +## `GET /api/v2/pleroma/admin/statuses` + +### Retrives all latest statuses with total + +- Params: + - *optional* `page_size`: number of statuses to return (default is `20`) + - *optional* `page`: **integer** page number + - *optional* `local_only`: excludes remote statuses + - *optional* `godmode`: `true`/`false` – allows to see private statuses + - *optional* `with_reblogs`: `true`/`false` – allows to see reblogs (default is false) +- Response: + - On failure: `Not found` + - On success: JSON, where: + - `total`: total count of the statuses + - `activities`: list of the statuses + +```json +{ + "total" : 1, + "activities": [ + // activities list + ] +} +``` + ## `GET /api/v1/pleroma/admin/relay` ### List Relays diff --git a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex index 839ac1a8d..1970f96f7 100644 --- a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex @@ -81,16 +81,18 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do action_fallback(AdminAPI.FallbackController) + defp truthy_param?(value), do: value in ["true", true] + def list_instance_statuses(conn, %{"instance" => instance} = params) do - with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true {page, page_size} = page_params(params) result = ActivityPub.fetch_statuses(nil, %{ instance: instance, limit: page_size, + godmode: truthy_param?(params["godmode"]), offset: (page - 1) * page_size, - exclude_reblogs: not with_reblogs, + exclude_reblogs: not truthy_param?(params["with_reblogs"]), total: true }) @@ -100,9 +102,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def list_user_statuses(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname} = params) do - with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true - godmode = params["godmode"] == "true" || params["godmode"] == true - with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do {page, page_size} = page_params(params) @@ -110,8 +109,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do ActivityPub.fetch_user_activities(user, nil, %{ limit: page_size, offset: (page - 1) * page_size, - godmode: godmode, - exclude_reblogs: not with_reblogs, + godmode: truthy_param?(params["godmode"]), + exclude_reblogs: not truthy_param?(params["with_reblogs"]), pagination_type: :offset, total: true }) diff --git a/lib/pleroma/web/admin_api/controllers/status_controller.ex b/lib/pleroma/web/admin_api/controllers/status_controller.ex index 7058def82..4e8dbf77b 100644 --- a/lib/pleroma/web/admin_api/controllers/status_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/status_controller.ex @@ -15,7 +15,11 @@ defmodule Pleroma.Web.AdminAPI.StatusController do require Logger plug(Pleroma.Web.ApiSpec.CastAndValidate) - plug(OAuthScopesPlug, %{scopes: ["admin:read:statuses"]} when action in [:index, :show]) + + plug( + OAuthScopesPlug, + %{scopes: ["admin:read:statuses"]} when action in [:index, :index2, :show] + ) plug( OAuthScopesPlug, @@ -39,6 +43,20 @@ defmodule Pleroma.Web.AdminAPI.StatusController do render(conn, "index.json", activities: activities, as: :activity) end + def index2(%{assigns: %{user: _admin}} = conn, params) do + result = + ActivityPub.fetch_statuses(nil, %{ + godmode: params.godmode, + local_only: params.local_only, + limit: params.page_size, + offset: (params.page - 1) * params.page_size, + exclude_reblogs: not params.with_reblogs, + total: true + }) + + render(conn, "index.json", %{total: result[:total], activities: result[:items], as: :activity}) + end + def show(conn, %{id: id}) do with %Activity{} = activity <- Activity.get_by_id(id) do render(conn, "show.json", %{activity: activity}) diff --git a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex index d25ab5247..3943a5235 100644 --- a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex +++ b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex @@ -22,8 +22,10 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do def index_operation do %Operation{ tags: ["Status administration"], + description: + "Use [/api/v2/pleroma/admin/statuses](#operation/AdminAPI.StatusController.index2) to get response with `total` field.", operationId: "AdminAPI.StatusController.index", - summary: "Get all statuses", + summary: "Get all statuses (without total)", security: [%{"oAuth" => ["admin:read:statuses"]}], parameters: [ Operation.parameter( @@ -68,6 +70,61 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do } end + def index2_operation do + %Operation{ + tags: ["Status administration"], + operationId: "AdminAPI.StatusController.index2", + summary: "Get all statuses", + security: [%{"oAuth" => ["admin:read:statuses"]}], + parameters: [ + Operation.parameter( + :godmode, + :query, + %Schema{type: :boolean, default: false}, + "Allows to see private statuses" + ), + Operation.parameter( + :local_only, + :query, + %Schema{type: :boolean, default: false}, + "Excludes remote statuses" + ), + Operation.parameter( + :with_reblogs, + :query, + %Schema{type: :boolean, default: false}, + "Allows to see reblogs" + ), + Operation.parameter( + :page, + :query, + %Schema{type: :integer, default: 1}, + "Page" + ), + Operation.parameter( + :page_size, + :query, + %Schema{type: :integer, default: 50}, + "Number of statuses to return" + ) + | admin_api_params() + ], + responses: %{ + 200 => + Operation.response("Response", "application/json", %Schema{ + type: :object, + properties: %{ + total: %Schema{type: :integer}, + reports: %Schema{ + type: :array, + items: status() + } + } + }) + } + } + end + def show_operation do %Operation{ tags: ["Status adminitration)"], diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index de24d31f4..0eeb095e1 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -155,6 +155,12 @@ defmodule Pleroma.Web.Router do post("/uploader_callback/:upload_path", UploaderController, :callback) end + scope "/api/v2/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:admin_api) + + get("/statuses", StatusController, :index2) + end + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index 8cd9f939b..5d5e10dd8 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -832,6 +832,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert length(activities) == 3 end + + test "godmode", %{conn: conn} do + user = insert(:user, local: false, ap_id: "https://example.com/users/user") + {:ok, a1} = CommonAPI.post(user, %{status: "public"}) + {:ok, a2} = CommonAPI.post(user, %{status: "private", visibility: "private"}) + + %{"total" => 1, "activities" => activities} = + conn |> get("/api/pleroma/admin/instances/example.com/statuses") |> json_response(200) + + assert Enum.map(activities, & &1["id"]) == [a1.id] + + %{"total" => 2, "activities" => activities} = + conn + |> get("/api/pleroma/admin/instances/example.com/statuses?godmode=true") + |> json_response(200) + + ids = Enum.map(activities, & &1["id"]) + assert a1.id in ids + assert a2.id in ids + end end describe "PATCH /confirm_email" do diff --git a/test/pleroma/web/admin_api/controllers/status_controller_test.exs b/test/pleroma/web/admin_api/controllers/status_controller_test.exs index 3fdf23ba2..a504cde5e 100644 --- a/test/pleroma/web/admin_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/status_controller_test.exs @@ -194,8 +194,64 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest do {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"}) {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"}) + conn = get(conn, "/api/pleroma/admin/statuses?godmode=true") + assert json_response_and_validate_schema(conn, 200) |> length() == 3 end end + + describe "GET /api/v2/pleroma/admin/statuses" do + test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do + blocked = insert(:user) + user = insert(:user) + User.block(admin, blocked) + + {:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"}) + + {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"}) + {:ok, private} = CommonAPI.post(user, %{status: ".", visibility: "private"}) + {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"}) + {:ok, _} = CommonAPI.post(blocked, %{status: ".", visibility: "public"}) + + %{"total" => 3, "activities" => activities} = + conn + |> get("/api/v2/pleroma/admin/statuses") + |> json_response_and_validate_schema(200) + + ids = Enum.map(activities, & &1["id"]) + refute private.id in ids + assert length(activities) == 3 + end + + test "returns only local statuses with local_only on", %{conn: conn} do + user = insert(:user) + remote_user = insert(:user, local: false, nickname: "archaeme@archae.me") + insert(:note_activity, user: user, local: true) + insert(:note_activity, user: remote_user, local: false) + + %{"total" => 1, "activities" => activities} = + conn + |> get("/api/v2/pleroma/admin/statuses?local_only=true") + |> json_response_and_validate_schema(200) + + assert length(activities) == 1 + end + + test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do + user = insert(:user) + + {:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"}) + + {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"}) + {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"}) + + %{"total" => 3, "activities" => activities} = + conn + |> get("/api/v2/pleroma/admin/statuses?godmode=true") + |> json_response_and_validate_schema(200) + + assert length(activities) == 3 + end + end end