import { Router } from 'express'; import { db } from '../db.js'; export const statsRouter = Router(); // GET /api/stats/overview // Bundles everything the "Overview" panel needs in one call, since the // frontend renders all three columns (users / activity / general) together. statsRouter.get('/overview', (req, res) => { const currentUsers = db .prepare(` SELECT u.id, u.username, s.started_at FROM sessions s JOIN users u ON u.id = s.user_id WHERE s.ended_at IS NULL ORDER BY s.started_at DESC LIMIT 20 `) .all(); const recentActivity = db .prepare('SELECT id, description, created_at FROM activity_log ORDER BY created_at DESC LIMIT 20') .all(); const statRows = db.prepare('SELECT key, value FROM site_stats').all(); const stats = Object.fromEntries(statRows.map((r) => [r.key, r.value])); const totalUsers = db.prepare('SELECT COUNT(*) AS count FROM users').get().count; const mostRecentUser = db .prepare('SELECT username, id FROM users ORDER BY joined_at DESC LIMIT 1') .get(); res.json({ currentUsers, recentActivity, general: { users: { total: totalUsers, mostRecent: mostRecentUser ?? null }, reports: { named: stats.reports_named ?? '0', associated: stats.reports_associated ?? '0', logged: stats.reports_logged ?? '0', }, build: { pipeline: stats.build_pipeline ?? 'unknown', buildNumber: stats.build_number ?? '0', version: stats.version ?? '0.0.0', }, }, }); }); // GET /api/stats/users (just the current-users list, if you want it standalone) statsRouter.get('/users', (req, res) => { const rows = db .prepare(` SELECT u.id, u.username, s.started_at FROM sessions s JOIN users u ON u.id = s.user_id WHERE s.ended_at IS NULL ORDER BY s.started_at DESC `) .all(); res.json(rows); }); // POST /api/stats/session/start { username } statsRouter.post('/session/start', (req, res) => { const { username } = req.body ?? {}; if (!username) return res.status(400).json({ error: 'username is required' }); let user = db.prepare('SELECT id FROM users WHERE username = ?').get(username); if (!user) { const result = db.prepare('INSERT INTO users (username) VALUES (?)').run(username); user = { id: result.lastInsertRowid }; } db.prepare('UPDATE users SET last_seen_at = strftime(\'%Y-%m-%dT%H:%M:%fZ\', \'now\') WHERE id = ?').run(user.id); const session = db.prepare('INSERT INTO sessions (user_id) VALUES (?)').run(user.id); res.status(201).json({ sessionId: session.lastInsertRowid, userId: user.id }); }); // POST /api/stats/session/end { sessionId } statsRouter.post('/session/end', (req, res) => { const { sessionId } = req.body ?? {}; if (!sessionId) return res.status(400).json({ error: 'sessionId is required' }); const result = db .prepare('UPDATE sessions SET ended_at = strftime(\'%Y-%m-%dT%H:%M:%fZ\', \'now\') WHERE id = ? AND ended_at IS NULL') .run(sessionId); if (result.changes === 0) return res.status(404).json({ error: 'no active session with that id' }); res.status(204).end(); });