Make account moderation submission atomic

This commit is contained in:
SimpleTest 2026-08-03 14:13:40 +03:00
parent 4c52c8bf3d
commit d3dc882549
3 changed files with 54 additions and 58 deletions

View File

@ -32,10 +32,6 @@ defmodule WhoNeedHelpWeb.AdminUserLive do
) )
end end
def handle_event("validate-moderation", %{"moderation" => params}, socket) do
{:noreply, assign(socket, :moderation_form, to_form(params, as: :moderation))}
end
def handle_event("set-staff-roles", %{"staff" => params}, socket) do def handle_event("set-staff-roles", %{"staff" => params}, socket) do
roles = params |> Map.get("roles", []) |> List.wrap() |> Enum.reject(&(&1 == "")) roles = params |> Map.get("roles", []) |> List.wrap() |> Enum.reject(&(&1 == ""))
@ -181,7 +177,6 @@ defmodule WhoNeedHelpWeb.AdminUserLive do
:if={can_moderate?(@current_scope.user, @user)} :if={can_moderate?(@current_scope.user, @user)}
for={@moderation_form} for={@moderation_form}
id={"moderate-user-#{@user.id}"} id={"moderate-user-#{@user.id}"}
phx-change="validate-moderation"
phx-submit="moderate-user" phx-submit="moderate-user"
class="mt-4 space-y-4" class="mt-4 space-y-4"
> >

View File

