feat(admin): wire Admin Users management (A9)
User list with create dialog, role toggle, (de)activate, and reset-password; self-lockout guard. Adds getUser/resetPassword endpoints, an isActive field on the User type, and en/ru strings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,11 @@ export const adminApi = api.injectEndpoints({
|
||||
transformResponse: (raw: RawUser[]) => raw.map(toUser),
|
||||
providesTags: ['User'],
|
||||
}),
|
||||
getUser: build.query<User, string>({
|
||||
query: (id) => `/admin/users/${id}`,
|
||||
transformResponse: (raw: RawUser) => toUser(raw),
|
||||
providesTags: (_res, _err, id) => [{ type: 'User', id }],
|
||||
}),
|
||||
createUser: build.mutation<
|
||||
User,
|
||||
{ username: string; password: string; role: 'admin' | 'user' }
|
||||
@@ -39,11 +44,20 @@ export const adminApi = api.injectEndpoints({
|
||||
},
|
||||
}),
|
||||
transformResponse: (raw: RawUser) => toUser(raw),
|
||||
invalidatesTags: ['User'],
|
||||
invalidatesTags: (_res, _err, { id }) => ['User', { type: 'User', id }],
|
||||
}),
|
||||
// Soft delete on the backend: deactivates the account and revokes its
|
||||
// sessions (see admin.py::deactivate_user), so it also refreshes the row.
|
||||
deleteUser: build.mutation<void, string>({
|
||||
query: (id) => ({ url: `/admin/users/${id}`, method: 'DELETE' }),
|
||||
invalidatesTags: ['User'],
|
||||
invalidatesTags: (_res, _err, id) => ['User', { type: 'User', id }],
|
||||
}),
|
||||
resetPassword: build.mutation<void, { id: string; newPassword: string }>({
|
||||
query: ({ id, newPassword }) => ({
|
||||
url: `/admin/users/${id}/reset-password`,
|
||||
method: 'POST',
|
||||
body: { new_password: newPassword },
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
overrideExisting: false,
|
||||
@@ -51,7 +65,9 @@ export const adminApi = api.injectEndpoints({
|
||||
|
||||
export const {
|
||||
useGetUsersQuery,
|
||||
useGetUserQuery,
|
||||
useCreateUserMutation,
|
||||
useUpdateUserMutation,
|
||||
useDeleteUserMutation,
|
||||
useResetPasswordMutation,
|
||||
} = adminApi;
|
||||
|
||||
@@ -128,6 +128,7 @@ export const toUser = (r: RawUser): User => ({
|
||||
username: r.username,
|
||||
// MVP role model: superuser → admin, everyone else → user.
|
||||
role: r.is_superuser ? 'admin' : 'user',
|
||||
isActive: r.is_active,
|
||||
createdAt: r.created_at,
|
||||
});
|
||||
|
||||
|
||||
@@ -181,6 +181,7 @@ export interface User {
|
||||
username: string;
|
||||
email?: string;
|
||||
role: 'admin' | 'user';
|
||||
isActive: boolean;
|
||||
createdAt: string;
|
||||
lastActiveAt?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user