'use strict'; const express = require('express'); const { db } = require('../db'); const { log } = require('../lib/audit'); const { toDisplayDateTime } = require('../lib/dates'); const { requireAuth, requireAdmin } = require('../middleware/auth'); const { sendMail, adminEmails } = require('../lib/mailer'); const router = express.Router(); router.use(requireAuth, requireAdmin); function query({ q, action, page, from, to }) { const where = []; const params = []; if (q) { where.push('(actor LIKE ? OR detail LIKE ?)'); params.push(`%${q}%`, `%${q}%`); } if (action) { where.push('action = ?'); params.push(action); } if (page) { where.push('page = ?'); params.push(page); } if (from) { where.push('ts >= ?'); params.push(from); } if (to) { where.push('ts <= ?'); params.push(to); } const sql = 'SELECT id, ts, actor, action, page, detail, ip FROM logs' + (where.length ? ' WHERE ' + where.join(' AND ') : '') + ' ORDER BY ts DESC, id DESC'; return db.prepare(sql).all(...params); } router.get('/', (req, res) => { const rows = query(req.query); const actions = db.prepare('SELECT DISTINCT action FROM logs ORDER BY action').all().map((r) => r.action); const pages = db.prepare('SELECT DISTINCT page FROM logs WHERE page IS NOT NULL ORDER BY page').all().map((r) => r.page); res.json({ logs: rows.slice(0, 1000), total: rows.length, actions, pages }); }); function toCSV(rows) { const head = ['id', 'timestamp', 'actor', 'action', 'page', 'detail', 'ip']; const esc = (v) => `"${String(v == null ? '' : v).replace(/"/g, '""')}"`; const lines = [head.join(',')]; for (const r of rows) { lines.push([r.id, toDisplayDateTime(r.ts), r.actor, r.action, r.page, r.detail, r.ip].map(esc).join(',')); } return lines.join('\r\n'); } router.get('/export', (req, res) => { const rows = query(req.query); const csv = toCSV(rows); log(req, 'LOGS_EXPORT', 'Logs', `Exported ${rows.length} log rows as CSV`); res.setHeader('Content-Type', 'text/csv; charset=utf-8'); res.setHeader('Content-Disposition', `attachment; filename="datahub-logs-${Date.now()}.csv"`); res.send(csv); }); router.post('/email', async (req, res) => { const rows = query(req.body || {}); const csv = toCSV(rows); const to = (req.body && req.body.to) || adminEmails().join(','); if (!to) return res.status(400).json({ error: 'No recipient. Add an admin email or provide "to".' }); const html = `
${rows.length} log entries are attached as CSV.
` + `© 2026 Martinhal IT - Joao Vaz - Version 1.5 Patch 0.2
`; try { const r = await sendMail({ to, subject: `ISDSS audit logs (${rows.length} entries)`, html, context: 'Audit log export', actor: req.session.user.username, attachments: [{ filename: `datahub-logs-${Date.now()}.csv`, content: csv }], }); log(req, 'LOGS_EMAIL', 'Logs', `Emailed ${rows.length} log rows to ${to} ${r.delivered ? '(delivered)' : '(queued, no SMTP)'}`); res.json({ ok: true, delivered: r.delivered, count: rows.length }); } catch (e) { log(req, 'MAIL_ERROR', 'Logs', `Log email failed: ${e.message}`); res.status(500).json({ error: e.message }); } }); module.exports = router;