@ -205,8 +205,8 @@ msgstr ""
msgid "Action center" msgid "Action center"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:113 #: lib/who_need_help_web/live/admin_user_live.ex:109
#: lib/who_need_help_web/live/admin_user_live.ex:193 #: lib/who_need_help_web/live/admin_user_live.ex:188
#: lib/who_need_help_web/live/admin_users_live.ex:125 #: lib/who_need_help_web/live/admin_users_live.ex:125
#: lib/who_need_help_web/live/admin_users_live.ex:185 #: lib/who_need_help_web/live/admin_users_live.ex:185
#: lib/who_need_help_web/live/notification_live.ex:521 #: lib/who_need_help_web/live/notification_live.ex:521
@ -264,7 +264,7 @@ msgid "Add unverified link"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_dashboard_live.ex:135 #: lib/who_need_help_web/live/admin_dashboard_live.ex:135
#: lib/who_need_help_web/live/admin_user_live.ex:102 #: lib/who_need_help_web/live/admin_user_live.ex:98
#: lib/who_need_help_web/live/admin_users_live.ex:123 #: lib/who_need_help_web/live/admin_users_live.ex:123
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Administrator" msgid "Administrator"
@ -891,7 +891,7 @@ msgstr ""
msgid "Interface language" msgid "Interface language"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:201 #: lib/who_need_help_web/live/admin_user_live.ex:196
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Internal note" msgid "Internal note"
msgstr "" msgstr ""
@ -1060,7 +1060,7 @@ msgid "Moderation"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_dashboard_live.ex:132 #: lib/who_need_help_web/live/admin_dashboard_live.ex:132
#: lib/who_need_help_web/live/admin_user_live.ex:99 #: lib/who_need_help_web/live/admin_user_live.ex:95
#: lib/who_need_help_web/live/admin_users_live.ex:120 #: lib/who_need_help_web/live/admin_users_live.ex:120
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Moderator" msgid "Moderator"
@ -1549,8 +1549,8 @@ msgstr ""
msgid "Resolved" msgid "Resolved"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:114 #: lib/who_need_help_web/live/admin_user_live.ex:110
#: lib/who_need_help_web/live/admin_user_live.ex:194 #: lib/who_need_help_web/live/admin_user_live.ex:189
#: lib/who_need_help_web/live/admin_users_live.ex:126 #: lib/who_need_help_web/live/admin_users_live.ex:126
#: lib/who_need_help_web/live/admin_users_live.ex:186 #: lib/who_need_help_web/live/admin_users_live.ex:186
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -1759,7 +1759,7 @@ msgstr ""
msgid "Starts" msgid "Starts"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:191 #: lib/who_need_help_web/live/admin_user_live.ex:186
#: lib/who_need_help_web/live/admin_users_live.ex:236 #: lib/who_need_help_web/live/admin_users_live.ex:236
#: lib/who_need_help_web/live/moderation_live.ex:632 #: lib/who_need_help_web/live/moderation_live.ex:632
#: lib/who_need_help_web/live/moderation_live.ex:812 #: lib/who_need_help_web/live/moderation_live.ex:812
@ -1792,8 +1792,8 @@ msgstr ""
msgid "Submit review" msgid "Submit review"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:115 #: lib/who_need_help_web/live/admin_user_live.ex:111
#: lib/who_need_help_web/live/admin_user_live.ex:195 #: lib/who_need_help_web/live/admin_user_live.ex:190
#: lib/who_need_help_web/live/admin_users_live.ex:127 #: lib/who_need_help_web/live/admin_users_live.ex:127
#: lib/who_need_help_web/live/admin_users_live.ex:187 #: lib/who_need_help_web/live/admin_users_live.ex:187
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -2795,7 +2795,7 @@ msgstr ""
#: lib/who_need_help_web/controllers/support_html.ex:6 #: lib/who_need_help_web/controllers/support_html.ex:6
#: lib/who_need_help_web/controllers/support_html/new.html.heex:32 #: lib/who_need_help_web/controllers/support_html/new.html.heex:32
#: lib/who_need_help_web/live/admin_user_live.ex:174 #: lib/who_need_help_web/live/admin_user_live.ex:170
#: lib/who_need_help_web/live/support_operation_live.ex:140 #: lib/who_need_help_web/live/support_operation_live.ex:140
#: lib/who_need_help_web/live/support_operations_live.ex:244 #: lib/who_need_help_web/live/support_operations_live.ex:244
#: lib/who_need_help_web/live/support_operations_live.ex:395 #: lib/who_need_help_web/live/support_operations_live.ex:395
@ -3232,7 +3232,7 @@ msgstr ""
#: lib/who_need_help_web/components/admin_components.ex:166 #: lib/who_need_help_web/components/admin_components.ex:166
#: lib/who_need_help_web/components/layouts.ex:197 #: lib/who_need_help_web/components/layouts.ex:197
#: lib/who_need_help_web/live/admin_dashboard_live.ex:131 #: lib/who_need_help_web/live/admin_dashboard_live.ex:131
#: lib/who_need_help_web/live/admin_user_live.ex:98 #: lib/who_need_help_web/live/admin_user_live.ex:94
#: lib/who_need_help_web/live/admin_users_live.ex:119 #: lib/who_need_help_web/live/admin_users_live.ex:119
#: lib/who_need_help_web/live/support_operations_live.ex:340 #: lib/who_need_help_web/live/support_operations_live.ex:340
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -5447,7 +5447,7 @@ msgstr ""
msgid "Safety guidance for voluntary help, medicine pickup, roadside requests, location sharing, and in-person activities." msgid "Safety guidance for voluntary help, medicine pickup, roadside requests, location sharing, and in-person activities."
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:205 #: lib/who_need_help_web/live/admin_user_live.ex:200
#: lib/who_need_help_web/live/support_operation_live.ex:335 #: lib/who_need_help_web/live/support_operation_live.ex:335
#: lib/who_need_help_web/live/support_operation_live.ex:438 #: lib/who_need_help_web/live/support_operation_live.ex:438
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -6777,7 +6777,7 @@ msgstr[1] ""
msgid "A single starting point for users, support, safety, legal work, analytics, roles, and audited staff actions." msgid "A single starting point for users, support, safety, legal work, analytics, roles, and audited staff actions."
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:222 #: lib/who_need_help_web/live/admin_user_live.ex:217
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "A staff member may hold several fixed roles." msgid "A staff member may hold several fixed roles."
msgstr "" msgstr ""
@ -6828,7 +6828,7 @@ msgstr ""
msgid "All metrics" msgid "All metrics"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:111 #: lib/who_need_help_web/live/admin_user_live.ex:107
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "All permissions, staff roles, and audit log" msgid "All permissions, staff roles, and audit log"
msgstr "" msgstr ""
@ -6839,7 +6839,7 @@ msgid "An account may hold several roles. Permissions are the union of those rol
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_dashboard_live.ex:134 #: lib/who_need_help_web/live/admin_dashboard_live.ex:134
#: lib/who_need_help_web/live/admin_user_live.ex:101 #: lib/who_need_help_web/live/admin_user_live.ex:97
#: lib/who_need_help_web/live/admin_users_live.ex:122 #: lib/who_need_help_web/live/admin_users_live.ex:122
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Analyst" msgid "Analyst"
@ -6948,7 +6948,7 @@ msgstr ""
msgid "Back to queue" msgid "Back to queue"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:140 #: lib/who_need_help_web/live/admin_user_live.ex:136
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Back to users" msgid "Back to users"
msgstr "" msgstr ""
@ -6958,7 +6958,7 @@ msgstr ""
msgid "Chat message" msgid "Chat message"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:95 #: lib/who_need_help_web/live/admin_user_live.ex:91
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Check the status and internal note." msgid "Check the status and internal note."
msgstr "" msgstr ""
@ -6973,7 +6973,7 @@ msgstr ""
msgid "Content locations" msgid "Content locations"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:109 #: lib/who_need_help_web/live/admin_user_live.ex:105
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Content-removal and legal notice queue" msgid "Content-removal and legal notice queue"
msgstr "" msgstr ""
@ -7055,7 +7055,7 @@ msgid "Joined %{date}"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_dashboard_live.ex:133 #: lib/who_need_help_web/live/admin_dashboard_live.ex:133
#: lib/who_need_help_web/live/admin_user_live.ex:100 #: lib/who_need_help_web/live/admin_user_live.ex:96
#: lib/who_need_help_web/live/admin_users_live.ex:121 #: lib/who_need_help_web/live/admin_users_live.ex:121
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Legal" msgid "Legal"
@ -7099,7 +7099,7 @@ msgid "Manage %{name}"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:20 #: lib/who_need_help_web/live/admin_user_live.ex:20
#: lib/who_need_help_web/live/admin_user_live.ex:135 #: lib/who_need_help_web/live/admin_user_live.ex:131
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Manage user" msgid "Manage user"
msgstr "" msgstr ""
@ -7179,7 +7179,7 @@ msgstr ""
msgid "Notice" msgid "Notice"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:93 #: lib/who_need_help_web/live/admin_user_live.ex:89
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "One or more staff roles are invalid." msgid "One or more staff roles are invalid."
msgstr "" msgstr ""
@ -7189,7 +7189,7 @@ msgstr ""
msgid "One row per date, metric, and non-identifying dimension." msgid "One row per date, metric, and non-identifying dimension."
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:267 #: lib/who_need_help_web/live/admin_user_live.ex:262
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Only administrators can change staff roles." msgid "Only administrators can change staff roles."
msgstr "" msgstr ""
@ -7245,7 +7245,7 @@ msgstr ""
msgid "Previous" msgid "Previous"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:110 #: lib/who_need_help_web/live/admin_user_live.ex:106
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Privacy-preserving aggregate product analytics" msgid "Privacy-preserving aggregate product analytics"
msgstr "" msgstr ""
@ -7320,14 +7320,14 @@ msgstr ""
msgid "Registrations" msgid "Registrations"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:159 #: lib/who_need_help_web/live/admin_user_live.ex:155
#: lib/who_need_help_web/live/admin_users_live.ex:263 #: lib/who_need_help_web/live/admin_users_live.ex:263
#: lib/who_need_help_web/live/admin_users_live.ex:304 #: lib/who_need_help_web/live/admin_users_live.ex:304
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Regular user" msgid "Regular user"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:107 #: lib/who_need_help_web/live/admin_user_live.ex:103
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Reports, safety signals, user restrictions, and categories" msgid "Reports, safety signals, user restrictions, and categories"
msgstr "" msgstr ""
@ -7347,7 +7347,7 @@ msgstr ""
msgid "Requests created" msgid "Requests created"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:176 #: lib/who_need_help_web/live/admin_user_live.ex:172
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Restrict or suspend access and record an internal reason." msgid "Restrict or suspend access and record an internal reason."
msgstr "" msgstr ""
@ -7357,7 +7357,7 @@ msgstr ""
msgid "Restricted workspace" msgid "Restricted workspace"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:136 #: lib/who_need_help_web/live/admin_user_live.ex:132
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Review account access and staff permissions for one user." msgid "Review account access and staff permissions for one user."
msgstr "" msgstr ""
@ -7415,7 +7415,7 @@ msgstr ""
msgid "SUBMISSION SAVED" msgid "SUBMISSION SAVED"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:206 #: lib/who_need_help_web/live/admin_user_live.ex:201
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Save account status" msgid "Save account status"
msgstr "" msgstr ""
@ -7472,13 +7472,13 @@ msgstr ""
msgid "Staff role" msgid "Staff role"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:220 #: lib/who_need_help_web/live/admin_user_live.ex:215
#: lib/who_need_help_web/live/admin_user_live.ex:234 #: lib/who_need_help_web/live/admin_user_live.ex:229
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Staff roles" msgid "Staff roles"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:45 #: lib/who_need_help_web/live/admin_user_live.ex:41
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Staff roles updated." msgid "Staff roles updated."
msgstr "" msgstr ""
@ -7513,7 +7513,7 @@ msgstr ""
msgid "Support and legal operations" msgid "Support and legal operations"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:104 #: lib/who_need_help_web/live/admin_user_live.ex:100
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Support conversations and verified support cases" msgid "Support conversations and verified support cases"
msgstr "" msgstr ""
@ -7543,19 +7543,19 @@ msgstr ""
msgid "Technical signal metadata" msgid "Technical signal metadata"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:96 #: lib/who_need_help_web/live/admin_user_live.ex:92
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "The account could not be updated." msgid "The account could not be updated."
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:91 #: lib/who_need_help_web/live/admin_user_live.ex:87
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "The last active administrator cannot lose administrator access or be restricted." msgid "The last active administrator cannot lose administrator access or be restricted."
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:14 #: lib/who_need_help_web/live/admin_user_live.ex:14
#: lib/who_need_help_web/live/admin_user_live.ex:57 #: lib/who_need_help_web/live/admin_user_live.ex:53
#: lib/who_need_help_web/live/admin_user_live.ex:94 #: lib/who_need_help_web/live/admin_user_live.ex:90
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "The selected account is no longer available." msgid "The selected account is no longer available."
msgstr "" msgstr ""
@ -7610,13 +7610,13 @@ msgstr ""
msgid "Unknown staff member" msgid "Unknown staff member"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:148 #: lib/who_need_help_web/live/admin_user_live.ex:144
#: lib/who_need_help_web/live/admin_users_live.ex:129 #: lib/who_need_help_web/live/admin_users_live.ex:129
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Unnamed user" msgid "Unnamed user"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:259 #: lib/who_need_help_web/live/admin_user_live.ex:254
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Update staff roles" msgid "Update staff roles"
msgstr "" msgstr ""
@ -7626,7 +7626,7 @@ msgstr ""
msgid "Update status, assignment, and optionally reply." msgid "Update status, assignment, and optionally reply."
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:257 #: lib/who_need_help_web/live/admin_user_live.ex:252
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Updating…" msgid "Updating…"
msgstr "" msgstr ""
@ -7688,12 +7688,12 @@ msgstr ""
msgid "Write the decision, next step, or information you need…" msgid "Write the decision, next step, or information you need…"
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:214 #: lib/who_need_help_web/live/admin_user_live.ex:209
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You can view this account but cannot change its access." msgid "You can view this account but cannot change its access."
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:87 #: lib/who_need_help_web/live/admin_user_live.ex:83
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You cannot restrict or suspend your own account." msgid "You cannot restrict or suspend your own account."
msgstr "" msgstr ""
@ -7709,7 +7709,7 @@ msgstr ""
msgid "You do not have permission for this action." msgid "You do not have permission for this action."
msgstr "" msgstr ""
#: lib/who_need_help_web/live/admin_user_live.ex:82 #: lib/who_need_help_web/live/admin_user_live.ex:78
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You do not have permission for this action. Role changes also require a recent sign-in." msgid "You do not have permission for this action. Role changes also require a recent sign-in."
msgstr "" msgstr ""

