Admin API: `PATCH /api/pleroma/admin/users/:nickname/change_password`
authoreugenijm <eugenijm@protonmail.com>
Tue, 28 Jan 2020 06:47:59 +0000 (09:47 +0300)
committereugenijm <eugenijm@protonmail.com>
Mon, 16 Mar 2020 17:32:07 +0000 (20:32 +0300)
CHANGELOG.md
docs/API/admin_api.md
lib/pleroma/moderation_log.ex
lib/pleroma/web/admin_api/admin_api_controller.ex
lib/pleroma/web/router.ex
test/web/admin_api/admin_api_controller_test.exs

index 4168086e269bb4fee745ee0e26c0bc56eb638cba..0f8091c8cb1080b66b6d2a22e8715980a045ce53 100644 (file)
@@ -67,6 +67,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Mastodon API: User timelines will now respect blocks, unless you are getting the user timeline of somebody you blocked (which would be empty otherwise).
 - Mastodon API: Favoriting / Repeating a post multiple times will now return the identical response every time. Before, executing that action twice would return an error ("already favorited") on the second try.
 - Mastodon API: Limit timeline requests to 3 per timeline per 500ms per user/ip by default.
+- Admin API: `PATCH /api/pleroma/admin/users/:nickname/change_password`
 </details>
 
 ### Added
index 47afdfba5a576d6678c677194a6a34b7b268b44d..cb8201f118edd5a3aabc1c5d01c0de041e416656 100644 (file)
@@ -414,6 +414,14 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
   - `nicknames`
 - Response: none (code `204`)
 
+## `PATCH /api/pleroma/admin/users/:nickname/change_password`
+
+### Change the user password
+
+- Params:
+  - `new_password`
+- Response: none (code `200`)
+
 ## `GET /api/pleroma/admin/reports`
 
 ### Get a list of reports
index e32895f70d5d269bcae8f0ed73b8b650fa358651..b5435a5539d0658fe936eeb38e3222b7ea2b8400 100644 (file)
@@ -605,6 +605,17 @@ defmodule Pleroma.ModerationLog do
     }"
   end
 
+  @spec get_log_entry_message(ModerationLog) :: String.t()
+  def get_log_entry_message(%ModerationLog{
+        data: %{
+          "actor" => %{"nickname" => actor_nickname},
+          "action" => "change_password",
+          "subject" => subjects
+        }
+      }) do
+    "@#{actor_nickname} changed password for users: #{users_to_nicknames_string(subjects)}"
+  end
+
   defp nicknames_to_string(nicknames) do
     nicknames
     |> Enum.map(&"@#{&1}")
index 175260bc2bcb8069aaa115722de136c975caef4d..2aa2c6ac2771f298d7642fac2c462b01b6b04486 100644 (file)
@@ -658,6 +658,39 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
     json_response(conn, :no_content, "")
   end
 
+  @doc "Changes password for a given user"
+  def change_password(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname} = params) do
+    with {_, user} <- {:user, User.get_cached_by_nickname(nickname)},
+         {:ok, _user} <-
+           User.reset_password(user, %{
+             password: params["new_password"],
+             password_confirmation: params["new_password"]
+           }) do
+      ModerationLog.insert_log(%{
+        actor: admin,
+        subject: [user],
+        action: "change_password"
+      })
+
+      User.force_password_reset_async(user)
+
+      ModerationLog.insert_log(%{
+        actor: admin,
+        subject: [user],
+        action: "force_password_reset"
+      })
+
+      json(conn, %{status: "success"})
+    else
+      {:error, changeset} ->
+        {_, {error, _}} = Enum.at(changeset.errors, 0)
+        json(conn, %{error: "New password #{error}."})
+
+      _ ->
+        json(conn, %{error: "Unable to change password."})
+    end
+  end
+
   def list_reports(conn, params) do
     {page, page_size} = page_params(params)
 
index e4e3ee704eac2705cfa3d1cdad6baa50455e3e1e..c03ad101e2d4cf7660f59a7add4d639d438c4723 100644 (file)
@@ -173,6 +173,7 @@ defmodule Pleroma.Web.Router do
 
     get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset)
     patch("/users/force_password_reset", AdminAPIController, :force_password_reset)
+    patch("/users/:nickname/change_password", AdminAPIController, :change_password)
 
     get("/users", AdminAPIController, :list_users)
     get("/users/:nickname", AdminAPIController, :user_show)
index e4c152fb71f165a817916b6a69c67c400a0980af..0c1214f054b1dbcd215ff08ea7592d2925e4c2e0 100644 (file)
@@ -3389,6 +3389,32 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
     end
   end
 
+  describe "PATCH /users/:nickname/change_password" do
+    test "changes password", %{conn: conn, admin: admin} do
+      user = insert(:user)
+      assert user.password_reset_pending == false
+
+      conn =
+        patch(conn, "/api/pleroma/admin/users/#{user.nickname}/change_password", %{
+          "new_password" => "password"
+        })
+
+      assert json_response(conn, 200) == %{"status" => "success"}
+
+      ObanHelpers.perform_all()
+
+      assert User.get_by_id(user.id).password_reset_pending == true
+
+      [log_entry1, log_entry2] = ModerationLog |> Repo.all() |> Enum.sort()
+
+      assert ModerationLog.get_log_entry_message(log_entry1) ==
+               "@#{admin.nickname} changed password for users: @#{user.nickname}"
+
+      assert ModerationLog.get_log_entry_message(log_entry2) ==
+               "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
+    end
+  end
+
   describe "PATCH /users/:nickname/force_password_reset" do
     test "sets password_reset_pending to true", %{conn: conn} do
       user = insert(:user)