import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, UsePipes, ValidationPipe, Req, Logger, } from '@nestjs/common'; import { QuestionBankService } from '../services/question-bank.service'; import { CreateQuestionBankDto, UpdateQuestionBankDto, CreateQuestionBankItemDto, UpdateQuestionBankItemDto, ReviewDto, } from '../services/question-bank.service'; import { CombinedAuthGuard } from '../../auth/combined-auth.guard'; import { KnowledgeGroupService } from '../../knowledge-group/knowledge-group.service'; @Controller('question-banks') @UseGuards(CombinedAuthGuard) @UsePipes(ValidationPipe) export class QuestionBankController { private readonly logger = new Logger(QuestionBankController.name); constructor( private readonly questionBankService: QuestionBankService, private readonly groupService: KnowledgeGroupService, ) {} @Post() async create(@Body() createDto: CreateQuestionBankDto, @Req() req: any) { try { this.logger.log(`Creating question bank: ${createDto.name}, user: ${req.user?.id}, tenant: ${req.user?.tenantId}`); return await this.questionBankService.create(createDto, req.user.id, req.user.tenantId); } catch (err: any) { this.logger.error(`[create] Failed: ${err.message}`, err.stack); throw err; } } @Get() findAll( @Req() req: any, @Query('page') page?: string, @Query('limit') limit?: string, ) { const pageNum = page ? parseInt(page, 10) : undefined; const limitNum = limit ? parseInt(limit, 10) : undefined; return this.questionBankService.findAll( req.user.id, req.user.tenantId, pageNum, limitNum, ); } @Get('by-template/:templateId') async findByTemplateId(@Param('templateId') templateId: string) { return this.questionBankService.findByTemplateId(templateId); } @Get(':id') async findOne(@Param('id') id: string) { return this.questionBankService.findOne(id); } @Put(':id') async update(@Param('id') id: string, @Body() updateDto: UpdateQuestionBankDto) { return this.questionBankService.update(id, updateDto); } @Delete(':id') async remove(@Param('id') id: string) { return this.questionBankService.remove(id); } @Put(':id/submit') async submitForReview(@Param('id') id: string, @Req() req: any) { return this.questionBankService.submitForReview(id, req.user.id); } @Put(':id/review') async review(@Param('id') id: string, @Body() reviewDto: ReviewDto, @Req() req: any) { return this.questionBankService.review(id, reviewDto, req.user.id); } @Put(':id/publish') async publish(@Param('id') id: string) { return this.questionBankService.publish(id); } @Get(':bankId/items') async getItems(@Param('bankId') bankId: string) { const bank = await this.questionBankService.findOne(bankId); return bank.items || []; } @Post(':bankId/items') async addItem( @Param('bankId') bankId: string, @Body() createDto: CreateQuestionBankItemDto, ) { return this.questionBankService.addItem(bankId, createDto); } @Put(':bankId/items/:id') async updateItem( @Param('bankId') bankId: string, @Param('id') id: string, @Body() updateDto: UpdateQuestionBankItemDto, ) { return this.questionBankService.updateItem(bankId, id, updateDto); } @Delete(':bankId/items/:id') async removeItem( @Param('bankId') bankId: string, @Param('id') id: string, ) { return this.questionBankService.removeItem(bankId, id); } @Post(':bankId/generate') async generate( @Param('bankId') bankId: string, @Body() body: { count: number; knowledgeBaseContent?: string }, @Req() req: any, ) { let content = body.knowledgeBaseContent || ''; if (!content || content.trim().length < 10) { try { const bank = await this.questionBankService.findOne(bankId); if (bank?.template?.knowledgeGroupId) { const files = await this.groupService.getGroupFiles( bank.template.knowledgeGroupId, req.user.id, req.user.tenantId, ); content = files .filter((f: any) => f.content && f.content.trim().length > 0) .map((f: any) => `--- ${f.title || f.originalName || 'Document'} ---\n${f.content}`) .join('\n\n'); this.logger.log(`[generate] Auto-loaded ${files.length} files, content length: ${content.length}`); } } catch (err: any) { this.logger.warn(`[generate] Auto-load failed: ${err.message}`); } } this.logger.log(`[generate] Generating ${body.count} questions for bank ${bankId}, content length: ${content.length}`); return this.questionBankService.generateQuestions( bankId, body.count, content, req.user.tenantId, ); } @Post(':bankId/items/batch-review') async batchReviewItems( @Param('bankId') bankId: string, @Body() body: { itemIds: string[]; approved: boolean; comment?: string }, ) { this.logger.log(`[batchReview] Reviewing ${body.itemIds.length} items, approved: ${body.approved}`); return this.questionBankService.batchReviewItems( bankId, body.itemIds, body.approved, body.comment, ); } }