UNPKG

mcp-quiz-server

Version:

🧠 AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.

232 lines (231 loc) • 9.52 kB
"use strict"; /** * @fileoverview Stats Routes - Clean Architecture HTTP routes for statistics and analytics * @version 1.0.0 * @since 2025-07-31 * @lastUpdated 2025-07-31 * @module StatsRoutes * @description HTTP routes for statistics and analytics following clean architecture principles. * Provides endpoints for user statistics, quiz analytics, and system metrics. * @contributors Claude Code Agent * @dependencies express, error-handler, audit-logger * @requirements REQ_API_001, REQ_PERF_001, REQ_COMPLIANCE_004 * @testCoverage Statistics route integration tests */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.createStatsRoutes = createStatsRoutes; const express = __importStar(require("express")); const error_handler_1 = require("../../../shared/error-handler"); /** * Creates statistics and analytics HTTP routes following clean architecture patterns. * * @description Sets up endpoints for user statistics, quiz analytics, and system * metrics with proper audit logging and error handling. * * @param config - Configuration object with dependencies * @returns Express router with statistics routes * * @example * ```typescript * const statsRouter = createStatsRoutes({ * auditLogger, * legacyService: quizService * }); * app.use('/stats', statsRouter); * ``` * * @since 2025-07-31 * @author Claude Code Agent * @requirements REQ_API_001 (Quiz Operations), REQ_PERF_001 (Performance Standards) * @accessibility Standard HTTP REST API for statistics data */ function createStatsRoutes(config) { const router = express.Router(); const { auditLogger, legacyService, authMiddleware } = config; /** * GET /stats/quiz - Get overall quiz statistics * Provides system-wide quiz statistics and metrics * Requires authentication and appropriate permissions */ router.get('/quiz', (authMiddleware === null || authMiddleware === void 0 ? void 0 : authMiddleware.requirePermission) ? authMiddleware.requirePermission('quiz:analyze') : (req, res, next) => { error_handler_1.Logger.warn('🚨 SECURITY WARNING: /stats/quiz endpoint is UNPROTECTED'); next(); }, (0, error_handler_1.asyncHandler)(async (req, res, next) => { try { if (!legacyService) { return res.status(503).json({ error: 'Statistics service not available' }); } const stats = await legacyService.getQuizStatistics(); // Audit log statistics access auditLogger.logUserAction('STATS_ACCESS', { resource: 'quiz_statistics', resourceId: 'overall_stats', ipAddress: req.ip || req.connection.remoteAddress, userAgent: req.get('User-Agent'), success: true, metadata: { statsType: 'quiz_overall', accessTimestamp: new Date().toISOString(), }, }); res.json({ success: true, statistics: stats, metadata: { generatedAt: new Date().toISOString(), dataType: 'quiz_statistics', }, }); } catch (error) { error_handler_1.Logger.error('Error fetching quiz statistics:', error instanceof Error ? error : new Error(String(error))); res.status(500).json({ success: false, error: 'Failed to fetch quiz statistics', details: error instanceof Error ? error.message : String(error), }); } })); /** * GET /stats/user/:id - Get user statistics * Retrieves performance statistics for a specific user * Requires authentication and owner/admin access */ router.get('/user/:id', (authMiddleware === null || authMiddleware === void 0 ? void 0 : authMiddleware.requireOwner) ? authMiddleware.requireOwner : (req, res, next) => { error_handler_1.Logger.warn('🚨 SECURITY WARNING: /stats/user/:id endpoint is UNPROTECTED'); next(); }, (0, error_handler_1.asyncHandler)(async (req, res, next) => { try { if (!legacyService) { return res.status(503).json({ error: 'Statistics service not available' }); } const userId = req.params.id; const stats = await legacyService.getUserStatistics(userId); // Audit log user statistics access auditLogger.logUserAction('STATS_ACCESS', { resource: 'user_statistics', resourceId: userId, ipAddress: req.ip || req.connection.remoteAddress, userAgent: req.get('User-Agent'), success: true, metadata: { targetUserId: userId, statsType: 'user_specific', accessTimestamp: new Date().toISOString(), }, }); res.json({ success: true, userId, statistics: stats, metadata: { generatedAt: new Date().toISOString(), dataType: 'user_statistics', }, }); } catch (error) { error_handler_1.Logger.error('Error fetching user statistics:', error instanceof Error ? error : new Error(String(error))); res.status(500).json({ success: false, error: 'Failed to fetch user statistics', details: error instanceof Error ? error.message : String(error), }); } })); /** * GET /stats/performance - Get system performance metrics * Provides performance and health metrics for the system */ router.get('/performance', (0, error_handler_1.asyncHandler)(async (req, res, next) => { var _a; try { const performanceMetrics = { timestamp: new Date().toISOString(), system: { nodeVersion: process.version, platform: process.platform, uptime: Math.floor(process.uptime()), memoryUsage: process.memoryUsage(), }, process: { pid: process.pid, ppid: process.ppid, cwd: process.cwd(), execPath: process.execPath, }, resources: { cpuUsage: process.cpuUsage(), resourceUsage: ((_a = process.resourceUsage) === null || _a === void 0 ? void 0 : _a.call(process)) || null, }, }; // Audit log performance metrics access auditLogger.logUserAction('STATS_ACCESS', { resource: 'performance_metrics', resourceId: 'system_performance', ipAddress: req.ip || req.connection.remoteAddress, userAgent: req.get('User-Agent'), success: true, metadata: { statsType: 'performance', systemUptime: performanceMetrics.system.uptime, accessTimestamp: new Date().toISOString(), }, }); res.json({ success: true, performance: performanceMetrics, metadata: { generatedAt: new Date().toISOString(), dataType: 'performance_metrics', }, }); } catch (error) { error_handler_1.Logger.error('Error fetching performance metrics:', error instanceof Error ? error : new Error(String(error))); res.status(500).json({ success: false, error: 'Failed to fetch performance metrics', details: error instanceof Error ? error.message : String(error), }); } })); return router; }