Добавлена функция удаления аккаунтов с каскадным удалением из всех записей для дева
This commit is contained in:
Vendored
+49
-33
@@ -518,8 +518,7 @@ export interface paths {
|
||||
get?: never;
|
||||
put?: never;
|
||||
post?: never;
|
||||
/** Delete User */
|
||||
delete: operations["delete_user_api_admin_users__user_id__delete"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
/** Update User */
|
||||
@@ -682,6 +681,23 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/admin/dev/users/{user_id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
post?: never;
|
||||
/** Delete User Hard */
|
||||
delete: operations["delete_user_hard_api_admin_dev_users__user_id__delete"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/health": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2479,37 +2495,6 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
delete_user_api_admin_users__user_id__delete: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
user_id: number;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["OkResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
update_user_api_admin_users__user_id__patch: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2903,6 +2888,37 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
delete_user_hard_api_admin_dev_users__user_id__delete: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
user_id: number;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["OkResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
health_api_health_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { Spinner } from "../../components/Spinner";
|
||||
import { useToast } from "../../context/ToastContext";
|
||||
import { useAdminUpdateUser, useAdminUsers } from "../../hooks/admin";
|
||||
// DEV-ТОЛЬКО: удаление аккаунтов. Импорт используется лишь под import.meta.env.DEV,
|
||||
// поэтому в прод/тест-сборке вырезается тришейкингом (как и dev-вход).
|
||||
import { DevDeleteAccountButton } from "./DevDeleteAccountButton";
|
||||
|
||||
export function AdminAccountsPage() {
|
||||
const { data: users, isLoading } = useAdminUsers();
|
||||
@@ -23,17 +26,22 @@ export function AdminAccountsPage() {
|
||||
</div>
|
||||
</div>
|
||||
{u.role !== "admin" && (
|
||||
<button
|
||||
className="btn small"
|
||||
onClick={async () => {
|
||||
await update
|
||||
.mutateAsync({ userId: u.id, is_active: !u.is_active })
|
||||
.catch(() => {});
|
||||
toast.show("Сохранено");
|
||||
}}
|
||||
>
|
||||
{u.is_active ? "Отключить" : "Включить"}
|
||||
</button>
|
||||
<div className="row">
|
||||
{import.meta.env.DEV && (
|
||||
<DevDeleteAccountButton userId={u.id} nickname={u.nickname} />
|
||||
)}
|
||||
<button
|
||||
className="btn small"
|
||||
onClick={async () => {
|
||||
await update
|
||||
.mutateAsync({ userId: u.id, is_active: !u.is_active })
|
||||
.catch(() => {});
|
||||
toast.show("Сохранено");
|
||||
}}
|
||||
>
|
||||
{u.is_active ? "Отключить" : "Включить"}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { ApiError, api, unwrap } from "../../api/client";
|
||||
import { qk } from "../../api/queryKeys";
|
||||
import { useToast } from "../../context/ToastContext";
|
||||
|
||||
/**
|
||||
* DEV-ТОЛЬКО кнопка жёсткого удаления аккаунта.
|
||||
*
|
||||
* Эндпоинт `DELETE /api/admin/dev/users/{id}` существует только в dev-сборке бэкенда
|
||||
* (backend/app/routers/dev_admin.py, исключён из прод/тест-образа). Этот модуль
|
||||
* рендерится лишь под `import.meta.env.DEV` в AdminAccountsPage, поэтому в прод-сборке
|
||||
* он не используется и вырезается тришейкингом — в прод/тест удаление недоступно.
|
||||
*/
|
||||
export function DevDeleteAccountButton({
|
||||
userId,
|
||||
nickname,
|
||||
}: {
|
||||
userId: number;
|
||||
nickname: string;
|
||||
}) {
|
||||
const qc = useQueryClient();
|
||||
const toast = useToast();
|
||||
const del = useMutation({
|
||||
mutationFn: async () =>
|
||||
unwrap(
|
||||
await api.DELETE("/api/admin/dev/users/{user_id}", {
|
||||
params: { path: { user_id: userId } },
|
||||
}),
|
||||
),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: qk.adminUsers }),
|
||||
});
|
||||
|
||||
return (
|
||||
<button
|
||||
className="btn small"
|
||||
// Яркая (сплошная) красная кнопка. Стиль инлайном, а не классом в общем CSS,
|
||||
// чтобы в прод/тест-стили не попало ничего, связанного с удалением.
|
||||
style={{ background: "var(--danger)", borderColor: "var(--danger)", color: "#fff" }}
|
||||
disabled={del.isPending}
|
||||
onClick={async () => {
|
||||
if (
|
||||
!window.confirm(
|
||||
`Удалить аккаунт «${nickname}»? Партии сохранятся, но игрок будет ` +
|
||||
`вычеркнут из них. Действие необратимо.`,
|
||||
)
|
||||
)
|
||||
return;
|
||||
try {
|
||||
await del.mutateAsync();
|
||||
toast.show("Аккаунт удалён");
|
||||
} catch (e) {
|
||||
toast.show(e instanceof ApiError ? e.message : "Не удалось удалить");
|
||||
}
|
||||
}}
|
||||
>
|
||||
Удалить
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user