- 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
- `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
}"
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}")
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)
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)
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)