View File

@ -64,27 +64,26 @@ defmodule WhoNeedHelpWeb.AdminLiveTest do
{:ok, user_view, html} = live(conn, ~p"/admin/users/#{target.id}") {:ok, user_view, html} = live(conn, ~p"/admin/users/#{target.id}")
assert html =~ "Account under review" assert html =~ "Account under review"
assert has_element?(user_view, "#staff-roles-#{target.id}") assert has_element?(user_view, "#staff-roles-#{target.id}")
refute has_element?(user_view, "#moderate-user-#{target.id}[phx-change]")
user_view user_view
|> form("#moderate-user-#{target.id}", %{ |> form("#moderate-user-#{target.id}", %{
"moderation" => %{ "moderation" => %{
"moderation_status" => "restricted", "moderation_status" => "restricted",
"moderation_note" => "Unsaved review note" "moderation_note" => "Confirmed restricted account"
} }
}) })
|> render_change() |> render_submit()
restricted = Repo.reload!(target)
assert restricted.moderation_status == :restricted
assert restricted.moderation_note == "Confirmed restricted account"
assert has_element?( assert has_element?(
user_view, user_view,
"#moderate-user-#{target.id} option[value='restricted'][selected]" "#moderate-user-#{target.id} option[value='restricted'][selected]"
) )
assert has_element?(
user_view,
"#moderate-user-#{target.id} textarea",
"Unsaved review note"
)
user_view user_view
|> form("#staff-roles-#{target.id}", %{ |> form("#staff-roles-#{target.id}", %{
"staff" => %{"roles" => ["support", "moderator"]} "staff" => %{"roles" => ["support", "moderator"]}
@ -106,17 +105,19 @@ defmodule WhoNeedHelpWeb.AdminLiveTest do
assert Repo.reload!(target).moderation_status == :suspended assert Repo.reload!(target).moderation_status == :suspended
assert Repo.exists?( assert Repo.exists?(
from event in AuditEvent, from(event in AuditEvent,
where: where:
event.actor_id == ^admin.id and event.target_id == ^target.id and event.actor_id == ^admin.id and event.target_id == ^target.id and
event.action == "user.staff_roles_changed" event.action == "user.staff_roles_changed"
)
) )
assert Repo.exists?( assert Repo.exists?(
from event in AuditEvent, from(event in AuditEvent,
where: where:
event.actor_id == ^admin.id and event.target_id == ^target.id and event.actor_id == ^admin.id and event.target_id == ^target.id and
event.action == "user.moderated" event.action == "user.moderated"
)
) )
{:ok, _audit_view, audit_html} = live(conn, ~p"/admin/audit") {:ok, _audit_view, audit_html} = live(conn, ~p"/admin/audit")