Create a per-user admin page to inspect users

Add page to allow admins to inspect all of the details stored on the
server of a user account.  For now this is just the UserDetails, but
in the future this is planned to be expanded to also show sessions
and logs.
This commit is contained in:
Hornwitser 2025-09-06 15:16:02 +02:00
parent 52973ffa9a
commit d006be251c
7 changed files with 176 additions and 26 deletions

View file

@ -0,0 +1,34 @@
import { z } from "zod/v4-mini";
import { readUsers } from "~/server/database";
import { serverUserToApiDetails } from "~/server/utils/user";
const integerStringSchema = z.pipe(
z.string().check(z.regex(/^\d+/)),
z.transform(Number)
);
const detailsSchema = z.object({
id: integerStringSchema,
});
export default defineEventHandler(async (event) => {
await requireServerSessionWithAdmin(event);
const users = await readUsers();
const { success, error, data: params } = detailsSchema.safeParse(getRouterParams(event));
if (!success) {
throw createError({
status: 400,
statusText: "Bad Request",
message: z.prettifyError(error),
});
}
const user = users.find(user => user.id === params.id);
if (!user) {
throw createError({
statusCode: 404,
statusMessage: "Not found",
});
}
return serverUserToApiDetails(user);
})

View file

@ -3,7 +3,7 @@
SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { ServerUser } from "~/server/database"
import type { ApiTombstone, ApiUser } from "~/shared/types/api";
import type { ApiTombstone, ApiUser, ApiUserDetails } from "~/shared/types/api";
export function serverUserToApi(user: ServerUser): ApiUser | ApiTombstone {
if (user.deleted) {
@ -20,3 +20,21 @@ export function serverUserToApi(user: ServerUser): ApiUser | ApiTombstone {
name: user.name,
}
}
export function serverUserToApiDetails(user: ServerUser): ApiUserDetails | ApiTombstone {
if (user.deleted) {
return {
id: user.id,
updatedAt: user.updatedAt,
deleted: true,
}
}
return {
id: user.id,
updatedAt: user.updatedAt,
interestedEventIds: user.interestedEventIds,
interestedEventSlotIds: user.interestedEventSlotIds,
timezone: user.timezone,
locale: user.locale,
}
}