Spaces:
Sleeping
Sleeping
| import { | |
| Controller, | |
| Get, | |
| Param, | |
| Query, | |
| Request, | |
| UseGuards, | |
| ParseIntPipe, | |
| ParseArrayPipe, | |
| } from '@nestjs/common'; | |
| import { | |
| ApiTags, | |
| ApiBearerAuth, | |
| ApiOperation, | |
| ApiResponse, | |
| ApiParam, | |
| ApiQuery, | |
| } from '@nestjs/swagger'; | |
| import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard'; | |
| import { RolesGuard } from '../../auth/guards/roles.guard'; | |
| import { Roles } from '../../../common/decorators/roles.decorator'; | |
| import { RoleName } from '../../auth/entities/role.entity'; | |
| import { AnalyticsService } from '../services/analytics.service'; | |
| import { AnalyticsQueryDto } from '../dto/analytics-query.dto'; | |
| ('📊 Analytics') | |
| ('JWT-auth') | |
| ('api/analytics') | |
| (JwtAuthGuard, RolesGuard) | |
| export class AnalyticsController { | |
| constructor(private readonly analyticsService: AnalyticsService) {} | |
| ('dashboard') | |
| ({ summary: 'Get analytics dashboard (role-based)' }) | |
| ({ status: 200, description: 'Dashboard data returned' }) | |
| async getDashboard(() req) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = req.user.roles?.map((r) => r.roleName || r) || []; | |
| return this.analyticsService.getDashboard(userId, roles); | |
| } | |
| ('performance') | |
| (RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ summary: 'Get performance metrics' }) | |
| ({ status: 200, description: 'Performance metrics returned' }) | |
| ({ name: 'courseId', required: true, type: Number }) | |
| async getPerformanceMetrics(() req, () query: AnalyticsQueryDto) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = req.user.roles?.map((r) => r.roleName || r) || []; | |
| return this.analyticsService.getPerformanceMetrics( | |
| query.courseId!, | |
| query, | |
| userId, | |
| roles, | |
| ); | |
| } | |
| ('engagement') | |
| (RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ summary: 'Get engagement data' }) | |
| ({ status: 200, description: 'Engagement data returned' }) | |
| ({ name: 'courseId', required: true, type: Number }) | |
| async getEngagement(() req, () query: AnalyticsQueryDto) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = req.user.roles?.map((r) => r.roleName || r) || []; | |
| return this.analyticsService.getEngagement( | |
| query.courseId!, | |
| query, | |
| userId, | |
| roles, | |
| ); | |
| } | |
| ('attendance-trends') | |
| (RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ summary: 'Get attendance trends' }) | |
| ({ status: 200, description: 'Attendance trends returned' }) | |
| ({ name: 'courseId', required: true, type: Number }) | |
| async getAttendanceTrends(() req, () query: AnalyticsQueryDto) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = req.user.roles?.map((r) => r.roleName || r) || []; | |
| return this.analyticsService.getAttendanceTrends( | |
| query.courseId!, | |
| query, | |
| userId, | |
| roles, | |
| ); | |
| } | |
| ('at-risk-students') | |
| (RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ summary: 'Get at-risk students' }) | |
| ({ status: 200, description: 'At-risk students returned' }) | |
| ({ name: 'courseId', required: false, type: Number }) | |
| async getAtRiskStudents(() req, ('courseId') courseId?: number) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = req.user.roles?.map((r) => r.roleName || r) || []; | |
| return this.analyticsService.getAtRiskStudents( | |
| courseId ? Number(courseId) : undefined, | |
| userId, | |
| roles, | |
| ); | |
| } | |
| ('grade-distribution') | |
| (RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ summary: 'Get grade distribution' }) | |
| ({ status: 200, description: 'Grade distribution returned' }) | |
| ({ name: 'courseId', required: true, type: Number }) | |
| async getGradeDistribution( | |
| () req, | |
| ('courseId', ParseIntPipe) courseId: number, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = req.user.roles?.map((r) => r.roleName || r) || []; | |
| return this.analyticsService.getGradeDistribution(courseId, userId, roles); | |
| } | |
| ('enrollment-trends') | |
| (RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ summary: 'Get enrollment trends' }) | |
| ({ status: 200, description: 'Enrollment trends returned' }) | |
| async getEnrollmentTrends(() query: AnalyticsQueryDto) { | |
| return this.analyticsService.getEnrollmentTrends(query); | |
| } | |
| ('course-comparison') | |
| (RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ summary: 'Compare metrics across courses' }) | |
| ({ status: 200, description: 'Course comparison returned' }) | |
| ({ | |
| name: 'courseIds', | |
| required: true, | |
| type: String, | |
| description: 'Comma-separated course IDs', | |
| }) | |
| async getCourseComparison( | |
| () req, | |
| ( | |
| 'courseIds', | |
| new ParseArrayPipe({ items: Number, separator: ',' }), | |
| ) | |
| courseIds: number[], | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = req.user.roles?.map((r) => r.roleName || r) || []; | |
| return this.analyticsService.getCourseComparison(courseIds, userId, roles); | |
| } | |
| ('courses/:courseId') | |
| (RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ summary: 'Get course analytics' }) | |
| ({ status: 200, description: 'Course analytics returned' }) | |
| ({ name: 'courseId', description: 'Course ID', type: Number }) | |
| async getCourseAnalytics( | |
| () req, | |
| ('courseId', ParseIntPipe) courseId: number, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = req.user.roles?.map((r) => r.roleName || r) || []; | |
| return this.analyticsService.getCourseAnalytics(courseId, userId, roles); | |
| } | |
| ('students/:studentId') | |
| ( | |
| RoleName.INSTRUCTOR, | |
| RoleName.ADMIN, | |
| RoleName.IT_ADMIN, | |
| RoleName.STUDENT, | |
| ) | |
| ({ summary: 'Get student analytics' }) | |
| ({ status: 200, description: 'Student analytics returned' }) | |
| ({ name: 'studentId', description: 'Student ID', type: Number }) | |
| ({ name: 'courseId', required: false, type: Number }) | |
| async getStudentAnalytics( | |
| ('studentId', ParseIntPipe) studentId: number, | |
| ('courseId') courseId?: number, | |
| ) { | |
| return this.analyticsService.getStudentAnalytics( | |
| studentId, | |
| courseId ? Number(courseId) : undefined, | |
| ); | |
| } | |
| ('weak-topics/:courseId') | |
| ({ summary: 'Get weak topics analysis' }) | |
| ({ status: 200, description: 'Weak topics returned' }) | |
| ({ name: 'courseId', description: 'Course ID', type: Number }) | |
| ({ name: 'userId', required: false, type: Number }) | |
| async getWeakTopics( | |
| ('courseId', ParseIntPipe) courseId: number, | |
| ('userId') userId?: number, | |
| ) { | |
| return this.analyticsService.getWeakTopics( | |
| courseId, | |
| userId ? Number(userId) : undefined, | |
| ); | |
| } | |
| } | |