From 4dd660301815af4f58ba8e586c2579fa8be28d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Gierwia=C5=82o?= Date: Tue, 2 Dec 2025 20:09:49 +0100 Subject: [PATCH] feat(activity-log): add admin API endpoints (Phase 4) Added 3 admin-only endpoints for activity log management: 1. GET /api/admin/activity-logs - Query logs with comprehensive filtering - Supports: date range, action, category, username, userId, success - Pagination with limit/offset - Logs ADMIN_VIEW_LOGS action - Returns: logs array, total count, pagination info 2. GET /api/admin/activity-logs/actions - Get list of unique action types - Returns: action names and categories - Useful for filter dropdowns in UI 3. GET /api/admin/activity-logs/stats - Dashboard statistics - Returns: total logs, unique users, failed actions, success rate, logs by category, recent activity (24h) All endpoints protected with authenticate + requireAdmin middleware. --- backend/src/routes/admin.js | 97 ++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/backend/src/routes/admin.js b/backend/src/routes/admin.js index 3de8d2a..acfd7c2 100644 --- a/backend/src/routes/admin.js +++ b/backend/src/routes/admin.js @@ -4,7 +4,7 @@ const { authenticate } = require('../middleware/auth'); const { requireAdmin } = require('../middleware/admin'); const matchingService = require('../services/matching'); const { SUGGESTION_STATUS } = require('../constants'); -const { ACTIONS, log: activityLog } = require('../services/activityLog'); +const { ACTIONS, log: activityLog, queryLogs, getActionTypes, getStats } = require('../services/activityLog'); const { getClientIP } = require('../utils/request'); const router = express.Router(); @@ -237,3 +237,98 @@ router.get('/events/:slug/matching-runs/:runId/suggestions', authenticate, requi next(error); } }); + +// ================================================================== +// ACTIVITY LOGS ENDPOINTS +// ================================================================== + +// GET /api/admin/activity-logs - Query activity logs with filters +router.get('/activity-logs', authenticate, requireAdmin, async (req, res, next) => { + try { + const { + startDate, + endDate, + action, + category, + username, + userId, + success, + limit = 100, + offset = 0, + } = req.query; + + // Parse query parameters + const filters = { + startDate: startDate ? new Date(startDate) : null, + endDate: endDate ? new Date(endDate) : null, + action: action || null, + category: category || null, + username: username || null, + userId: userId ? parseInt(userId) : null, + success: success !== undefined ? success === 'true' : null, + limit: parseInt(limit), + offset: parseInt(offset), + }; + + // Query logs + const result = await queryLogs(filters); + + // Log admin viewing activity logs + activityLog({ + userId: req.user.id, + username: req.user.username, + ipAddress: getClientIP(req), + action: ACTIONS.ADMIN_VIEW_LOGS, + method: req.method, + path: req.path, + metadata: { + filters: { + startDate, + endDate, + action, + category, + username, + userId, + success, + }, + resultCount: result.logs.length, + }, + }); + + res.json({ + success: true, + data: result, + }); + } catch (error) { + next(error); + } +}); + +// GET /api/admin/activity-logs/actions - Get unique action types +router.get('/activity-logs/actions', authenticate, requireAdmin, async (req, res, next) => { + try { + const actions = await getActionTypes(); + + res.json({ + success: true, + count: actions.length, + data: actions, + }); + } catch (error) { + next(error); + } +}); + +// GET /api/admin/activity-logs/stats - Get activity log statistics +router.get('/activity-logs/stats', authenticate, requireAdmin, async (req, res, next) => { + try { + const stats = await getStats(); + + res.json({ + success: true, + data: stats, + }); + } catch (error) { + next(error); + } +});