Add themed admin page with user management, audit log, and system info panels; add compliance note delete functionality

This commit is contained in:
root
2026-04-20 21:39:43 +00:00
parent 043c85cc69
commit 0cdaecf890
5 changed files with 1506 additions and 32 deletions

View File

@@ -891,6 +891,68 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) {
}
});
// -----------------------------------------------------------------------
// DELETE /notes/:id
// Delete a note (or all notes in the same group_id) by note ID.
// Only the note author or an Admin can delete.
//
// Params: id — note row ID
// Query: ?group=true — delete all notes sharing the same group_id
// Response: { deleted: number }
// -----------------------------------------------------------------------
router.delete('/notes/:id', requireGroup('Admin', 'Standard_User'), async (req, res) => {
const noteId = parseInt(req.params.id, 10);
if (isNaN(noteId)) return res.status(400).json({ error: 'Invalid note ID' });
const deleteGroup = req.query.group === 'true';
try {
// Fetch the note to verify ownership
const note = await dbGet(db,
`SELECT id, hostname, metric_id, note, group_id, created_by FROM compliance_notes WHERE id = ?`,
[noteId]
);
if (!note) return res.status(404).json({ error: 'Note not found' });
// Only the author or an Admin can delete
const isAuthor = req.user && String(req.user.id) === String(note.created_by);
const isAdminUser = req.user && req.user.group === 'Admin';
if (!isAuthor && !isAdminUser) {
return res.status(403).json({ error: 'You can only delete your own notes' });
}
let deleted = 0;
if (deleteGroup && note.group_id) {
const result = await dbRun(db,
`DELETE FROM compliance_notes WHERE group_id = ?`,
[note.group_id]
);
deleted = result.changes || 0;
} else {
const result = await dbRun(db,
`DELETE FROM compliance_notes WHERE id = ?`,
[noteId]
);
deleted = result.changes || 0;
}
logAudit(db, {
userId: req.user.id,
username: req.user.username,
action: 'compliance_note_delete',
entityType: 'compliance_note',
entityId: String(noteId),
details: JSON.stringify({ hostname: note.hostname, group_id: note.group_id, deleted_count: deleted }),
ipAddress: req.ip,
});
res.json({ deleted });
} catch (err) {
console.error('[Compliance] DELETE /notes error:', err.message);
res.status(500).json({ error: 'Failed to delete note' });
}
});
// -----------------------------------------------------------------------
// GET /trends
// Per-upload active totals + per-team counts for time-series charts.