import { Router } from 'express'; import { countAdmins, createLocalUser, getUser, listUsers, updateUser, type UserRole } from '../db/users'; import { revokeUserSessions } from '../db/sessions'; import { hashPassword, validatePassword } from '../lib/passwords'; const router=Router(); const role=(value:unknown):value is UserRole=>value==='admin'||value==='user'; const profileInvalid=(displayName:unknown,email:unknown)=>typeof displayName==='string'&&displayName.length>160||typeof email==='string'&&(email.length>254||!!email&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)); router.get('/',(_req,res)=>res.json(listUsers())); router.post('/',async(req,res)=>{const {username,password}=req.body??{};const nextRole=role(req.body?.role)?req.body.role:'user';if(typeof username!=='string'||!username.trim()){res.status(400).json({code:'USERNAME_REQUIRED',error:'Username is required.'});return;}if(typeof password!=='string'||validatePassword(password)){res.status(400).json({code:'PASSWORD_INVALID',error:typeof password==='string'?validatePassword(password):'Password is required.'});return;}if(profileInvalid(req.body?.displayName,req.body?.email)){res.status(400).json({code:'PROFILE_INVALID',error:'Display name or contact email is invalid.'});return;}try{res.status(201).json(createLocalUser(username,await hashPassword(password),nextRole,{displayName:typeof req.body?.displayName==='string'?req.body.displayName:'',email:typeof req.body?.email==='string'?req.body.email:''}));}catch(error){res.status(409).json({code:'USER_CREATE_FAILED',error:error instanceof Error&&error.message.includes('UNIQUE')?'Username already exists.':'User could not be created.'});}}); router.put('/:id',(req,res)=>{const existing=getUser(req.params.id);if(!existing){res.status(404).json({code:'USER_NOT_FOUND',error:'User not found.'});return;}if(profileInvalid(req.body?.displayName,req.body?.email)){res.status(400).json({code:'PROFILE_INVALID',error:'Display name or contact email is invalid.'});return;}const nextRole=role(req.body?.role)?req.body.role:undefined;const enabled=typeof req.body?.enabled==='boolean'?req.body.enabled:undefined;if(existing.role==='admin'&&existing.enabled&&(nextRole==='user'||enabled===false)&&countAdmins()<=1){res.status(409).json({code:'LAST_ADMIN_REQUIRED',error:'At least one enabled administrator is required.'});return;}const changed=updateUser(existing.id,{role:nextRole,enabled,displayName:typeof req.body?.displayName==='string'?req.body.displayName:undefined,email:typeof req.body?.email==='string'?req.body.email:undefined});if(nextRole||enabled===false)revokeUserSessions(existing.id);res.json(changed);}); router.post('/:id/reset-password',async(req,res)=>{const password=req.body?.password;if(typeof password!=='string'||validatePassword(password)){res.status(400).json({code:'PASSWORD_INVALID',error:typeof password==='string'?validatePassword(password):'Password is required.'});return;}if(!getUser(req.params.id)){res.status(404).json({code:'USER_NOT_FOUND',error:'User not found.'});return;}const changed=updateUser(req.params.id,{passwordHash:await hashPassword(password)});revokeUserSessions(req.params.id);res.json(changed);}); router.post('/:id/revoke-sessions',(req,res)=>{if(!getUser(req.params.id)){res.status(404).json({code:'USER_NOT_FOUND',error:'User not found.'});return;}revokeUserSessions(req.params.id);res.status(204).send();}); export default router;