`GET /admin/api/users` (liste, plus récent d'abord, plafonnée à 200) et `POST /admin/api/users` (création à la main), tous deux derrière `requireAdmin`. La création génère un mot de passe temporaire aléatoire (`randomInt`, charset sans caractères ambigus, comme `generateInviteCode`) renvoyé une seule fois ; le compte démarre sans foyer, comme une inscription self-service. Évènement `admin.user_created` (fire-and-forget) pour distinguer les comptes provisionnés à la main dans le dashboard. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
31 lines
1 KiB
TypeScript
31 lines
1 KiB
TypeScript
import { wrapAsyncHandler } from "@batch-cooking/express-tools";
|
|
import { adminCreateUserSchema } from "@batch-cooking/shared";
|
|
import { Router } from "express";
|
|
import { requireAdmin } from "../../middlewares/require-admin.js";
|
|
import { createUserProfile, listUsers } from "./admin-users.service.js";
|
|
|
|
/**
|
|
* Router mounted at `/admin/api/users` (via `admin.routes.ts`) — every route
|
|
* behind {@link requireAdmin}. Backs the `/admin/utilisateurs` page: a
|
|
* read-only list of end-user accounts and a "create an account by hand"
|
|
* form. The server generates a one-time temporary password on create and
|
|
* returns it in the response (see `admin-users.service.ts`).
|
|
*/
|
|
export const adminUsersRouter = Router();
|
|
|
|
adminUsersRouter.get(
|
|
"/",
|
|
requireAdmin,
|
|
wrapAsyncHandler(async (_req, res) => {
|
|
res.status(200).json(await listUsers());
|
|
}),
|
|
);
|
|
|
|
adminUsersRouter.post(
|
|
"/",
|
|
requireAdmin,
|
|
wrapAsyncHandler(async (req, res) => {
|
|
const input = adminCreateUserSchema.parse(req.body);
|
|
res.status(201).json(await createUserProfile(input));
|
|
}),
|
|
);
|