422 lines
13 KiB
JavaScript
422 lines
13 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const questionController = require('../controllers/question.controller');
|
|
const adminController = require('../controllers/admin.controller');
|
|
const { verifyToken, isAdmin } = require('../middleware/auth.middleware');
|
|
const { adminLimiter } = require('../middleware/rateLimiter');
|
|
const { cacheStatistics, cacheGuestAnalytics, cacheGuestSettings, invalidateCacheMiddleware, invalidateCache } = require('../middleware/cache');
|
|
|
|
/**
|
|
* @swagger
|
|
* /admin/statistics:
|
|
* get:
|
|
* summary: Get system-wide statistics for admin dashboard
|
|
* tags: [Admin]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* responses:
|
|
* 200:
|
|
* description: Statistics retrieved successfully
|
|
* content:
|
|
* application/json:
|
|
* schema:
|
|
* type: object
|
|
* properties:
|
|
* users:
|
|
* type: object
|
|
* properties:
|
|
* total:
|
|
* type: integer
|
|
* active:
|
|
* type: integer
|
|
* inactiveLast7Days:
|
|
* type: integer
|
|
* quizzes:
|
|
* type: object
|
|
* properties:
|
|
* totalSessions:
|
|
* type: integer
|
|
* averageScore:
|
|
* type: number
|
|
* passRate:
|
|
* type: number
|
|
* content:
|
|
* type: object
|
|
* properties:
|
|
* totalCategories:
|
|
* type: integer
|
|
* totalQuestions:
|
|
* type: integer
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
*
|
|
* /admin/guest-settings:
|
|
* get:
|
|
* summary: Get guest user settings
|
|
* tags: [Admin]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* responses:
|
|
* 200:
|
|
* description: Guest settings retrieved successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
* put:
|
|
* summary: Update guest user settings
|
|
* tags: [Admin]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* requestBody:
|
|
* content:
|
|
* application/json:
|
|
* schema:
|
|
* type: object
|
|
* properties:
|
|
* maxQuizzes:
|
|
* type: integer
|
|
* minimum: 1
|
|
* maximum: 100
|
|
* expiryHours:
|
|
* type: integer
|
|
* minimum: 1
|
|
* maximum: 168
|
|
* publicCategories:
|
|
* type: array
|
|
* items:
|
|
* type: integer
|
|
* featureRestrictions:
|
|
* type: object
|
|
* responses:
|
|
* 200:
|
|
* description: Settings updated successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
*
|
|
* /admin/guest-analytics:
|
|
* get:
|
|
* summary: Get guest user analytics
|
|
* tags: [Admin]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* responses:
|
|
* 200:
|
|
* description: Analytics retrieved successfully
|
|
* content:
|
|
* application/json:
|
|
* schema:
|
|
* type: object
|
|
* properties:
|
|
* overview:
|
|
* type: object
|
|
* properties:
|
|
* totalGuestSessions:
|
|
* type: integer
|
|
* activeGuestSessions:
|
|
* type: integer
|
|
* convertedGuestSessions:
|
|
* type: integer
|
|
* conversionRate:
|
|
* type: number
|
|
* quizActivity:
|
|
* type: object
|
|
* behavior:
|
|
* type: object
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
*
|
|
* /admin/users:
|
|
* get:
|
|
* summary: Get all users with pagination and filtering
|
|
* tags: [Admin]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* parameters:
|
|
* - in: query
|
|
* name: page
|
|
* schema:
|
|
* type: integer
|
|
* default: 1
|
|
* - in: query
|
|
* name: limit
|
|
* schema:
|
|
* type: integer
|
|
* default: 10
|
|
* maximum: 100
|
|
* - in: query
|
|
* name: role
|
|
* schema:
|
|
* type: string
|
|
* enum: [user, admin]
|
|
* - in: query
|
|
* name: isActive
|
|
* schema:
|
|
* type: boolean
|
|
* - in: query
|
|
* name: sortBy
|
|
* schema:
|
|
* type: string
|
|
* enum: [createdAt, username, email]
|
|
* - in: query
|
|
* name: sortOrder
|
|
* schema:
|
|
* type: string
|
|
* enum: [asc, desc]
|
|
* responses:
|
|
* 200:
|
|
* description: Users retrieved successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
*
|
|
* /admin/users/{userId}:
|
|
* get:
|
|
* summary: Get user details by ID
|
|
* tags: [Admin]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* parameters:
|
|
* - in: path
|
|
* name: userId
|
|
* required: true
|
|
* schema:
|
|
* type: integer
|
|
* responses:
|
|
* 200:
|
|
* description: User details retrieved successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
* 404:
|
|
* $ref: '#/components/responses/NotFoundError'
|
|
*/
|
|
|
|
// Apply admin rate limiter to all routes
|
|
router.use(adminLimiter);
|
|
|
|
router.get('/statistics', verifyToken, isAdmin, cacheStatistics, adminController.getSystemStatistics);
|
|
router.get('/guest-settings', verifyToken, isAdmin, cacheGuestSettings, adminController.getGuestSettings);
|
|
router.put('/guest-settings', verifyToken, isAdmin, invalidateCacheMiddleware(() => invalidateCache.guestSettings()), adminController.updateGuestSettings);
|
|
router.get('/guest-analytics', verifyToken, isAdmin, cacheGuestAnalytics, adminController.getGuestAnalytics);
|
|
router.get('/users', verifyToken, isAdmin, adminController.getAllUsers);
|
|
router.get('/users/:userId', verifyToken, isAdmin, adminController.getUserById);
|
|
|
|
/**
|
|
* @swagger
|
|
* /admin/users/{userId}/role:
|
|
* put:
|
|
* summary: Update user role
|
|
* tags: [Admin]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* parameters:
|
|
* - in: path
|
|
* name: userId
|
|
* required: true
|
|
* schema:
|
|
* type: integer
|
|
* requestBody:
|
|
* required: true
|
|
* content:
|
|
* application/json:
|
|
* schema:
|
|
* type: object
|
|
* required:
|
|
* - role
|
|
* properties:
|
|
* role:
|
|
* type: string
|
|
* enum: [user, admin]
|
|
* responses:
|
|
* 200:
|
|
* description: User role updated successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
* 404:
|
|
* $ref: '#/components/responses/NotFoundError'
|
|
*
|
|
* /admin/users/{userId}/activate:
|
|
* put:
|
|
* summary: Reactivate deactivated user
|
|
* tags: [Admin]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* parameters:
|
|
* - in: path
|
|
* name: userId
|
|
* required: true
|
|
* schema:
|
|
* type: integer
|
|
* responses:
|
|
* 200:
|
|
* description: User reactivated successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
* 404:
|
|
* $ref: '#/components/responses/NotFoundError'
|
|
*
|
|
* /admin/users/{userId}:
|
|
* delete:
|
|
* summary: Deactivate user (soft delete)
|
|
* tags: [Admin]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* parameters:
|
|
* - in: path
|
|
* name: userId
|
|
* required: true
|
|
* schema:
|
|
* type: integer
|
|
* responses:
|
|
* 200:
|
|
* description: User deactivated successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
* 404:
|
|
* $ref: '#/components/responses/NotFoundError'
|
|
*
|
|
* /admin/questions:
|
|
* post:
|
|
* summary: Create a new question
|
|
* tags: [Questions]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* requestBody:
|
|
* required: true
|
|
* content:
|
|
* application/json:
|
|
* schema:
|
|
* type: object
|
|
* required:
|
|
* - questionText
|
|
* - questionType
|
|
* - correctAnswer
|
|
* - difficulty
|
|
* - categoryId
|
|
* properties:
|
|
* questionText:
|
|
* type: string
|
|
* questionType:
|
|
* type: string
|
|
* enum: [multiple_choice, trueFalse, short_answer]
|
|
* options:
|
|
* type: array
|
|
* items:
|
|
* type: string
|
|
* correctAnswer:
|
|
* type: string
|
|
* difficulty:
|
|
* type: string
|
|
* enum: [easy, medium, hard]
|
|
* points:
|
|
* type: integer
|
|
* explanation:
|
|
* type: string
|
|
* categoryId:
|
|
* type: integer
|
|
* tags:
|
|
* type: array
|
|
* items:
|
|
* type: string
|
|
* keywords:
|
|
* type: array
|
|
* items:
|
|
* type: string
|
|
* responses:
|
|
* 201:
|
|
* description: Question created successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
*
|
|
* /admin/questions/{id}:
|
|
* put:
|
|
* summary: Update a question
|
|
* tags: [Questions]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* parameters:
|
|
* - in: path
|
|
* name: id
|
|
* required: true
|
|
* schema:
|
|
* type: integer
|
|
* requestBody:
|
|
* content:
|
|
* application/json:
|
|
* schema:
|
|
* type: object
|
|
* properties:
|
|
* questionText:
|
|
* type: string
|
|
* options:
|
|
* type: array
|
|
* items:
|
|
* type: string
|
|
* correctAnswer:
|
|
* type: string
|
|
* difficulty:
|
|
* type: string
|
|
* enum: [easy, medium, hard]
|
|
* isActive:
|
|
* type: boolean
|
|
* responses:
|
|
* 200:
|
|
* description: Question updated successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
* 404:
|
|
* $ref: '#/components/responses/NotFoundError'
|
|
* delete:
|
|
* summary: Delete a question (soft delete)
|
|
* tags: [Questions]
|
|
* security:
|
|
* - bearerAuth: []
|
|
* parameters:
|
|
* - in: path
|
|
* name: id
|
|
* required: true
|
|
* schema:
|
|
* type: integer
|
|
* responses:
|
|
* 200:
|
|
* description: Question deleted successfully
|
|
* 401:
|
|
* $ref: '#/components/responses/UnauthorizedError'
|
|
* 403:
|
|
* $ref: '#/components/responses/ForbiddenError'
|
|
* 404:
|
|
* $ref: '#/components/responses/NotFoundError'
|
|
*/
|
|
// Apply admin rate limiter to all routes
|
|
router.use(adminLimiter);
|
|
|
|
router.put('/users/:userId/role', verifyToken, isAdmin, adminController.updateUserRole);
|
|
router.put('/users/:userId/activate', verifyToken, isAdmin, adminController.reactivateUser);
|
|
router.delete('/users/:userId', verifyToken, isAdmin, adminController.deactivateUser);
|
|
router.get('/questions', verifyToken, isAdmin, questionController.getAllQuestions);
|
|
router.get('/questions/:id', verifyToken, isAdmin, questionController.getQuestionByIdAdmin);
|
|
router.post('/questions', verifyToken, isAdmin, questionController.createQuestion);
|
|
router.put('/questions/:id', verifyToken, isAdmin, questionController.updateQuestion);
|
|
router.delete('/questions/:id', verifyToken, isAdmin, questionController.deleteQuestion);
|
|
|
|
module.exports = router;
|