fix(M-AI-07-06): answer leak fixes (A3/A4) + state compatibility
- getQuizQuestions: only return answer/explanation after user has submitted - findOne: remove questions include (use getQuizQuestions instead) - State mapping: lifecycleStatus compatible with legacy status field Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
40e772cc3a
commit
c3b8919489
@ -546,11 +546,20 @@ export class UserAiService {
|
||||
async getQuizQuestions(userId: string, quizId: string) {
|
||||
const quiz = await this.prisma.quiz.findFirst({ where: { id: quizId, userId }, select: { id: true } });
|
||||
if (!quiz) throw new NotFoundException({ errorCode: 'QUIZ_NOT_FOUND', message: 'Quiz not found' });
|
||||
|
||||
// M-AI-07-06: 检查用户是否已提交过该 Quiz(至少一次 attempt finished)
|
||||
const hasAttempt = await this.prisma.quizAttempt.findFirst({
|
||||
where: { quizId, userId, finishedAt: { not: null } },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
return this.prisma.quizQuestion.findMany({
|
||||
where: { quizId },
|
||||
select: {
|
||||
id: true, type: true, stem: true, options: true,
|
||||
answer: true, explanation: true, sourceBlockIds: true, orderIndex: true,
|
||||
// ★ M-AI-07-06: 答案和解析仅在用户已提交后返回
|
||||
...(hasAttempt ? { answer: true, explanation: true } : {}),
|
||||
sourceBlockIds: true, orderIndex: true,
|
||||
},
|
||||
orderBy: { orderIndex: 'asc' },
|
||||
});
|
||||
|
||||
@ -82,7 +82,9 @@ export class QuizService {
|
||||
|
||||
async findOne(id: string) {
|
||||
const quiz = await this.prisma.quiz.findUnique({
|
||||
where: { id }, include: { questions: { orderBy: { orderIndex: 'asc' } } },
|
||||
where: { id },
|
||||
// M-AI-07-06: 不 include questions(避免答案泄漏)
|
||||
// 客户端应使用 getQuizQuestions 获取题目,submit 后通过 getResults 获取答案
|
||||
});
|
||||
if (!quiz) throw new NotFoundException('测验不存在');
|
||||
return quiz;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user