Files
gongxue-base/apps/server/src/exams/exams.controller.ts

146 lines
4.3 KiB
TypeScript

import {
Body,
Controller,
Get,
Param,
ParseIntPipe,
Post,
Put,
Query,
Request,
UseGuards,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RequirePermission } from '../auth/decorators/permission.decorator';
import { extractRequestInfo } from '../common/request-utils';
import { OperationLogsService } from '../operation-logs/operation-logs.service';
import type { AuthenticatedUser } from '../authorization';
import { CreateExamDto, QueryExamDto, UpdateExamScoreValueDto } from './dto/exam.dto';
import { ExamsService } from './exams.service';
interface AuthenticatedRequest {
user: AuthenticatedUser;
ip?: string;
headers?: Record<string, string | string[] | undefined>;
}
@UseGuards(JwtAuthGuard)
@UsePipes(new ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true }))
@Controller('exams')
export class ExamsController {
constructor(
private readonly service: ExamsService,
private readonly logService: OperationLogsService,
) {}
private canManageAll(req: AuthenticatedRequest) {
return req.user.isSuperAdmin || req.user.permissions.includes('exam:edit');
}
@Get()
@RequirePermission('exam:view')
async findAll(@Query() query: QueryExamDto, @Request() req: AuthenticatedRequest) {
const classIds = await this.service.getAccessibleClassIds(req.user.id, this.canManageAll(req));
return this.service.findAll(query, classIds);
}
@Get(':id')
@RequirePermission('exam:view')
findOne(@Param('id', ParseIntPipe) id: number, @Request() req: AuthenticatedRequest) {
return this.service.findOne(id, req.user.id, this.canManageAll(req));
}
@Post()
@RequirePermission('exam:view')
async create(@Body() dto: CreateExamDto, @Request() req: AuthenticatedRequest) {
const result = await this.service.create(dto, req.user.id, this.canManageAll(req));
const { ipAddress, userAgent } = extractRequestInfo(req);
await this.logService.log({
userId: req.user.id,
username: req.user.username,
module: '考试管理',
action: '创建考试',
targetId: result.id,
targetType: 'exam',
detail: `${dto.examName} - ${dto.subject}`,
ipAddress,
userAgent,
});
return result;
}
@Put(':id/archive')
@RequirePermission('exam:view')
async archive(
@Param('id', ParseIntPipe) id: number,
@Request() req: AuthenticatedRequest,
) {
const result = await this.service.archive(id, req.user.id, this.canManageAll(req));
const { ipAddress, userAgent } = extractRequestInfo(req);
await this.logService.log({
userId: req.user.id,
username: req.user.username,
module: '考试管理',
action: '归档考试',
targetId: id,
targetType: 'exam',
ipAddress,
userAgent,
});
return result;
}
@Put(':id/restore')
@RequirePermission('exam:view')
async restore(
@Param('id', ParseIntPipe) id: number,
@Request() req: AuthenticatedRequest,
) {
const result = await this.service.restore(id, req.user.id, this.canManageAll(req));
const { ipAddress, userAgent } = extractRequestInfo(req);
await this.logService.log({
userId: req.user.id,
username: req.user.username,
module: '考试管理',
action: '恢复考试',
targetId: id,
targetType: 'exam',
ipAddress,
userAgent,
});
return result;
}
@Put(':examId/scores/:scoreId')
@RequirePermission('exam:view')
async updateScore(
@Param('examId', ParseIntPipe) examId: number,
@Param('scoreId', ParseIntPipe) scoreId: number,
@Body() dto: UpdateExamScoreValueDto,
@Request() req: AuthenticatedRequest,
) {
const result = await this.service.updateScore(
examId,
scoreId,
dto.score,
req.user.id,
this.canManageAll(req),
);
const { ipAddress, userAgent } = extractRequestInfo(req);
await this.logService.log({
userId: req.user.id,
username: req.user.username,
module: '考试管理',
action: dto.score === null || dto.score === undefined ? '清空成绩' : '录入成绩',
targetId: scoreId,
targetType: 'exam_score',
detail: dto.score === null || dto.score === undefined ? '成绩已清空' : `成绩:${dto.score}`,
ipAddress,
userAgent,
});
return result;
}
}