diff --git a/src/main/java/com/shy_polarbear/server/domain/quiz/dto/QuizType.java b/src/main/java/com/shy_polarbear/server/domain/quiz/dto/QuizType.java deleted file mode 100644 index 0b815be..0000000 --- a/src/main/java/com/shy_polarbear/server/domain/quiz/dto/QuizType.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.shy_polarbear.server.domain.quiz.dto; - -import com.shy_polarbear.server.global.common.util.EnumModel; -import com.shy_polarbear.server.global.exception.ExceptionStatus; -import lombok.AllArgsConstructor; - -@AllArgsConstructor -public enum QuizType implements EnumModel { - OX("OX"), MULTIPLE_CHOICE("MULTIPLE_CHOICE"); - - private final String value; - - @Override - public String getKey() { - return this.name(); - } - - @Override - public String getValue() { - return this.value; - } - - public static QuizType toEnum(String stringParam) { - return switch (stringParam.toUpperCase()) { - case "OX" -> OX; - case "MULTIPLE_CHOICE" -> MULTIPLE_CHOICE; - - default -> throw new RuntimeException(ExceptionStatus.SERVER_ERROR.getMessage()); - }; - } -} diff --git a/src/main/java/com/shy_polarbear/server/domain/quiz/dto/response/QuizCardResponse.java b/src/main/java/com/shy_polarbear/server/domain/quiz/dto/response/QuizCardResponse.java index 71c733e..6707efb 100644 --- a/src/main/java/com/shy_polarbear/server/domain/quiz/dto/response/QuizCardResponse.java +++ b/src/main/java/com/shy_polarbear/server/domain/quiz/dto/response/QuizCardResponse.java @@ -1,12 +1,9 @@ package com.shy_polarbear.server.domain.quiz.dto.response; -import com.shy_polarbear.server.domain.quiz.dto.QuizType; import com.shy_polarbear.server.domain.quiz.model.MultipleChoiceQuiz; -import com.shy_polarbear.server.domain.quiz.model.OXQuiz; -import com.shy_polarbear.server.global.common.constants.BusinessLogicConstants; -import lombok.Builder; - +import com.shy_polarbear.server.domain.quiz.model.Quiz; import java.util.List; +import lombok.Builder; @Builder public record QuizCardResponse( @@ -16,23 +13,25 @@ public record QuizCardResponse( int time, List choices // nullable ) { - public static QuizCardResponse of(MultipleChoiceQuiz quiz) { + public static QuizCardResponse from(Quiz quiz) { return QuizCardResponse.builder() .quizId(quiz.getId()) - .type(QuizType.MULTIPLE_CHOICE.getValue()) + .type(quiz.getType().getValue()) .question(quiz.getQuestion()) - .time(BusinessLogicConstants.MULTIPLE_CHOICE_QUIZ_TIME_LIMIT) - .choices(quiz.getMultipleChoiceList().stream().map(MultipleChoiceResponse::of).toList()) + .time(quiz.getTimeLimit()) + .choices(resolveChoicesFromDynamicQuizType(quiz)) .build(); } - public static QuizCardResponse of(OXQuiz quiz) { - return QuizCardResponse.builder() - .quizId(quiz.getId()) - .type(QuizType.OX.getValue()) - .question(quiz.getQuestion()) - .time(BusinessLogicConstants.OX_QUIZ_TIME_LIMIT) - .build(); + private static List resolveChoicesFromDynamicQuizType(Quiz quiz) { + if (quiz.getClass().equals(MultipleChoiceQuiz.class)) { + return ((MultipleChoiceQuiz) quiz).getMultipleChoiceList().stream() + .map(MultipleChoiceResponse::of) + .toList(); + } + + return null; } + } diff --git a/src/main/java/com/shy_polarbear/server/domain/quiz/model/MultipleChoiceQuiz.java b/src/main/java/com/shy_polarbear/server/domain/quiz/model/MultipleChoiceQuiz.java index d337e7c..c095634 100644 --- a/src/main/java/com/shy_polarbear/server/domain/quiz/model/MultipleChoiceQuiz.java +++ b/src/main/java/com/shy_polarbear/server/domain/quiz/model/MultipleChoiceQuiz.java @@ -1,24 +1,25 @@ package com.shy_polarbear.server.domain.quiz.model; +import java.util.ArrayList; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.OneToMany; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; - @Getter @Entity -@DiscriminatorValue("M") @NoArgsConstructor(access = AccessLevel.PROTECTED) public class MultipleChoiceQuiz extends Quiz { @OneToMany(mappedBy = "multipleChoiceQuiz", cascade = CascadeType.ALL, orphanRemoval = true) - private List multipleChoiceList = new ArrayList<>(); + private final List multipleChoiceList = new ArrayList<>(); @Builder public MultipleChoiceQuiz(String question, String explanation) { - super(question, explanation); + super(QuizType.MULTIPLE_CHOICE, question, explanation); } + } diff --git a/src/main/java/com/shy_polarbear/server/domain/quiz/model/OXQuiz.java b/src/main/java/com/shy_polarbear/server/domain/quiz/model/OXQuiz.java index cb16c2e..883687a 100644 --- a/src/main/java/com/shy_polarbear/server/domain/quiz/model/OXQuiz.java +++ b/src/main/java/com/shy_polarbear/server/domain/quiz/model/OXQuiz.java @@ -1,27 +1,25 @@ package com.shy_polarbear.server.domain.quiz.model; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; - -// TODO: Getter, constructor, builder은 어디서 만드는게 좋지? 자식쪽에서 하는게 맞을듯. Quiz에서 만들고 다 적용되면 좋긴한데. @Getter @Entity -@DiscriminatorValue("OX") @NoArgsConstructor(access = AccessLevel.PROTECTED) public class OXQuiz extends Quiz { + @Enumerated(EnumType.STRING) private OXChoice answer; @Builder public OXQuiz(String question, String explanation, OXChoice answer) { - super(question, explanation); + super(QuizType.OX, question, explanation); this.answer = answer; } + } diff --git a/src/main/java/com/shy_polarbear/server/domain/quiz/model/Quiz.java b/src/main/java/com/shy_polarbear/server/domain/quiz/model/Quiz.java index f54a5d1..62f686c 100644 --- a/src/main/java/com/shy_polarbear/server/domain/quiz/model/Quiz.java +++ b/src/main/java/com/shy_polarbear/server/domain/quiz/model/Quiz.java @@ -2,16 +2,22 @@ import com.shy_polarbear.server.global.common.model.BaseEntity; import com.shy_polarbear.server.global.common.util.profiles.CustomProfileUtils; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import javax.persistence.*; - @Getter @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@DiscriminatorColumn(name = "DTYPE") @NoArgsConstructor(access = AccessLevel.PROTECTED) public abstract class Quiz extends BaseEntity { @Id @@ -25,11 +31,22 @@ public abstract class Quiz extends BaseEntity { @Column(nullable = false, length = 1000) private String explanation; - protected Quiz(String question, String explanation) { + @Column(nullable = false, name = "quiz_type") + @Enumerated(EnumType.STRING) + private QuizType type; + + protected Quiz(QuizType type, String question, String explanation) { + this.type = type; this.question = question; this.explanation = explanation; } + public int getTimeLimit() { + return this.type.getTimeLimit(); + } + + + // TODO refactor: Mockito spy 대체 // test public void setIdForMockTest(Long mockId) { CustomProfileUtils.validateIsProfileNullOrTest(); diff --git a/src/main/java/com/shy_polarbear/server/domain/quiz/model/QuizType.java b/src/main/java/com/shy_polarbear/server/domain/quiz/model/QuizType.java index 507246c..ff3d4e6 100644 --- a/src/main/java/com/shy_polarbear/server/domain/quiz/model/QuizType.java +++ b/src/main/java/com/shy_polarbear/server/domain/quiz/model/QuizType.java @@ -1,9 +1,36 @@ package com.shy_polarbear.server.domain.quiz.model; +import com.shy_polarbear.server.domain.quiz.exception.QuizException; +import com.shy_polarbear.server.global.common.util.EnumModel; +import com.shy_polarbear.server.global.exception.ExceptionStatus; +import java.util.Arrays; +import lombok.AllArgsConstructor; -public enum QuizType { +@AllArgsConstructor +public enum QuizType implements EnumModel { + OX("OX", 17), MULTIPLE_CHOICE("MULTIPLE_CHOICE", 17); - // OX, 객관식 - TRUE_FALSE, MULTIPLE_CHOICE + private final String value; + private final int timeLimit; + public static QuizType of(String param) { + return Arrays.stream(QuizType.values()) + .filter(v -> v.getValue().equals(param.toUpperCase())) + .findFirst() + .orElseThrow(() -> new QuizException(ExceptionStatus.CLIENT_ERROR)); + } + + @Override + public String getKey() { + return this.name(); + } + + @Override + public String getValue() { + return this.value; + } + + public int getTimeLimit() { + return this.timeLimit; + } } diff --git a/src/main/java/com/shy_polarbear/server/domain/quiz/service/QuizService.java b/src/main/java/com/shy_polarbear/server/domain/quiz/service/QuizService.java index 3c972a3..2c78e4a 100644 --- a/src/main/java/com/shy_polarbear/server/domain/quiz/service/QuizService.java +++ b/src/main/java/com/shy_polarbear/server/domain/quiz/service/QuizService.java @@ -45,14 +45,14 @@ public QuizCardResponse getDailyQuiz(Long currentUserId) { Quiz quiz = quizRepository.findRecentQuizNotYetSolvedByUser(currentUserId) .orElseThrow(() -> new QuizException(ExceptionStatus.NO_MORE_DAILY_QUIZ)); - return buildQuizCardResponseFromQuiz(quiz); + return QuizCardResponse.from(quiz); } // 복습 퀴즈 조회 : 랜덤으로 5개 public PageResponse getRandomReviewQuizzes(Long currentUserId, int limit) { Slice result = quizRepository .findRandomQuizzesAlreadySolvedByUser(currentUserId, limit) - .map(this::buildQuizCardResponseFromQuiz); + .map(QuizCardResponse::from); Long count = quizRepository.countAllQuizzesAlreadySolvedByUser(currentUserId); return PageResponse.of(result, count); @@ -63,6 +63,7 @@ public WhetherDailyQuizSolvedResponse getWhetherDailyQuizSolved(Long currentUser LocalDate today = LocalDate.now(); Optional optionalUserQuiz = userQuizRepository.findFirstSubmittedDailyQuizByUser(today.toString(), currentUserId); + // TODO refactor: UserQuiz 책임 이동 boolean isSubmitted = optionalUserQuiz.isPresent(); // 레코드 존재 여부 Long quizId = isSubmitted ? optionalUserQuiz.get().getQuiz().getId() : null; // 존재 여부에 따라 id값 할당 boolean isSolved = isSubmitted && optionalUserQuiz.get().isCorrect(); @@ -83,6 +84,7 @@ public OXQuizScoreResponse scoreOXQuizSubmission(Long currentUserId, long quizId } else if (Objects.isNull(request.getAnswer())) { // 시간초과되지 않았는데 선택지가 null: 클라이언트 에러 throw new QuizException(ExceptionStatus.QUIZ_SUBMISSION_NULL_CLIENT_ERROR); } else { + // TODO refactor: OXChoice 책임 이동 OXChoice submittedChoice = OXChoice.toEnum(request.getAnswer()); boolean isCorrect = submittedChoice.equals(oxQuiz.getAnswer()); // 제출된 답안과 실제 답 비교 @@ -111,6 +113,7 @@ public MultipleChoiceQuizScoreResponse scoreMultipleQuizSubmission(Long currentU } else if (Objects.isNull(request.getAnswerId())) { // 시간초과되지 않았는데 선택지가 null: 클라이언트 에러 throw new QuizException(ExceptionStatus.QUIZ_SUBMISSION_NULL_CLIENT_ERROR); } else { + // TODO refactor: MultipleChoiceQuiz 책임 이동 MultipleChoice submittedChoice = multipleChoiceList.stream().filter(it -> it.getId().equals(request.getAnswerId())).findFirst() .orElseThrow(() -> new QuizException(ExceptionStatus.NOT_FOUND_CHOICE)); @@ -122,12 +125,4 @@ public MultipleChoiceQuizScoreResponse scoreMultipleQuizSubmission(Long currentU } } - // 퀴즈 유형에 따른 분기처리 - private QuizCardResponse buildQuizCardResponseFromQuiz(Quiz quiz) { - if (quiz.getClass().equals(OXQuiz.class)) { - return QuizCardResponse.of((OXQuiz) quiz); - } else { - return QuizCardResponse.of((MultipleChoiceQuiz) quiz); - } - } } diff --git a/src/main/java/com/shy_polarbear/server/global/common/constants/BusinessLogicConstants.java b/src/main/java/com/shy_polarbear/server/global/common/constants/BusinessLogicConstants.java index 7472427..ee804fe 100644 --- a/src/main/java/com/shy_polarbear/server/global/common/constants/BusinessLogicConstants.java +++ b/src/main/java/com/shy_polarbear/server/global/common/constants/BusinessLogicConstants.java @@ -1,12 +1,11 @@ package com.shy_polarbear.server.global.common.constants; -public abstract class BusinessLogicConstants { +public abstract class BusinessLogicConstants { // TODO refactor: 각 객체로 책임 이동 /** * 퀴즈 */ - public static final int OX_QUIZ_TIME_LIMIT = 17; - public static final int MULTIPLE_CHOICE_QUIZ_TIME_LIMIT = 17; + public static final String REVIEW_QUIZ_LIMIT_PARAM_DEFAULT_VALUE = "5"; /** diff --git a/src/test/java/com/shy_polarbear/server/domain/quiz/service/QuizServiceTest.java b/src/test/java/com/shy_polarbear/server/domain/quiz/service/QuizServiceTest.java index 0a2ec33..9ee5c90 100644 --- a/src/test/java/com/shy_polarbear/server/domain/quiz/service/QuizServiceTest.java +++ b/src/test/java/com/shy_polarbear/server/domain/quiz/service/QuizServiceTest.java @@ -2,7 +2,7 @@ import com.shy_polarbear.server.domain.point.model.PointType; import com.shy_polarbear.server.domain.point.service.PointService; -import com.shy_polarbear.server.domain.quiz.dto.QuizType; +import com.shy_polarbear.server.domain.quiz.model.QuizType; import com.shy_polarbear.server.domain.quiz.dto.request.MultipleChoiceQuizScoreRequest; import com.shy_polarbear.server.domain.quiz.dto.request.OXQuizScoreRequest; import com.shy_polarbear.server.domain.quiz.dto.response.MultipleChoiceQuizScoreResponse; @@ -16,7 +16,6 @@ import com.shy_polarbear.server.domain.user.model.User; import com.shy_polarbear.server.domain.user.service.UserService; import com.shy_polarbear.server.domain.user.template.UserTemplate; -import com.shy_polarbear.server.global.common.constants.BusinessLogicConstants; import com.shy_polarbear.server.global.common.dto.PageResponse; import com.shy_polarbear.server.global.exception.ExceptionStatus; import org.junit.jupiter.api.DisplayName; @@ -81,7 +80,7 @@ public void getDailyQuizSuccess() { // then assertThat(response.quizId()).isEqualTo(mockOXQuiz.getId()); assertThat(response.type()).isEqualTo(QuizType.OX.getValue()); - assertThat(response.time()).isEqualTo(BusinessLogicConstants.OX_QUIZ_TIME_LIMIT); + assertThat(response.time()).isEqualTo(QuizType.OX.getTimeLimit()); assertThat(response.question()).isEqualTo(mockOXQuiz.getQuestion()); assertThat(response.choices()).isNull(); } @@ -110,7 +109,7 @@ public void getRandomReviewQuizzesSuccess() { PageResponse response = quizService.getRandomReviewQuizzes(UserTemplate.ID, limit); // then - List mockResponse = mockOXQuizList.stream().map(it -> QuizCardResponse.of((OXQuiz) it)).toList(); + List mockResponse = mockOXQuizList.stream().map(it -> QuizCardResponse.from((OXQuiz) it)).toList(); assertThat(response.getContent()).isEqualTo(mockResponse); }