aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md5
-rw-r--r--docs/development/API/admin_api.md13
-rw-r--r--lib/pleroma/user.ex9
-rw-r--r--lib/pleroma/web/activity_pub/mrf/tag_policy.ex11
-rw-r--r--lib/pleroma/web/admin_api/controllers/admin_api_controller.ex28
-rw-r--r--lib/pleroma/web/admin_api/controllers/tag_controller.ex62
-rw-r--r--lib/pleroma/web/router.ex5
-rw-r--r--test/web/admin_api/controllers/tag_controller_test.exs150
8 files changed, 253 insertions, 30 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a1fa22398..301c4f2aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -88,6 +88,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.
</details>
### Fixed
@@ -152,6 +153,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Security
- Fixed the possibility of using file uploads to spoof posts.
+=======
+- Mix tasks for controlling user account confirmation status in bulk (`mix pleroma.user confirm_all` and `mix pleroma.user unconfirm_all`)
+- Mix task for sending confirmation emails to all unconfirmed users (`mix pleroma.email send_confirmation_mails`)
+- Mix task option for force-unfollowing relays
### Changed
diff --git a/docs/development/API/admin_api.md b/docs/development/API/admin_api.md
index 8f855d251..63e287b88 100644
--- a/docs/development/API/admin_api.md
+++ b/docs/development/API/admin_api.md
@@ -119,6 +119,19 @@ The `/api/v1/pleroma/admin/*` path is backwards compatible with `/api/pleroma/ad
}
```
+## `GET /api/v1/pleroma/admin/users/tag`
+
+### List tags
+
+- Params: None
+
+- Response:
+
+``` json
+["verify", "mrf_tag:media-force-nsfw"]
+
+```
+
## `PUT /api/v1/pleroma/admin/users/tag`
### Tag a list of users
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index c1aa0f716..5cbe5bb75 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1259,6 +1259,15 @@ defmodule Pleroma.User do
|> Repo.all()
end
+ @spec list_tags() :: list(String.t())
+ def list_tags do
+ from(
+ u in __MODULE__,
+ select: type(fragment("DISTINCT unnest(?)", u.tags), :string)
+ )
+ |> Repo.all()
+ end
+
def increase_note_count(%User{} = user) do
User
|> where(id: ^user.id)
diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
index 528093ac0..316ea0368 100644
--- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
@@ -21,6 +21,17 @@ 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 get_tags(%User{tags: tags}) when is_list(tags), do: tags
defp get_tags(_), do: []
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..7f06e11ed 100644
--- a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
@@ -35,8 +35,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
when action in [
:get_password_reset,
:force_password_reset,
- :tag_users,
- :untag_users,
:right_add,
:right_add_multiple,
:right_delete,
@@ -138,32 +136,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
end
- def tag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
- with {:ok, _} <- User.tag(nicknames, tags) do
- ModerationLog.insert_log(%{
- actor: admin,
- nicknames: nicknames,
- tags: tags,
- action: "tag"
- })
-
- json_response(conn, :no_content, "")
- end
- end
-
- def untag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
- with {:ok, _} <- User.untag(nicknames, tags) do
- ModerationLog.insert_log(%{
- actor: admin,
- nicknames: nicknames,
- tags: tags,
- action: "untag"
- })
-
- json_response(conn, :no_content, "")
- end
- end
-
def right_add_multiple(%{assigns: %{user: admin}} = conn, %{
"permission_group" => permission_group,
"nicknames" => nicknames
diff --git a/lib/pleroma/web/admin_api/controllers/tag_controller.ex b/lib/pleroma/web/admin_api/controllers/tag_controller.ex
new file mode 100644
index 000000000..9419bf31e
--- /dev/null
+++ b/lib/pleroma/web/admin_api/controllers/tag_controller.ex
@@ -0,0 +1,62 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.TagController do
+ use Pleroma.Web, :controller
+
+ import Pleroma.Web.ControllerHelper, only: [json_response: 3]
+
+ alias Pleroma.ModerationLog
+ alias Pleroma.User
+ alias Pleroma.Web.AdminAPI
+ alias Pleroma.Web.Plugs.OAuthScopesPlug
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["write:accounts"], admin: true} when action in [:tag, :untag]
+ )
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["read:accounts"], admin: true} when action in [:list]
+ )
+
+ action_fallback(AdminAPI.FallbackController)
+
+ def list(%{assigns: %{user: _admin}} = conn, _) do
+ tags =
+ Pleroma.User.list_tags()
+ |> Kernel.++(Pleroma.Web.ActivityPub.MRF.TagPolicy.policy_tags())
+ |> Enum.uniq()
+ |> Enum.sort()
+
+ json(conn, tags)
+ end
+
+ def tag(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
+ with {:ok, _} <- User.tag(nicknames, tags) do
+ ModerationLog.insert_log(%{
+ actor: admin,
+ nicknames: nicknames,
+ tags: tags,
+ action: "tag"
+ })
+
+ json_response(conn, :no_content, "")
+ end
+ end
+
+ def untag(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
+ with {:ok, _} <- User.untag(nicknames, tags) do
+ ModerationLog.insert_log(%{
+ actor: admin,
+ nicknames: nicknames,
+ tags: tags,
+ action: "untag"
+ })
+
+ json_response(conn, :no_content, "")
+ end
+ end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index de0bd27d7..7410b29b6 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -159,8 +159,9 @@ defmodule Pleroma.Web.Router do
pipe_through(:admin_api)
put("/users/disable_mfa", AdminAPIController, :disable_mfa)
- put("/users/tag", AdminAPIController, :tag_users)
- delete("/users/tag", AdminAPIController, :untag_users)
+ get("/users/tag", TagController, :list)
+ put("/users/tag", TagController, :tag)
+ delete("/users/tag", TagController, :untag)
get("/users/:nickname/permission_group", AdminAPIController, :right_get)
get("/users/:nickname/permission_group/:permission_group", AdminAPIController, :right_get)
diff --git a/test/web/admin_api/controllers/tag_controller_test.exs b/test/web/admin_api/controllers/tag_controller_test.exs
new file mode 100644
index 000000000..671bda53a
--- /dev/null
+++ b/test/web/admin_api/controllers/tag_controller_test.exs
@@ -0,0 +1,150 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.TagControllerTest do
+ use Pleroma.Web.ConnCase
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Pleroma.Factory
+
+ alias Pleroma.ModerationLog
+ 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)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+
+ {:ok, %{admin: admin, token: token, conn: conn}}
+ end
+
+ describe "GET /api/pleroma/admin/users/tag" do
+ test "it returns user tags and mrf policy tags", %{conn: conn} do
+ insert(:user, %{tags: ["x"]})
+ insert(:user, %{tags: ["y"]})
+ insert(:user, %{tags: ["unchanged"]})
+
+ response =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> get("/api/pleroma/admin/users/tag")
+ |> json_response(200)
+
+ assert [
+ "mrf_tag:disable-any-subscription",
+ "mrf_tag:disable-remote-subscription",
+ "mrf_tag:force-unlisted",
+ "mrf_tag:media-force-nsfw",
+ "mrf_tag:media-strip",
+ "mrf_tag:sandbox",
+ "unchanged",
+ "x",
+ "y"
+ ] == response
+ end
+ end
+
+ describe "PUT /api/pleroma/admin/users/tag" do
+ setup %{conn: conn} do
+ user1 = insert(:user, %{tags: ["x"]})
+ user2 = insert(:user, %{tags: ["y"]})
+ user3 = insert(:user, %{tags: ["unchanged"]})
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> put(
+ "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
+ "#{user2.nickname}&tags[]=foo&tags[]=bar"
+ )
+
+ %{conn: conn, user1: user1, user2: user2, user3: user3}
+ end
+
+ test "it appends specified tags to users with specified nicknames", %{
+ conn: conn,
+ admin: admin,
+ user1: user1,
+ user2: user2
+ } do
+ assert empty_json_response(conn)
+ assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
+ assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
+
+ log_entry = Repo.one(ModerationLog)
+
+ users =
+ [user1.nickname, user2.nickname]
+ |> Enum.map(&"@#{&1}")
+ |> Enum.join(", ")
+
+ tags = ["foo", "bar"] |> Enum.join(", ")
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} added tags: #{tags} to users: #{users}"
+ end
+
+ test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
+ assert empty_json_response(conn)
+ assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
+ end
+ end
+
+ describe "DELETE /api/pleroma/admin/users/tag" do
+ setup %{conn: conn} do
+ user1 = insert(:user, %{tags: ["x"]})
+ user2 = insert(:user, %{tags: ["y", "z"]})
+ user3 = insert(:user, %{tags: ["unchanged"]})
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> delete(
+ "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
+ "#{user2.nickname}&tags[]=x&tags[]=z"
+ )
+
+ %{conn: conn, user1: user1, user2: user2, user3: user3}
+ end
+
+ test "it removes specified tags from users with specified nicknames", %{
+ conn: conn,
+ admin: admin,
+ user1: user1,
+ user2: user2
+ } do
+ assert empty_json_response(conn)
+ assert User.get_cached_by_id(user1.id).tags == []
+ assert User.get_cached_by_id(user2.id).tags == ["y"]
+
+ log_entry = Repo.one(ModerationLog)
+
+ users =
+ [user1.nickname, user2.nickname]
+ |> Enum.map(&"@#{&1}")
+ |> Enum.join(", ")
+
+ tags = ["x", "z"] |> Enum.join(", ")
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
+ end
+
+ test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
+ assert empty_json_response(conn)
+ assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
+ end
+ end
+end