Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 1x 1x 1x 1x 4x 3x 3x 3x 3x 1x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x 2x 2x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 18x 1x 2x 1x 1x 1x 1x 1x 1x | /**
* Admin alert routes — list, create, acknowledge, resolve alerts and manage config.
*
* GET /admin/alerts → List alerts with filters (admin only)
* POST /admin/alerts → Create a new alert (admin only)
* GET /admin/alerts/:alertId → Get single alert (admin only)
* PATCH /admin/alerts/:alertId → Update alert status (admin only)
* GET /admin/alert-config → Get alert thresholds (admin only)
* PATCH /admin/alert-config → Update alert thresholds (admin only)
*/
const router = require('express').Router();
const { db } = require('../utils/firebase');
const { requireAdmin } = require('../middleware/auth');
const { DEFAULT_ALERT_CONFIG } = require('../utils/alertManager');
const { generateId } = require('../utils/helpers');
const log = require('../utils/log');
const DEFAULT_LIMIT = 50;
const MAX_LIMIT = 200;
// GET /admin/alerts — List alerts with optional filters
router.get('/admin/alerts', async (req, res) => {
if (requireAdmin(req, res)) return;
try {
const { type, severity, status } = req.query;
let limit = Number.parseInt(req.query.limit, 10) || DEFAULT_LIMIT;
Iif (limit < 1) limit = DEFAULT_LIMIT;
Iif (limit > MAX_LIMIT) limit = MAX_LIMIT;
let query = db.collection('alerts').orderBy('createdAt', 'desc');
Iif (type) query = query.where('type', '==', type);
Iif (severity) query = query.where('severity', '==', severity);
Iif (status) query = query.where('status', '==', status);
query = query.limit(limit);
const snapshot = await query.get();
const alerts = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
res.json({ alerts });
} catch (err) {
log.error('admin-alerts', 'Error listing alerts', { error: err.message });
res.status(500).json({ error: 'Internal server error' });
}
});
// POST /admin/alerts — Create a new alert
router.post('/admin/alerts', async (req, res) => {
if (requireAdmin(req, res)) return;
try {
const { type, severity, message, status } = req.body;
if (!type || !message) {
return res.status(400).json({ error: 'type and message are required' });
}
const alertId = `alert_${generateId()}`;
const alertData = {
id: alertId,
type: type || 'error_rate',
severity: severity || 'medium',
message,
status: status || 'new',
createdAt: Date.now(),
};
await db.collection('alerts').doc(alertId).set(alertData);
res.json({ id: alertId, alertId, ...alertData });
} catch (err) {
log.error('admin-alerts', 'Error creating alert', { error: err.message });
res.status(500).json({ error: 'Internal server error' });
}
});
// GET /admin/alerts/:alertId — Get single alert
router.get('/admin/alerts/:alertId', async (req, res) => {
if (requireAdmin(req, res)) return;
try {
const { alertId } = req.params;
const snap = await db.collection('alerts').doc(alertId).get();
if (!snap.exists) {
return res.status(404).json({ error: 'Alert not found' });
}
res.json({ id: snap.id, ...snap.data() });
} catch (err) {
log.error('admin-alerts', 'Error getting alert', {
alertId: req.params.alertId,
error: err.message,
});
res.status(500).json({ error: 'Internal server error' });
}
});
// PATCH /admin/alerts/:alertId — Update alert status
router.patch('/admin/alerts/:alertId', async (req, res) => {
if (requireAdmin(req, res)) return;
try {
const { alertId } = req.params;
const { status } = req.body;
if (!status || !['acknowledged', 'resolved'].includes(status)) {
return res
.status(400)
.json({ error: 'Invalid status. Must be "acknowledged" or "resolved".' });
}
const ref = db.collection('alerts').doc(alertId);
const snap = await ref.get();
Iif (!snap.exists) {
return res.status(404).json({ error: 'Alert not found' });
}
const update = { status };
const adminId = req.auth.uniqueId || req.auth.uid;
if (status === 'acknowledged') {
update.acknowledgedBy = adminId;
} else Eif (status === 'resolved') {
update.resolvedBy = adminId;
update.resolvedAt = new Date().toISOString();
}
await ref.update(update);
res.json({ success: true, alertId, ...update });
} catch (err) {
log.error('admin-alerts', 'Error updating alert', {
alertId: req.params.alertId,
error: err.message,
});
res.status(500).json({ error: 'Internal server error' });
}
});
// GET /admin/alert-config — Get alert thresholds
router.get('/admin/alert-config', async (req, res) => {
Iif (requireAdmin(req, res)) return;
try {
const snap = await db.collection('alertConfig').doc('settings').get();
const config = snap.exists
? { ...DEFAULT_ALERT_CONFIG, ...snap.data() }
: { ...DEFAULT_ALERT_CONFIG };
res.json({ config });
} catch (err) {
log.error('admin-alerts', 'Error getting alert config', { error: err.message });
res.status(500).json({ error: 'Internal server error' });
}
});
// PATCH /admin/alert-config — Update alert thresholds
router.patch('/admin/alert-config', async (req, res) => {
Iif (requireAdmin(req, res)) return;
try {
const allowedKeys = Object.keys(DEFAULT_ALERT_CONFIG);
const update = {};
for (const key of allowedKeys) {
if (req.body[key] !== undefined) {
update[key] = req.body[key];
}
}
if (Object.keys(update).length === 0) {
return res.status(400).json({ error: 'No valid fields to update' });
}
await db.collection('alertConfig').doc('settings').set(update, { merge: true });
// Return merged config
const snap = await db.collection('alertConfig').doc('settings').get();
const config = { ...DEFAULT_ALERT_CONFIG, ...snap.data() };
res.json({ success: true, config });
} catch (err) {
log.error('admin-alerts', 'Error updating alert config', { error: err.message });
res.status(500).json({ error: 'Internal server error' });
}
});
module.exports = router;
|