import { Router } from 'express'; import { verifyPassword, createSession, destroySession, setSessionCookie, clearSessionCookie, hashPassword, requireAdmin } from '../auth.js'; import { getDb } from '../db/index.js'; export const router = Router(); router.post('/login', (req, res) => { const { username, password } = req.body || {}; if (!username || !password) return res.status(400).json({ error: 'username + password required' }); const user = getDb().prepare('SELECT * FROM users WHERE username = ?').get(username); if (!user || !verifyPassword(password, user.password_hash)) { return res.status(401).json({ error: 'invalid credentials' }); } const { token, expires } = createSession(user.id); setSessionCookie(res, token, expires); res.json({ id: user.id, username: user.username, role: user.role }); }); router.post('/logout', (req, res) => { destroySession(req.session?.token); clearSessionCookie(res); res.json({ ok: true }); }); router.get('/me', (req, res) => { if (!req.user) return res.status(401).json({ error: 'not signed in' }); res.json(req.user); }); // Admin-only user management router.get('/users', requireAdmin, (_req, res) => { const users = getDb().prepare('SELECT id, username, role, created_at FROM users ORDER BY username').all(); res.json(users); }); router.post('/users', requireAdmin, (req, res) => { const { username, password, role = 'user' } = req.body || {}; if (!username || !password) return res.status(400).json({ error: 'username + password required' }); if (!['admin', 'user'].includes(role)) return res.status(400).json({ error: 'bad role' }); try { const info = getDb().prepare('INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)') .run(username, hashPassword(password), role); getDb().prepare('INSERT INTO profiles (user_id, display_name) VALUES (?, ?)') .run(info.lastInsertRowid, username); res.status(201).json({ id: info.lastInsertRowid, username, role }); } catch (err) { if (String(err).includes('UNIQUE')) return res.status(409).json({ error: 'username taken' }); throw err; } }); router.patch('/users/:id', requireAdmin, (req, res) => { const id = Number(req.params.id); const { password, role } = req.body || {}; const db = getDb(); if (password) db.prepare('UPDATE users SET password_hash = ? WHERE id = ?').run(hashPassword(password), id); if (role && ['admin', 'user'].includes(role)) { db.prepare('UPDATE users SET role = ? WHERE id = ?').run(role, id); } res.json({ ok: true }); }); router.delete('/users/:id', requireAdmin, (req, res) => { const id = Number(req.params.id); if (id === req.user.id) return res.status(400).json({ error: 'cannot delete self' }); getDb().prepare('DELETE FROM users WHERE id = ?').run(id); res.json({ ok: true }); });