AdminAPI: suggest a user through the API
authorAlex Gleason <alex@alexgleason.me>
Fri, 26 Nov 2021 21:19:01 +0000 (15:19 -0600)
committerAlex Gleason <alex@alexgleason.me>
Fri, 26 Nov 2021 21:19:01 +0000 (15:19 -0600)
docs/development/API/admin_api.md
lib/pleroma/moderation_log.ex
lib/pleroma/user.ex
lib/pleroma/web/admin_api/controllers/user_controller.ex
lib/pleroma/web/api_spec/operations/admin/user_operation.ex
lib/pleroma/web/router.ex
test/pleroma/user_test.exs
test/pleroma/web/admin_api/controllers/user_controller_test.exs

index 8f855d251a5ac2b9c2cb945c0534b8699d3f4605..79531c45b6e40c252228594be55dd2ffbc36f8b2 100644 (file)
@@ -261,6 +261,46 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
 }
 ```
 
+## `PATCH /api/v1/pleroma/admin/users/suggest`
+
+### Suggest a user
+
+Adds the user(s) to follower recommendations.
+
+- Params:
+  - `nicknames`: nicknames array
+- Response:
+
+```json
+{
+  users: [
+    {
+      // user object
+    }
+  ]
+}
+```
+
+## `PATCH /api/v1/pleroma/admin/users/unsuggest`
+
+### Unsuggest a user
+
+Removes the user(s) from follower recommendations.
+
+- Params:
+  - `nicknames`: nicknames array
+- Response:
+
+```json
+{
+  users: [
+    {
+      // user object
+    }
+  ]
+}
+```
+
 ## `GET /api/v1/pleroma/admin/users/:nickname_or_id`
 
 ### Retrive the details of a user
index 1849cacc8889d7396345f3a7cf290de26c737fc7..ca032657c81092fc4b50726485673ce794b7bf6c 100644 (file)
@@ -338,6 +338,26 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} approved users: #{users_to_nicknames_string(users)}"
   end
 
+  def get_log_entry_message(%ModerationLog{
+        data: %{
+          "actor" => %{"nickname" => actor_nickname},
+          "action" => "add_suggestion",
+          "subject" => users
+        }
+      }) do
+    "@#{actor_nickname} added suggested users: #{users_to_nicknames_string(users)}"
+  end
+
+  def get_log_entry_message(%ModerationLog{
+        data: %{
+          "actor" => %{"nickname" => actor_nickname},
+          "action" => "remove_suggestion",
+          "subject" => users
+        }
+      }) do
+    "@#{actor_nickname} removed suggested users: #{users_to_nicknames_string(users)}"
+  end
+
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
index 6d62e9b4346daf6b441520eb1b03fbf688ca317d..880f027bc103ce34cd8b544572e2e8f896a3decb 100644 (file)
@@ -1678,6 +1678,22 @@ defmodule Pleroma.User do
 
   def confirm(%User{} = user), do: {:ok, user}
 
+  def set_suggestion(users, is_suggested) when is_list(users) do
+    Repo.transaction(fn ->
+      Enum.map(users, fn user ->
+        with {:ok, user} <- set_suggestion(user, is_suggested), do: user
+      end)
+    end)
+  end
+
+  def set_suggestion(%User{is_suggested: is_suggested} = user, is_suggested), do: {:ok, user}
+
+  def set_suggestion(%User{} = user, is_suggested) when is_boolean(is_suggested) do
+    user
+    |> change(is_suggested: is_suggested)
+    |> update_and_set_cache()
+  end
+
   def update_notification_settings(%User{} = user, settings) do
     user
     |> cast(%{notification_settings: settings}, [])
index 637a0e702d37003800144b4767d91de8a7a99d22..50208a8b76a1b4ac634632a29d69f58f0326c80f 100644 (file)
@@ -35,7 +35,9 @@ defmodule Pleroma.Web.AdminAPI.UserController do
            :toggle_activation,
            :activate,
            :deactivate,
-           :approve
+           :approve,
+           :suggest,
+           :unsuggest
          ]
   )
 
@@ -239,6 +241,32 @@ defmodule Pleroma.Web.AdminAPI.UserController do
     render(conn, "index.json", users: updated_users)
   end
 
+  def suggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
+    users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
+    {:ok, updated_users} = User.set_suggestion(users, true)
+
+    ModerationLog.insert_log(%{
+      actor: admin,
+      subject: users,
+      action: "add_suggestion"
+    })
+
+    render(conn, "index.json", users: updated_users)
+  end
+
+  def unsuggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
+    users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
+    {:ok, updated_users} = User.set_suggestion(users, false)
+
+    ModerationLog.insert_log(%{
+      actor: admin,
+      subject: users,
+      action: "remove_suggestion"
+    })
+
+    render(conn, "index.json", users: updated_users)
+  end
+
   def index(conn, params) do
     {page, page_size} = page_params(params)
     filters = maybe_parse_filters(params[:filters])
index c9d0bfd7c1d0f00d6ad42803c093fe7b0f8867a7..57fb1ad65e8c101af4700cfbafd0017a1c6efaab 100644 (file)
@@ -216,7 +216,71 @@ defmodule Pleroma.Web.ApiSpec.Admin.UserOperation do
         request_body(
           "Parameters",
           %Schema{
-            description: "POST body for deleting multiple users",
+            description: "POST body for approving multiple users",
+            type: :object,
+            properties: %{
+              nicknames: %Schema{
+                type: :array,
+                items: %Schema{type: :string}
+              }
+            }
+          }
+        ),
+      responses: %{
+        200 =>
+          Operation.response("Response", "application/json", %Schema{
+            type: :object,
+            properties: %{user: %Schema{type: :array, items: user()}}
+          }),
+        403 => Operation.response("Forbidden", "application/json", ApiError)
+      }
+    }
+  end
+
+  def suggest_operation do
+    %Operation{
+      tags: ["User administration"],
+      summary: "Suggest multiple users",
+      operationId: "AdminAPI.UserController.suggest",
+      security: [%{"oAuth" => ["admin:write:accounts"]}],
+      parameters: admin_api_params(),
+      requestBody:
+        request_body(
+          "Parameters",
+          %Schema{
+            description: "POST body for adding multiple suggested users",
+            type: :object,
+            properties: %{
+              nicknames: %Schema{
+                type: :array,
+                items: %Schema{type: :string}
+              }
+            }
+          }
+        ),
+      responses: %{
+        200 =>
+          Operation.response("Response", "application/json", %Schema{
+            type: :object,
+            properties: %{user: %Schema{type: :array, items: user()}}
+          }),
+        403 => Operation.response("Forbidden", "application/json", ApiError)
+      }
+    }
+  end
+
+  def unsuggest_operation do
+    %Operation{
+      tags: ["User administration"],
+      summary: "Unsuggest multiple users",
+      operationId: "AdminAPI.UserController.unsuggest",
+      security: [%{"oAuth" => ["admin:write:accounts"]}],
+      parameters: admin_api_params(),
+      requestBody:
+        request_body(
+          "Parameters",
+          %Schema{
+            description: "POST body for removing multiple suggested users",
             type: :object,
             properties: %{
               nicknames: %Schema{
index acf9ce6c2149773ef226d066c5db5e43fdbf57ec..1f51bf45633d898a8b9a0fe43b39766f7e462b95 100644 (file)
@@ -194,6 +194,9 @@ defmodule Pleroma.Web.Router do
     patch("/users/deactivate", UserController, :deactivate)
     patch("/users/approve", UserController, :approve)
 
+    patch("/users/suggest", UserController, :suggest)
+    patch("/users/unsuggest", UserController, :unsuggest)
+
     get("/relay", RelayController, :index)
     post("/relay", RelayController, :follow)
     delete("/relay", RelayController, :unfollow)
index 4021a565da63258b6a480ef06cb7119d92f0fea6..c6282db78bd20619c418e7c45072587e718fac4f 100644 (file)
@@ -1720,6 +1720,38 @@ defmodule Pleroma.UserTest do
     assert user.banner == %{}
   end
 
+  describe "set_suggestion" do
+    test "suggests a user" do
+      user = insert(:user, is_suggested: false)
+      refute user.is_suggested
+      {:ok, user} = User.set_suggestion(user, true)
+      assert user.is_suggested
+    end
+
+    test "suggests a list of users" do
+      unsuggested_users = [
+        insert(:user, is_suggested: false),
+        insert(:user, is_suggested: false),
+        insert(:user, is_suggested: false)
+      ]
+
+      {:ok, users} = User.set_suggestion(unsuggested_users, true)
+
+      assert Enum.count(users) == 3
+
+      Enum.each(users, fn user ->
+        assert user.is_suggested
+      end)
+    end
+
+    test "unsuggests a user" do
+      user = insert(:user, is_suggested: true)
+      assert user.is_suggested
+      {:ok, user} = User.set_suggestion(user, false)
+      refute user.is_suggested
+    end
+  end
+
   test "get_public_key_for_ap_id fetches a user that's not in the db" do
     assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
   end
index d9da34f6ed5209d49d4253a0dfa23eecb18043ed..df13f00e6f13adba05fcdb287dac8eb5d192a938 100644 (file)
@@ -873,6 +873,58 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest do
              "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}"
   end
 
+  test "PATCH /api/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do
+    user1 = insert(:user, is_suggested: false)
+    user2 = insert(:user, is_suggested: false)
+
+    _response =
+      conn
+      |> put_req_header("content-type", "application/json")
+      |> patch(
+        "/api/pleroma/admin/users/suggest",
+        %{nicknames: [user1.nickname, user2.nickname]}
+      )
+      |> json_response_and_validate_schema(200)
+
+    [user1, user2] = Repo.reload!([user1, user2])
+
+    assert user1.is_suggested
+    assert user2.is_suggested
+
+    log_entry = Repo.one(ModerationLog)
+
+    assert ModerationLog.get_log_entry_message(log_entry) ==
+             "@#{admin.nickname} added suggested users: @#{user1.nickname}, @#{
+               user2.nickname
+             }"
+  end
+
+  test "PATCH /api/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do
+    user1 = insert(:user, is_suggested: true)
+    user2 = insert(:user, is_suggested: true)
+
+    _response =
+      conn
+      |> put_req_header("content-type", "application/json")
+      |> patch(
+        "/api/pleroma/admin/users/unsuggest",
+        %{nicknames: [user1.nickname, user2.nickname]}
+      )
+      |> json_response_and_validate_schema(200)
+
+    [user1, user2] = Repo.reload!([user1, user2])
+
+    refute user1.is_suggested
+    refute user2.is_suggested
+
+    log_entry = Repo.one(ModerationLog)
+
+    assert ModerationLog.get_log_entry_message(log_entry) ==
+             "@#{admin.nickname} removed suggested users: @#{user1.nickname}, @#{
+               user2.nickname
+             }"
+  end
+
   test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
     user = insert(:user)