AdminAPI: Confirm user account, resend confirmation email

This commit is contained in:
Maxim Filippov 2019-11-19 20:14:02 +09:00
parent 09b4f7269e
commit 46eb160135
8 changed files with 153 additions and 8 deletions

View File

@ -67,6 +67,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API: Add the `recipients` parameter to `GET /api/v1/conversations`
- Configuration: `feed` option for user atom feed.
- Pleroma API: Add Emoji reactions
- Admin API: `PATCH /api/pleroma/users/confirm_email` to confirm email for multiple users, `PATCH /api/pleroma/users/resend_confirmation_email` to resend confirmation email for multiple users
</details>
### Fixed

View File

@ -878,3 +878,19 @@ Compile time settings (need instance reboot):
- Authentication: required
- Params: None
- Response: JSON, "ok" and 200 status
## `PATCH /api/pleroma/admin/users/confirm_email`
### Confirm users' emails
- Params:
- `nicknames`
- Response: Array of user nicknames
## `PATCH /api/pleroma/admin/users/resend_confirmation_email`
### Resend confirmation email
- Params:
- `nicknames`
- Response: Array of user nicknames

View File

@ -624,7 +624,31 @@ def get_log_entry_message(%ModerationLog{
"subject" => subjects
}
}) do
"@#{actor_nickname} force password reset for users: #{users_to_nicknames_string(subjects)}"
"@#{actor_nickname} forced password reset for users: #{users_to_nicknames_string(subjects)}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "confirm_email",
"subject" => subjects
}
}) do
"@#{actor_nickname} confirmed email for users: #{users_to_nicknames_string(subjects)}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "resend_confirmation_email",
"subject" => subjects
}
}) do
"@#{actor_nickname} re-sent confirmation email for users: #{
users_to_nicknames_string(subjects)
}"
end
defp nicknames_to_string(nicknames) do

View File

@ -489,6 +489,10 @@ def try_send_confirmation_email(%User{} = user) do
end
end
def try_send_confirmation_email(users) do
Enum.map(users, &try_send_confirmation_email/1)
end
def needs_update?(%User{local: true}), do: false
def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true
@ -1572,6 +1576,11 @@ def toggle_confirmation(%User{} = user) do
|> update_and_set_cache()
end
@spec toggle_confirmation([User.t()]) :: [{:ok, User.t()} | {:error, Changeset.t()}]
def toggle_confirmation(users) do
Enum.map(users, &toggle_confirmation/1)
end
def get_mascot(%{mascot: %{} = mascot}) when not is_nil(mascot) do
mascot
end

View File

@ -335,7 +335,7 @@ def list_users(conn, params) do
}
with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
{:ok, users, count} <- filter_relay_user(users, count),
{:ok, users, count} <- filter_service_users(users, count),
do:
conn
|> json(
@ -347,15 +347,16 @@ def list_users(conn, params) do
)
end
defp filter_relay_user(users, count) do
filtered_users = Enum.reject(users, &relay_user?/1)
count = if Enum.any?(users, &relay_user?/1), do: length(filtered_users), else: count
defp filter_service_users(users, count) do
filtered_users = Enum.reject(users, &service_user?/1)
count = if Enum.any?(users, &service_user?/1), do: length(filtered_users), else: count
{:ok, filtered_users, count}
end
defp relay_user?(user) do
user.ap_id == Relay.relay_ap_id()
defp service_user?(user) do
String.match?(user.ap_id, ~r/.*\/relay$/) or
String.match?(user.ap_id, ~r/.*\/internal\/fetch$/)
end
@filters ~w(local external active deactivated is_admin is_moderator)
@ -799,6 +800,34 @@ def reload_emoji(conn, _params) do
conn |> json("ok")
end
def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
User.toggle_confirmation(users)
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "confirm_email"
})
conn |> json("")
end
def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
User.try_send_confirmation_email(users)
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "resend_confirmation_email"
})
conn |> json("")
end
def errors(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)

View File

@ -36,7 +36,8 @@ def render("show.json", %{user: user}) do
"deactivated" => user.deactivated,
"local" => user.local,
"roles" => User.roles(user),
"tags" => user.tags || []
"tags" => user.tags || [],
"confirmation_pending" => user.confirmation_pending
}
end

View File

@ -177,6 +177,9 @@ defmodule Pleroma.Web.Router do
get("/users/:nickname", AdminAPIController, :user_show)
get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses)
patch("/users/confirm_email", AdminAPIController, :confirm_email)
patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email)
get("/reports", AdminAPIController, :list_reports)
get("/grouped_reports", AdminAPIController, :list_grouped_reports)
get("/reports/:id", AdminAPIController, :report_show)

View File

@ -2839,6 +2839,68 @@ test "DELETE /relay", %{admin: admin} do
"@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
end
end
describe "PATCH /confirm_email" do
setup %{conn: conn} do
admin = insert(:user, is_admin: true)
%{conn: assign(conn, :user, admin), admin: admin}
end
test "it confirms emails of two users", %{admin: admin} do
[first_user, second_user] = insert_pair(:user, confirmation_pending: true)
assert first_user.confirmation_pending == true
assert second_user.confirmation_pending == true
build_conn()
|> assign(:user, admin)
|> patch("/api/pleroma/admin/users/confirm_email", %{
nicknames: [
first_user.nickname,
second_user.nickname
]
})
assert first_user.confirmation_pending == true
assert second_user.confirmation_pending == true
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
second_user.nickname
}"
end
end
describe "PATCH /resend_confirmation_email" do
setup %{conn: conn} do
admin = insert(:user, is_admin: true)
%{conn: assign(conn, :user, admin), admin: admin}
end
test "it resend emails for two users", %{admin: admin} do
[first_user, second_user] = insert_pair(:user, confirmation_pending: true)
build_conn()
|> assign(:user, admin)
|> patch("/api/pleroma/admin/users/resend_confirmation_email", %{
nicknames: [
first_user.nickname,
second_user.nickname
]
})
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
second_user.nickname
}"
end
end
end
# Needed for testing