Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] 레벨테스트 리팩토링을 진행한다 (#14) #41

Merged
merged 6 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class LevelTestController {
private final LevelTestService levelTestService;

@PostMapping
@Operation(summary = "레벨 테스트 퀴즈 추가", description = "레벨 테스트 더미 데이터 추가를 위한 API 입니다.")
@Operation(summary = "레벨 테스트 퀴즈 추가", description = "레벨 테스트 더미 데이터 추가를 위한 API 입니다. 사용 X")
public ResponseEntity<ApiResponse<?>> addLevelTestQuiz(
@Valid @RequestBody AddLevelTestQuizRequest request) {

Expand All @@ -44,18 +44,23 @@ public ResponseEntity<ApiResponse<?>> addLevelTestQuiz(
@GetMapping("/quiz")
@Operation(
summary = "레벨 테스트 퀴즈 목록 조회",
description = "레벨 테스트 퀴즈 목록 조회를 위한 API 입니다. 인증 없이 접근가능합니다.")
description =
"레벨 테스트 퀴즈 목록 조회를 위한 API 입니다. 인증 없이 접근가능합니다. 각 레벨에서 랜덤으로 3개씩 가져옵니다. 프론트에서 문제 id와 유저 입력한 정답 캐싱이 필요합니다.")
public ResponseEntity<ApiResponse<?>> getLevelTestQuizList() {
QuizListDTO levelTestQuizList = levelTestService.getLevelTestQuizList();

LevelTestQuizListResponse levelTestQuizListResponse =
LevelTestQuizListResponse.toLevelTestQuizListResponse(levelTestQuizList);
QuizListDTO levelTestQuizList = levelTestService.getLevelTestQuizList();

return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.from(levelTestQuizListResponse));
return ResponseEntity.status(HttpStatus.OK)
.body(
ApiResponse.from(
LevelTestQuizListResponse.toLevelTestQuizListResponse(levelTestQuizList)));
}

@PostMapping("/result")
@Operation(summary = "레벨 테스트 결과 제출", description = "레벨 테스트 결과 제출을 위한 API 입니다.")
@Operation(
summary = "레벨 테스트 결과 제출",
description =
"레벨 테스트 결과 제출을 위한 API 입니다. 테스트 종료 후, 각 문제 id와 답안을 한번에 서버로 전송하면 정답률, 유저의 레벨, 틀린문제에 대한 해설을 반환합니다.")
public ResponseEntity<ApiResponse<?>> submitLevelTestResult(
@Valid @RequestBody SubmitLevelTestRequest request,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/ripple/BE/learning/dto/QuizDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static QuizDTO toQuizDTO(final Quiz quiz) {
quiz.getAnswer(),
quiz.getChoices() == null ? null : ChoiceListDTO.toChoiceListDTO(quiz.getChoices()),
quiz.getExplanation(),
null);
quiz.getLearningSet().getName());
}

public static QuizDTO toQuizDTO(Map<String, String> excelData) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@

import com.ripple.BE.learning.domain.type.Type;
import com.ripple.BE.learning.dto.QuizDTO;
import com.ripple.BE.user.domain.type.Level;

public record QuizResponse(
Long id, Type type, String question, String answer, ChoiceListResponse choiceList) {
Long id,
String learningSetName,
Level level,
Type type,
String question,
String answer,
ChoiceListResponse choiceList) {
public static QuizResponse toQuizResponse(final QuizDTO quizDTO) {
return new QuizResponse(
quizDTO.id(),
quizDTO.learningSetName(),
quizDTO.level(),
quizDTO.type(),
quizDTO.question(),
quizDTO.answer(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

public record RandomQuizResponse(
Long quizId, // 퀴즈 ID
String learningSetName, // 학습 세트 이름
String name, // 퀴즈 이름
Type type, // 퀴즈 타입
String question, // 문제
Expand All @@ -15,6 +16,7 @@ public static RandomQuizResponse toQuizResponse(final QuizDTO quizDTO) {

return new RandomQuizResponse(
quizDTO.id(),
quizDTO.learningSetName(),
quizDTO.name(),
quizDTO.type(),
quizDTO.question(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ public interface QuizRepository extends JpaRepository<Quiz, Long>, QuizRepositor
List<Quiz> findAllByLearningSetAndLevel(
@Param("learningSet") LearningSet learningSet, @Param("level") Level level);

List<Quiz> findAllByLevel(Level level);

List<Quiz> findAllByPurpose(Purpose purpose);
}
49 changes: 34 additions & 15 deletions src/main/java/com/ripple/BE/learning/service/LevelTestService.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
package com.ripple.BE.learning.service;

import static com.ripple.BE.learning.exception.errorcode.QuizErrorCode.*;
import static com.ripple.BE.user.exception.errorcode.UserErrorCode.*;

import com.ripple.BE.learning.domain.quiz.Quiz;
import com.ripple.BE.learning.domain.type.Purpose;
import com.ripple.BE.learning.domain.type.Type;
import com.ripple.BE.learning.dto.AnswerDTO;
import com.ripple.BE.learning.dto.QuizDTO;
import com.ripple.BE.learning.dto.QuizListDTO;
import com.ripple.BE.learning.dto.QuizSubmitDTO;
import com.ripple.BE.learning.dto.response.LevelTestResultResponse;
import com.ripple.BE.learning.exception.QuizException;
import com.ripple.BE.learning.repository.quiz.QuizRepository;
import com.ripple.BE.user.domain.User;
import com.ripple.BE.user.domain.type.Level;
import com.ripple.BE.user.exception.UserException;
import com.ripple.BE.user.repository.UserRepository;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -46,10 +45,21 @@ public void addLevelTestQuiz(QuizDTO quizDTO) {

/** 레벨 테스트 퀴즈 목록 조회 */
public QuizListDTO getLevelTestQuizList() {
List<Quiz> list = quizRepository.findAllByPurpose(Purpose.LEVEL_TEST);
List<Quiz> quizList = quizRepository.findAll();

return QuizListDTO.toQuizListDTO(list);
// 추후 학습, 용어 사전 데이터 추가 후 4지선다 답안 랜덤으로 넣는 로직 추가
// 레벨별 퀴즈 목록 조회
List<Quiz> beginnerQuizzes = getRandomQuizzes(quizList, Level.BEGINNER);
List<Quiz> intermediateQuizzes = getRandomQuizzes(quizList, Level.INTERMEDIATE);
List<Quiz> advancedQuizzes = getRandomQuizzes(quizList, Level.ADVANCED);

// 전체 레벨 테스트 퀴즈 목록 생성
List<Quiz> finalQuizzes =
Stream.concat(
Stream.concat(beginnerQuizzes.stream(), intermediateQuizzes.stream()),
advancedQuizzes.stream())
.collect(Collectors.toList());

return QuizListDTO.toQuizListDTO(finalQuizzes);
}

/**
Expand All @@ -61,10 +71,7 @@ public QuizListDTO getLevelTestQuizList() {
*/
@Transactional
public LevelTestResultResponse submitLevelTestResult(QuizSubmitDTO quizSubmitDTO, Long userId) {
// 레벨 테스트 퀴즈 목록 조회
Map<Long, Quiz> quizMap =
quizRepository.findAllByPurpose(Purpose.LEVEL_TEST).stream()
.collect(Collectors.toMap(Quiz::getId, quiz -> quiz));
List<Quiz> quizList = quizRepository.findAll();

Map<Type, Integer> scoreMap =
Map.of(
Expand All @@ -78,12 +85,10 @@ public LevelTestResultResponse submitLevelTestResult(QuizSubmitDTO quizSubmitDTO
List<AnswerDTO> wrongAnswers = new ArrayList<>();

for (QuizSubmitDTO.Answer answer : quizSubmitDTO.answers()) {
Quiz quiz = quizMap.get(answer.quizId());
if (quiz == null) {
throw new QuizException(QUIZ_NOT_FOUND);
}
Quiz quiz =
quizList.stream().filter(q -> q.getId().equals(answer.quizId())).findFirst().orElse(null);

if (quiz.getAnswer().equals(answer.answer())) {
if (quiz != null && quiz.getAnswer().equals(answer.answer())) {
correctCount++;
score += scoreMap.get(quiz.getType());
} else {
Expand Down Expand Up @@ -126,4 +131,18 @@ private Level calculateLevel(int score) {
return Level.ADVANCED;
}
}

/**
* 레벨 테스트 퀴즈 랜덤 조회
*
* @param quizList
* @param level
* @return
*/
private List<Quiz> getRandomQuizzes(List<Quiz> quizList, Level level) {
List<Quiz> quizzes =
quizList.stream().filter(quiz -> quiz.getLevel() == level).collect(Collectors.toList());
Collections.shuffle(quizzes);
return quizzes.stream().limit(3).toList();
}
}