Implement secure quiz question retrieval
This commit is contained in:
1 parent
7b5d091989
commit
c03a7e6362
1 file changed
+47
@@ -1,5 +1,6 @@
|
||||
package com.example.questionbank.service.quiz;
|
||||
|
||||
import com.example.questionbank.domain.Choice;
|
||||
import com.example.questionbank.domain.ExamAttempt;
|
||||
import com.example.questionbank.domain.Question;
|
||||
import com.example.questionbank.domain.Subject;
|
||||
@@ -9,8 +10,11 @@ import com.example.questionbank.repository.ExamAttemptRepository;
|
||||
import com.example.questionbank.repository.QuestionRepository;
|
||||
import com.example.questionbank.repository.SubjectRepository;
|
||||
import com.example.questionbank.repository.UserRepository;
|
||||
import com.example.questionbank.web.rest.dto.ChoiceView;
|
||||
import com.example.questionbank.web.rest.dto.ExamAttemptStartResult;
|
||||
import com.example.questionbank.web.rest.dto.ExamQuestionView;
|
||||
import java.time.Instant;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -37,6 +41,7 @@ public class QuizAttemptService {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
// 1. 시험 응시 시작
|
||||
@Transactional
|
||||
public ExamAttemptStartResult start(Long subjectId, String login) {
|
||||
Subject subject = subjectRepository
|
||||
@@ -65,6 +70,48 @@ public class QuizAttemptService {
|
||||
attempt.setScore(0);
|
||||
|
||||
ExamAttempt saved = attemptRepository.save(attempt);
|
||||
|
||||
return new ExamAttemptStartResult(saved.getId(), saved.getStartedAt());
|
||||
}
|
||||
|
||||
// 2. 시험 문제 조회 (정답은 숨김)
|
||||
@Transactional(readOnly = true)
|
||||
public List<ExamQuestionView> getQuestions(Long attemptId, String login) {
|
||||
ExamAttempt attempt = getOwnedAttempt(attemptId, login);
|
||||
|
||||
if (attempt.getStatus() != AttemptStatus.IN_PROGRESS) {
|
||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "진행 중인 응시만 문제를 조회할 수 있습니다.");
|
||||
}
|
||||
|
||||
return questionRepository
|
||||
.findAllBySubjectIdAndActiveTrue(attempt.getSubject().getId())
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(Question::getId))
|
||||
.map(question ->
|
||||
new ExamQuestionView(
|
||||
question.getId(),
|
||||
question.getPrompt(),
|
||||
question
|
||||
.getChoices()
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(Choice::getDisplayOrder))
|
||||
.map(choice -> new ChoiceView(choice.getOptionKey(), choice.getContent(), choice.getDisplayOrder()))
|
||||
.toList()
|
||||
)
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// 3. 응시 기록이 로그인한 사용자 본인의 것인지 확인
|
||||
private ExamAttempt getOwnedAttempt(Long attemptId, String login) {
|
||||
ExamAttempt attempt = attemptRepository
|
||||
.findById(attemptId)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "응시를 찾을 수 없습니다."));
|
||||
|
||||
if (!attempt.getUser().getLogin().equals(login)) {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "응시를 찾을 수 없습니다.");
|
||||
}
|
||||
|
||||
return attempt;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user