diff --git a/CHANGELOG.md b/CHANGELOG.md index 301c4f2aa..8fff5edcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Improved hashtag timeline performance (requires a background migration). +
+ API Changes + - **Breaking** Admin API: methods and routes for users tags. +
+ ### Added - Reports now generate notifications for admins and mods. @@ -88,7 +93,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. -- Add `GET /api/pleroma/admin/users/tag` - returns a list of users tags. +- Admin API: add `GET /api/pleroma/admin/users/tag` - returns a list of users tags. ### Fixed diff --git a/docs/development/API/admin_api.md b/docs/development/API/admin_api.md index 63e287b88..afec1a960 100644 --- a/docs/development/API/admin_api.md +++ b/docs/development/API/admin_api.md @@ -123,30 +123,29 @@ The `/api/v1/pleroma/admin/*` path is backwards compatible with `/api/pleroma/ad ### List tags -- Params: None - -- Response: +* Params: None +* Response: ``` json ["verify", "mrf_tag:media-force-nsfw"] ``` -## `PUT /api/v1/pleroma/admin/users/tag` +## `PATCH /api/v1/pleroma/admin/users/tag` ### Tag a list of users -- Params: - - `nicknames` (array) - - `tags` (array) +* Params: + * `nicknames` (array) + * `tags` (array) ## `DELETE /api/v1/pleroma/admin/users/tag` ### Untag a list of users -- Params: - - `nicknames` (array) - - `tags` (array) +* Params: + * `nicknames` (array) + * `tags` (array) ## `GET /api/v1/pleroma/admin/users/:nickname/permission_group` diff --git a/lib/pleroma/tag.ex b/lib/pleroma/tag.ex index 3b01f1119..dbbb99068 100644 --- a/lib/pleroma/tag.ex +++ b/lib/pleroma/tag.ex @@ -8,7 +8,15 @@ defmodule Pleroma.Tag do import Ecto.Query alias Pleroma.Repo - alias Pleroma.Web.ActivityPub.MRF + + @mrf_tags [ + "mrf_tag:media-force-nsfw", + "mrf_tag:media-strip", + "mrf_tag:force-unlisted", + "mrf_tag:sandbox", + "mrf_tag:disable-remote-subscription", + "mrf_tag:disable-any-subscription" + ] @type t :: %__MODULE__{} @@ -43,11 +51,12 @@ defmodule Pleroma.Tag do def list_tags do from(u in __MODULE__, select: u.name) |> Repo.all() - |> Kernel.++(MRF.TagPolicy.policy_tags()) + |> Kernel.++(@mrf_tags) |> Enum.uniq() |> Enum.sort() end + @spec get_tag_ids([String.t()]) :: [pos_integer()] def get_tag_ids(tag_names) do names = normalize_tags(tag_names) @@ -59,6 +68,7 @@ defmodule Pleroma.Tag do |> Repo.all() end + @spec normalize_tags([String.t()]) :: [String.t()] def normalize_tags(tag_names) do tag_names |> List.wrap() @@ -66,6 +76,8 @@ defmodule Pleroma.Tag do end defp normalize_tag(tag_name) do - String.trim(String.downcase(tag_name)) + tag_name + |> String.downcase() + |> String.trim() end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 690d751fd..0ef5f4661 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2006,6 +2006,7 @@ defmodule Pleroma.User do def parse_bio(_, _), do: "" + @spec tag_names(t()) :: [String.t()] def tag_names(%__MODULE__{} = user) do {:ok, tags} = Repo.get_assoc(user, :tags) Enum.map(tags, & &1.name) @@ -2013,6 +2014,7 @@ defmodule Pleroma.User do def tag_names(_), do: [] + @spec tag([String.t()] | String.t() | t(), [String.t()] | String.t()) :: {:ok, [t()]} | t() def tag(user_identifiers, tags) when is_list(user_identifiers) do Repo.transaction(fn -> for user_identifier <- user_identifiers, do: tag(user_identifier, tags) @@ -2025,9 +2027,10 @@ defmodule Pleroma.User do def tag(%User{} = user, tags) do tag_names = Pleroma.Tag.normalize_tags(tags) Pleroma.Tag.upsert_tags(tag_names) - update_tags(user, tag_names) + update_user_tags(user, tag_names) end + @spec untag([String.t()] | String.t() | t(), [String.t() | String.t()]) :: {:ok, [t()]} | t() def untag(user_identifiers, tags) when is_list(user_identifiers) do Repo.transaction(fn -> for user_identifier <- user_identifiers, do: untag(user_identifier, tags) @@ -2051,7 +2054,7 @@ defmodule Pleroma.User do preload_tags_and_set_cache(user) end - defp update_tags(%User{} = user, new_tags) do + defp update_user_tags(%User{} = user, new_tags) do {:ok, user_id} = FlakeId.Ecto.Type.dump(user.id) tags = diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index e4d174fa9..638bd6469 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -21,17 +21,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do require Pleroma.Constants - def policy_tags do - [ - "mrf_tag:media-force-nsfw", - "mrf_tag:media-strip", - "mrf_tag:force-unlisted", - "mrf_tag:sandbox", - "mrf_tag:disable-remote-subscription", - "mrf_tag:disable-any-subscription" - ] - end - defp process_tag( "mrf_tag:media-force-nsfw", %{ diff --git a/lib/pleroma/web/admin_api/controllers/tag_controller.ex b/lib/pleroma/web/admin_api/controllers/tag_controller.ex index 2cf6ff9bb..7fdee98d6 100644 --- a/lib/pleroma/web/admin_api/controllers/tag_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/tag_controller.ex @@ -15,12 +15,12 @@ defmodule Pleroma.Web.AdminAPI.TagController do plug( OAuthScopesPlug, - %{scopes: ["write:accounts"], admin: true} when action in [:tag, :untag] + %{scopes: ["write:accounts"], admin: true} when action in [:update, :delete] ) plug( OAuthScopesPlug, - %{scopes: ["read:accounts"], admin: true} when action in [:list] + %{scopes: ["read:accounts"], admin: true} when action in [:index] ) plug(ApiSpec.CastAndValidate) @@ -29,13 +29,16 @@ defmodule Pleroma.Web.AdminAPI.TagController do defdelegate open_api_operation(action), to: ApiSpec.Admin.TagOperation - def list(%{assigns: %{user: _admin}} = conn, _) do + def index(%{assigns: %{user: _admin}} = conn, _) do tags = Pleroma.Tag.list_tags() json(conn, tags) end - def tag(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames, tags: tags}} = conn, _) do + def update( + %{assigns: %{user: admin}, body_params: %{nicknames: nicknames, tags: tags}} = conn, + _ + ) do with {:ok, _} <- User.tag(nicknames, tags) do ModerationLog.insert_log(%{ actor: admin, @@ -48,7 +51,7 @@ defmodule Pleroma.Web.AdminAPI.TagController do end end - def untag( + def delete( %{assigns: %{user: admin}, body_params: %{nicknames: nicknames, tags: tags}} = conn, _ ) do diff --git a/lib/pleroma/web/api_spec/operations/admin/tag_operation.ex b/lib/pleroma/web/api_spec/operations/admin/tag_operation.ex index 8bee51fe2..1716e5b7d 100644 --- a/lib/pleroma/web/api_spec/operations/admin/tag_operation.ex +++ b/lib/pleroma/web/api_spec/operations/admin/tag_operation.ex @@ -14,11 +14,11 @@ defmodule Pleroma.Web.ApiSpec.Admin.TagOperation do apply(__MODULE__, operation, []) end - def list_operation do + def index_operation do %Operation{ tags: ["Admin", "Tags"], summary: "List available tags.", - operationId: "AdminAPI.TagController.list", + operationId: "AdminAPI.TagController.index", parameters: admin_api_params(), responses: %{ 200 => @@ -31,11 +31,11 @@ defmodule Pleroma.Web.ApiSpec.Admin.TagOperation do } end - def tag_operation do + def update_operation do %Operation{ tags: ["Admin", "Tags"], summary: "Adds tags to users.", - operationId: "AdminAPI.TagController.tag", + operationId: "AdminAPI.TagController.update", parameters: admin_api_params(), requestBody: request_body( @@ -57,11 +57,11 @@ defmodule Pleroma.Web.ApiSpec.Admin.TagOperation do } end - def untag_operation do + def delete_operation do %Operation{ tags: ["Admin", "Tags"], summary: "Remove tags from users.", - operationId: "AdminAPI.TagController.untag", + operationId: "AdminAPI.TagController.delete", parameters: admin_api_params(), requestBody: request_body( diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 7410b29b6..17d7bee01 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -159,9 +159,10 @@ defmodule Pleroma.Web.Router do pipe_through(:admin_api) put("/users/disable_mfa", AdminAPIController, :disable_mfa) - get("/users/tag", TagController, :list) - put("/users/tag", TagController, :tag) - delete("/users/tag", TagController, :untag) + + get("/users/tags", TagController, :index) + patch("/users/tags", TagController, :update) + delete("/users/tags", TagController, :delete) get("/users/:nickname/permission_group", AdminAPIController, :right_get) get("/users/:nickname/permission_group/:permission_group", AdminAPIController, :right_get) diff --git a/test/pleroma/web/admin_api/controllers/tag_controller_test.exs b/test/pleroma/web/admin_api/controllers/tag_controller_test.exs index 0c4164d27..ab5e7fd54 100644 --- a/test/pleroma/web/admin_api/controllers/tag_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/tag_controller_test.exs @@ -12,12 +12,6 @@ defmodule Pleroma.Web.AdminAPI.TagControllerTest do alias Pleroma.Repo alias Pleroma.User - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - - :ok - end - setup do admin = insert(:user, is_admin: true) token = insert(:oauth_admin_token, user: admin) @@ -30,7 +24,7 @@ defmodule Pleroma.Web.AdminAPI.TagControllerTest do {:ok, %{admin: admin, token: token, conn: conn}} end - describe "GET /api/pleroma/admin/users/tag" do + describe "GET /api/pleroma/admin/users/tags" do test "it returns user tags and mrf policy tags", %{conn: conn} do insert(:tag, name: "x") insert(:tag, name: "y") @@ -39,7 +33,7 @@ defmodule Pleroma.Web.AdminAPI.TagControllerTest do response = conn |> put_req_header("content-type", "application/json") - |> get("/api/pleroma/admin/users/tag") + |> get("/api/pleroma/admin/users/tags") |> json_response_and_validate_schema(200) assert [ @@ -56,7 +50,7 @@ defmodule Pleroma.Web.AdminAPI.TagControllerTest do end end - describe "PUT /api/pleroma/admin/users/tag" do + describe "PUT /api/pleroma/admin/users/tags" do setup %{conn: conn} do user1 = insert(:user, %{tags: [build(:tag, name: "x")]}) user2 = insert(:user, %{tags: [build(:tag, name: "y")]}) @@ -64,7 +58,7 @@ defmodule Pleroma.Web.AdminAPI.TagControllerTest do assert conn |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/users/tag", %{ + |> patch("/api/pleroma/admin/users/tags", %{ nicknames: [user1.nickname, user2.nickname], tags: ["foo", "bar"] }) @@ -102,7 +96,7 @@ defmodule Pleroma.Web.AdminAPI.TagControllerTest do end end - describe "DELETE /api/pleroma/admin/users/tag" do + describe "DELETE /api/pleroma/admin/users/tags" do setup %{conn: conn} do user1 = insert(:user, %{tags: [build(:tag, name: "x")]}) user2 = insert(:user, %{tags: [build(:tag, name: "y"), build(:tag, name: "z")]}) @@ -111,7 +105,7 @@ defmodule Pleroma.Web.AdminAPI.TagControllerTest do assert conn |> put_req_header("content-type", "application/json") |> delete( - "/api/pleroma/admin/users/tag", + "/api/pleroma/admin/users/tags", %{nicknames: [user1.nickname, user2.nickname], tags: ["x", "z"]} ) |> json_response_and_validate_schema(204)