diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/controller/CsQuizController.java b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/CsQuizController.java index 7a764b1a..bb52b6e5 100644 --- a/src/main/java/darkoverload/itzip/feature/csQuiz/controller/CsQuizController.java +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/CsQuizController.java @@ -4,9 +4,13 @@ import darkoverload.itzip.feature.csQuiz.controller.request.QuizCreatedRequest; import darkoverload.itzip.feature.csQuiz.controller.request.QuizPointRequest; import darkoverload.itzip.feature.csQuiz.controller.response.QuizCategoryDetailResponse; +import darkoverload.itzip.feature.csQuiz.controller.response.QuizRankingResponse; +import darkoverload.itzip.feature.csQuiz.controller.response.QuizRankingResponses; +import darkoverload.itzip.feature.csQuiz.controller.response.QuizScoreResponse; import darkoverload.itzip.feature.csQuiz.entity.QuizCategory; import darkoverload.itzip.feature.csQuiz.entity.UserQuizStatus; import darkoverload.itzip.feature.csQuiz.service.QuizService; +import darkoverload.itzip.feature.csQuiz.service.sub.quizscore.QuizScoreService; import darkoverload.itzip.feature.jwt.infrastructure.CustomUserDetails; import darkoverload.itzip.global.config.response.code.CommonExceptionCode; import darkoverload.itzip.global.config.response.code.CommonResponseCode; @@ -18,6 +22,7 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.RequestBody; import lombok.RequiredArgsConstructor; @@ -31,7 +36,10 @@ @RequestMapping("cs-quiz") @RequiredArgsConstructor public class CsQuizController { + private final QuizService quizService; + private final QuizScoreService quizScoreService; + /** * 주어진 카테고리 ID에 해당하는 카테고리 정보를 조회하는 메서드 * @@ -111,4 +119,39 @@ public String createQuiz( quizService.createQuiz(quizCreatedRequest, customUserDetails); return "문제를 생성했습니다."; } -} \ No newline at end of file + + @Operation( + summary = "퀴즈 점수 조회", + description = "현재 인증된 사용자의 퀴즈 점수를 조회하여 반환합니다." + ) + @ResponseCodeAnnotation(CommonResponseCode.SUCCESS) + @ExceptionCodeAnnotations({ + CommonExceptionCode.NOT_FOUND_USER, + CommonExceptionCode.NOT_FOUND_QUIZ_SCORE + }) + @GetMapping("/score") + public QuizScoreResponse getScore(@AuthenticationPrincipal final CustomUserDetails customUserDetails) { + return QuizScoreResponse.from( + quizScoreService.findQuizScoreById(customUserDetails) + ); + } + + @Operation( + summary = "퀴즈 랭킹 조회", + description = "퀴즈 점수를 기준으로 상위 6명의 랭킹 정보를 조회하여 반환합니다." + ) + @ResponseCodeAnnotation(CommonResponseCode.SUCCESS) + @ExceptionCodeAnnotations({ + CommonExceptionCode.NOT_FOUND_QUIZ_SCORE_RANKING, + CommonExceptionCode.QUIZ_PROCESSING_ERROR + }) + @GetMapping("/rankings") + public QuizRankingResponses getRankings() { + return QuizRankingResponses.of( + quizScoreService.getTop6Ranking().getRankings().stream() + .map(QuizRankingResponse::from) + .toList() + ); + } + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/controller/CsQuizzesController.java b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/CsQuizzesController.java index f8679559..a20ebdd3 100644 --- a/src/main/java/darkoverload/itzip/feature/csQuiz/controller/CsQuizzesController.java +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/CsQuizzesController.java @@ -4,6 +4,7 @@ import darkoverload.itzip.feature.csQuiz.entity.SortBy; import darkoverload.itzip.feature.csQuiz.controller.response.QuizDetailResponse; import darkoverload.itzip.feature.csQuiz.service.QuizService; +import darkoverload.itzip.feature.jwt.infrastructure.CustomUserDetails; import darkoverload.itzip.global.config.response.code.CommonExceptionCode; import darkoverload.itzip.global.config.response.code.CommonResponseCode; import darkoverload.itzip.global.config.swagger.ExceptionCodeAnnotations; @@ -14,9 +15,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.PagedModel; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; - //퀴즈(복수) 관련 엔드포인트 모음 @Tag(name = "Computer Science Quiz", description = "퀴즈(복수) 관련 엔드포인트 모음") @RestController @@ -31,7 +32,6 @@ public class CsQuizzesController { * @param difficulty 퀴즈 난이도 (선택 사항) * @param categoryId 카테고리 ID (선택 사항) * @param sortBy 정렬 기준 (기본값: NEWEST) - * @param userId 사용자 ID (기본값: 0) * @param inUserSolved 사용자가 푼 퀴즈 포함 여부 (기본값: false) * @param page 페이지 번호 (기본값: 0) * @param size 페이지 크기 (기본값: 10) @@ -46,19 +46,20 @@ public class CsQuizzesController { @ExceptionCodeAnnotations({CommonExceptionCode.NOT_FOUND_USER}) @GetMapping("/search") public PagedModel> getFilteredAndSortedQuizzes( + @AuthenticationPrincipal CustomUserDetails userDetails, @Parameter(description = "퀴즈 난이도 입력칸 1~3") @RequestParam(required = false) Integer difficulty, @Parameter(description = "카테고리 식별값 입력칸") @RequestParam(required = false) Long categoryId, @Parameter(description = "NEWEST 새로운 순, OLDEST 오래된 순, RECOMMENED 추천순 아무것도 없으면 새로운순") @RequestParam(required = false, defaultValue = "NEWEST") SortBy sortBy, - @Parameter(description = "사용자 ID") @RequestParam(required = false) Long userId, @Parameter(description = "사용자가 푼 문제를 포함 하는지 true면 포함 false면 미포함") @RequestParam(required = false, defaultValue = "false") boolean inUserSolved, @Parameter(description = "문제 페이지 0부터 시작") @RequestParam(defaultValue = "0") int page, @Parameter(description = "가져올 문제 수") @RequestParam(defaultValue = "10") int size, - @Parameter(description = "검색할 단어") @RequestParam(required = false) String keyword) { + @Parameter(description = "검색할 단어") @RequestParam(required = false) String keyword + ) { QuizQueryRequest quizQueryRequest = QuizQueryRequest.builder() .difficulty(difficulty) .categoryId(categoryId) .sortBy(sortBy) - .userId(userId) + .email(userDetails.getEmail()) .inUserSolved(inUserSolved) .page(page) .size(size) diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/controller/request/QuizQueryRequest.java b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/request/QuizQueryRequest.java index 798eb790..a37db9c8 100644 --- a/src/main/java/darkoverload/itzip/feature/csQuiz/controller/request/QuizQueryRequest.java +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/request/QuizQueryRequest.java @@ -15,7 +15,7 @@ public class QuizQueryRequest { //NEWEST, OLDEST private SortBy sortBy; //사용자 ID - private Long userId; + private String email; //사용자가 푼문제를 포함하는지 ture면 포함 false면 미포함 private boolean inUserSolved; //문제 페이지 0부터 시작 diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/controller/response/QuizRankingResponse.java b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/response/QuizRankingResponse.java new file mode 100644 index 00000000..c8c2f093 --- /dev/null +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/response/QuizRankingResponse.java @@ -0,0 +1,30 @@ +package darkoverload.itzip.feature.csQuiz.controller.response; + +import darkoverload.itzip.feature.csQuiz.entity.QuizRanking; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema(description = "퀴즈 랭킹 응답 DTO로 사용자의 순위, 이름, 그리고 점수를 포함합니다.") +public class QuizRankingResponse { + + @Schema(description = "사용자의 순위", example = "1") + private final int rank; + + @Schema(description = "사용자 이름", example = "홍길동") + private final String name; + + @Schema(description = "퀴즈 점수", example = "100") + private final int score; + + public QuizRankingResponse(final int rank, final String name, final int score) { + this.rank = rank; + this.name = name; + this.score = score; + } + + public static QuizRankingResponse from(final QuizRanking ranking) { + return new QuizRankingResponse(ranking.getRank(), ranking.getName(), ranking.getScore()); + } + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/controller/response/QuizRankingResponses.java b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/response/QuizRankingResponses.java new file mode 100644 index 00000000..b2dc1104 --- /dev/null +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/response/QuizRankingResponses.java @@ -0,0 +1,21 @@ +package darkoverload.itzip.feature.csQuiz.controller.response; + +import lombok.Getter; + +import java.util.Collections; +import java.util.List; + +@Getter +public class QuizRankingResponses { + + private final List responses; + + private QuizRankingResponses(final List responses) { + this.responses = Collections.unmodifiableList(responses); + } + + public static QuizRankingResponses of(final List responses) { + return new QuizRankingResponses(responses); + } + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/controller/response/QuizScoreResponse.java b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/response/QuizScoreResponse.java new file mode 100644 index 00000000..516b48ae --- /dev/null +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/controller/response/QuizScoreResponse.java @@ -0,0 +1,26 @@ +package darkoverload.itzip.feature.csQuiz.controller.response; + +import darkoverload.itzip.feature.csQuiz.entity.QuizScore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema(description = "퀴즈 점수 응답 DTO로 해당 객체는 사용자의 닉네임과 현재 퀴즈 점수를 포함합니다.") +public class QuizScoreResponse { + + @Schema(description = "사용자 닉네임", example = "홍길동") + private final String name; + + @Schema(description = "사용자의 퀴즈 점수", example = "120") + private final int score; + + public QuizScoreResponse(final String name, final int score) { + this.name = name; + this.score = score; + } + + public static QuizScoreResponse from(final QuizScore score) { + return new QuizScoreResponse(score.getUser().getNickname(), score.getScore()); + } + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/entity/QuizRanking.java b/src/main/java/darkoverload/itzip/feature/csQuiz/entity/QuizRanking.java new file mode 100644 index 00000000..e45f6adc --- /dev/null +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/entity/QuizRanking.java @@ -0,0 +1,33 @@ +package darkoverload.itzip.feature.csQuiz.entity; + +import darkoverload.itzip.global.config.response.code.CommonExceptionCode; +import darkoverload.itzip.global.config.response.exception.RestApiException; +import lombok.Getter; + +import java.util.Objects; + +@Getter +public class QuizRanking { + + private final int rank; + private final String name; + private final int score; + + private QuizRanking(final int rank, final String name, final int score) { + checkNameNotNull(name); + this.rank = rank; + this.name = name; + this.score = score; + } + + private void checkNameNotNull(final String name) { + if (Objects.isNull(name)) { + throw new RestApiException(CommonExceptionCode.QUIZ_PROCESSING_ERROR); + } + } + + public static QuizRanking create(final int rank, final QuizScore score) { + return new QuizRanking(rank, score.getUser().getNickname(), score.getScore()); + } + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/entity/QuizRankings.java b/src/main/java/darkoverload/itzip/feature/csQuiz/entity/QuizRankings.java new file mode 100644 index 00000000..40c5ad53 --- /dev/null +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/entity/QuizRankings.java @@ -0,0 +1,22 @@ +package darkoverload.itzip.feature.csQuiz.entity; + +import java.util.Collections; +import java.util.List; + +public class QuizRankings { + + private final List rankings; + + private QuizRankings(final List rankings) { + this.rankings = Collections.unmodifiableList(rankings); + } + + public static QuizRankings of(final List rankings) { + return new QuizRankings(rankings); + } + + public List getRankings() { + return rankings; + } + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/entity/QuizScore.java b/src/main/java/darkoverload/itzip/feature/csQuiz/entity/QuizScore.java new file mode 100644 index 00000000..9bf9770d --- /dev/null +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/entity/QuizScore.java @@ -0,0 +1,49 @@ +package darkoverload.itzip.feature.csQuiz.entity; + +import darkoverload.itzip.feature.user.entity.UserEntity; +import darkoverload.itzip.global.config.response.code.CommonExceptionCode; +import darkoverload.itzip.global.config.response.exception.RestApiException; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.Objects; + +@Getter +@Entity +@Table(name = "quiz_scores") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class QuizScore { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne + @JoinColumn(name = "user_id") + private UserEntity user; + + private Integer score; + + private QuizScore(final UserEntity user) { + notNullParameters(user); + this.user = user; + this.score = 0; + } + + private void notNullParameters(final UserEntity user) { + if (Objects.isNull(user)) { + throw new RestApiException(CommonExceptionCode.QUIZ_PROCESSING_ERROR); + } + } + + public static QuizScore create(final UserEntity user) { + return new QuizScore(user); + } + + public void incrementScore(final Integer score) { + this.score += score; + } + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/repository/quizscore/QuizScoreRepository.java b/src/main/java/darkoverload/itzip/feature/csQuiz/repository/quizscore/QuizScoreRepository.java new file mode 100644 index 00000000..2cde0bae --- /dev/null +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/repository/quizscore/QuizScoreRepository.java @@ -0,0 +1,13 @@ +package darkoverload.itzip.feature.csQuiz.repository.quizscore; + +import darkoverload.itzip.feature.csQuiz.entity.QuizScore; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +public interface QuizScoreRepository extends JpaRepository { + + Optional> findTop6ByOrderByScoreDesc(); + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/service/QuizService.java b/src/main/java/darkoverload/itzip/feature/csQuiz/service/QuizService.java index 6e14aa91..d67f7434 100644 --- a/src/main/java/darkoverload/itzip/feature/csQuiz/service/QuizService.java +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/service/QuizService.java @@ -3,7 +3,7 @@ import darkoverload.itzip.feature.csQuiz.service.sub.quiz.CheckAnswer; import darkoverload.itzip.feature.csQuiz.service.sub.quiz.CreateQuiz; import darkoverload.itzip.feature.csQuiz.service.sub.quiz.GivenPointToQuiz; -import darkoverload.itzip.feature.csQuiz.service.sub.quizCategory.FindQuizCategory; +import darkoverload.itzip.feature.csQuiz.service.sub.quizcategory.FindQuizCategory; import darkoverload.itzip.feature.csQuiz.service.sub.quizzes.FindQiuzQuery; //컨트롤러가 사용할 service계층 진입점 상속을 통해서 서브 시스템들을 받아온다. diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/service/QuizServiceImpl.java b/src/main/java/darkoverload/itzip/feature/csQuiz/service/QuizServiceImpl.java index 1d79ee29..06f79786 100644 --- a/src/main/java/darkoverload/itzip/feature/csQuiz/service/QuizServiceImpl.java +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/service/QuizServiceImpl.java @@ -8,11 +8,10 @@ import darkoverload.itzip.feature.csQuiz.controller.response.QuizDetailResponse; import darkoverload.itzip.feature.csQuiz.entity.QuizCategory; import darkoverload.itzip.feature.csQuiz.entity.UserQuizStatus; -import darkoverload.itzip.feature.csQuiz.repository.quiz.QuizRepository; import darkoverload.itzip.feature.csQuiz.service.sub.quiz.CheckAnswer; import darkoverload.itzip.feature.csQuiz.service.sub.quiz.CreateQuiz; import darkoverload.itzip.feature.csQuiz.service.sub.quiz.GivenPointToQuiz; -import darkoverload.itzip.feature.csQuiz.service.sub.quizCategory.FindQuizCategory; +import darkoverload.itzip.feature.csQuiz.service.sub.quizcategory.FindQuizCategory; import darkoverload.itzip.feature.csQuiz.service.sub.quizzes.FindQiuzQuery; import darkoverload.itzip.feature.jwt.infrastructure.CustomUserDetails; import lombok.RequiredArgsConstructor; @@ -42,7 +41,6 @@ public class QuizServiceImpl implements QuizService { @Qualifier("createQuizImpl") private final CreateQuiz createQuiz; - private final QuizRepository quizRepository; /** * 주어진 필터와 정렬 기준, 사용자 정보를 기반으로 퀴즈 목록을 조회하는 메서드 diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quiz/CheckAnswerImpl.java b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quiz/CheckAnswerImpl.java index f3976343..d63d1358 100644 --- a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quiz/CheckAnswerImpl.java +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quiz/CheckAnswerImpl.java @@ -2,9 +2,11 @@ import darkoverload.itzip.feature.csQuiz.controller.request.QuizAnswerRequest; import darkoverload.itzip.feature.csQuiz.entity.QuizDocument; +import darkoverload.itzip.feature.csQuiz.entity.QuizScore; import darkoverload.itzip.feature.csQuiz.entity.QuizUserSolvedMapping; import darkoverload.itzip.feature.csQuiz.entity.UserQuizStatus; import darkoverload.itzip.feature.csQuiz.repository.quiz.QuizRepository; +import darkoverload.itzip.feature.csQuiz.repository.quizscore.QuizScoreRepository; import darkoverload.itzip.feature.csQuiz.repository.quizusersolvedmapping.QuizUserSolvedMappingRepository; import darkoverload.itzip.feature.jwt.infrastructure.CustomUserDetails; import darkoverload.itzip.feature.user.domain.User; @@ -22,8 +24,18 @@ @Service @RequiredArgsConstructor public class CheckAnswerImpl implements CheckAnswer { + + private static final int EASY = 1; + private static final int MEDIUM = 2; + private static final int HARD = 3; + + private static final int EASY_SCORE = 10; + private static final int MEDIUM_SCORE = 20; + private static final int HARD_SCORE = 30; + //퀴즈 정답 체크에 필요한 리파지토리 private final QuizRepository quizRepository; + private final QuizScoreRepository quizScoreRepository; private final QuizUserSolvedMappingRepository quizUserSolvedMappingRepository; //User객체를 받아올 userRepository; @@ -86,6 +98,31 @@ public UserQuizStatus checkAnswer(QuizAnswerRequest quizAnswerRequest, CustomUse .modifyDate(LocalDateTime.now()) .build()); + if (isCorrect) { + final QuizScore quizScore = quizScoreRepository.findById(userEntity.getId()) + .orElseGet(() -> { + QuizScore newQuizScore = QuizScore.create(userEntity); + return quizScoreRepository.save(newQuizScore); + }); + + switch (quizDocument.getDifficulty()) { + case HARD -> quizScore.incrementScore(calculateScore(HARD)); + case MEDIUM -> quizScore.incrementScore(calculateScore(MEDIUM)); + case EASY -> quizScore.incrementScore(calculateScore(EASY)); + default -> throw new RestApiException(CommonExceptionCode.NOT_FOUND_DIFFICULTY); + } + } + return quizStatus; } + + private int calculateScore(final int difficulty) { + return switch (difficulty) { + case HARD -> HARD_SCORE; + case MEDIUM -> MEDIUM_SCORE; + case EASY -> EASY_SCORE; + default -> throw new RestApiException(CommonExceptionCode.NOT_FOUND_DIFFICULTY); + }; + } + } \ No newline at end of file diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizCategory/FindQuizCategory.java b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizcategory/FindQuizCategory.java similarity index 85% rename from src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizCategory/FindQuizCategory.java rename to src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizcategory/FindQuizCategory.java index 03e64b88..e3db1445 100644 --- a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizCategory/FindQuizCategory.java +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizcategory/FindQuizCategory.java @@ -1,4 +1,4 @@ -package darkoverload.itzip.feature.csQuiz.service.sub.quizCategory; +package darkoverload.itzip.feature.csQuiz.service.sub.quizcategory; import darkoverload.itzip.feature.csQuiz.controller.response.QuizCategoryDetailResponse; import darkoverload.itzip.feature.csQuiz.entity.QuizCategory; diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizCategory/FindQuizCategoryImpl.java b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizcategory/FindQuizCategoryImpl.java similarity index 96% rename from src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizCategory/FindQuizCategoryImpl.java rename to src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizcategory/FindQuizCategoryImpl.java index 22ea638d..10dde3d7 100644 --- a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizCategory/FindQuizCategoryImpl.java +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizcategory/FindQuizCategoryImpl.java @@ -1,4 +1,4 @@ -package darkoverload.itzip.feature.csQuiz.service.sub.quizCategory; +package darkoverload.itzip.feature.csQuiz.service.sub.quizcategory; import darkoverload.itzip.feature.csQuiz.controller.response.QuizCategoryDetailResponse; import darkoverload.itzip.feature.csQuiz.entity.QuizCategory; diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizscore/QuizScoreService.java b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizscore/QuizScoreService.java new file mode 100644 index 00000000..3ca0ab2a --- /dev/null +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizscore/QuizScoreService.java @@ -0,0 +1,13 @@ +package darkoverload.itzip.feature.csQuiz.service.sub.quizscore; + +import darkoverload.itzip.feature.csQuiz.entity.QuizRankings; +import darkoverload.itzip.feature.csQuiz.entity.QuizScore; +import darkoverload.itzip.feature.jwt.infrastructure.CustomUserDetails; + +public interface QuizScoreService { + + QuizScore findQuizScoreById(CustomUserDetails userDetails); + + QuizRankings getTop6Ranking(); + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizscore/QuizScoreServiceImpl.java b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizscore/QuizScoreServiceImpl.java new file mode 100644 index 00000000..c66b8848 --- /dev/null +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizscore/QuizScoreServiceImpl.java @@ -0,0 +1,54 @@ +package darkoverload.itzip.feature.csQuiz.service.sub.quizscore; + +import darkoverload.itzip.feature.csQuiz.entity.QuizRanking; +import darkoverload.itzip.feature.csQuiz.entity.QuizRankings; +import darkoverload.itzip.feature.csQuiz.entity.QuizScore; +import darkoverload.itzip.feature.csQuiz.repository.quizscore.QuizScoreRepository; +import darkoverload.itzip.feature.jwt.infrastructure.CustomUserDetails; +import darkoverload.itzip.feature.user.domain.User; +import darkoverload.itzip.feature.user.entity.UserEntity; +import darkoverload.itzip.feature.user.service.UserService; +import darkoverload.itzip.global.config.response.code.CommonExceptionCode; +import darkoverload.itzip.global.config.response.exception.RestApiException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class QuizScoreServiceImpl implements QuizScoreService { + + private final UserService userService; + + private final QuizScoreRepository quizScoreRepository; + + @Override + public QuizScore findQuizScoreById(CustomUserDetails userDetails) { + final UserEntity user = userService.findByEmail(userDetails.getEmail()) + .map(User::convertToEntity) + .orElseThrow(() -> new RestApiException(CommonExceptionCode.NOT_FOUND_USER)); + + return quizScoreRepository.findById(user.getId()) + .orElseThrow(() -> new RestApiException(CommonExceptionCode.NOT_FOUND_QUIZ_SCORE)); + } + + @Override + public QuizRankings getTop6Ranking() { + final List scores = quizScoreRepository.findTop6ByOrderByScoreDesc() + .orElseThrow(() -> new RestApiException(CommonExceptionCode.NOT_FOUND_QUIZ_SCORE_RANKING)); + + final List rankings = new ArrayList<>(); + int rank = 1; + for (QuizScore score : scores) { + rankings.add(QuizRanking.create(rank, score)); + rank++; + } + + return QuizRankings.of(rankings); + } + +} diff --git a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizzes/FindQuizQuerytImpl.java b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizzes/FindQuizQuerytImpl.java index 797e3731..07b29eca 100644 --- a/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizzes/FindQuizQuerytImpl.java +++ b/src/main/java/darkoverload/itzip/feature/csQuiz/service/sub/quizzes/FindQuizQuerytImpl.java @@ -51,9 +51,9 @@ public PagedModel> findQuizzesByQuery(QuizQueryR // 사용자가 푼 문제의 Id값들만 저장할 리스트 초기화 List solvedProblemIds = new ArrayList<>(); - if (quizQueryRequest.getUserId() != null){ + if (quizQueryRequest.isInUserSolved() != true && quizQueryRequest.getEmail() != null) { //사용자를 찾고 사용자가 없을시 사용자가 없음 예외 출력 - UserEntity userEntity = userService.getById(quizQueryRequest.getUserId()) + UserEntity userEntity = userService.getByEmail(quizQueryRequest.getEmail()) .convertToEntity(); //사용자가 푼문제매핑 테이블 list로 받아옴 diff --git a/src/main/java/darkoverload/itzip/global/config/response/code/CommonExceptionCode.java b/src/main/java/darkoverload/itzip/global/config/response/code/CommonExceptionCode.java index 160642ee..629ece26 100644 --- a/src/main/java/darkoverload/itzip/global/config/response/code/CommonExceptionCode.java +++ b/src/main/java/darkoverload/itzip/global/config/response/code/CommonExceptionCode.java @@ -130,6 +130,14 @@ public enum CommonExceptionCode implements ResponseCode { ALREADY_CORRECT(HttpStatus.BAD_REQUEST, "이미 정답을 맞췄습니다."), //카테고리가 없음 NOT_FOUND_CATEGORY(HttpStatus.NOT_FOUND, "카테고리가 없습니다."), + //난이도 없음 + NOT_FOUND_DIFFICULTY(HttpStatus.NOT_FOUND, "난이도가 없습니다."), + //퀴즈 처리 중 문제 발생 + QUIZ_PROCESSING_ERROR(HttpStatus.BAD_REQUEST, "퀴즈 처리 중 문제가 발생했습니다."), + //퀴즈 점수가 없음 + NOT_FOUND_QUIZ_SCORE(HttpStatus.NOT_FOUND, "퀴즈 점수를 찾을 수 없습니다"), + //퀴즈 랭킹이 없음 + NOT_FOUND_QUIZ_SCORE_RANKING(HttpStatus.NOT_FOUND, "랭킹을 찾을 수 없습니다."), /** * Algorithm Error