From e3dd0f7d8272b8f205c2aec9acd5051843269639 Mon Sep 17 00:00:00 2001 From: sh0723 Date: Wed, 20 Aug 2025 12:15:44 +0900 Subject: [PATCH 1/8] =?UTF-8?q?problem=20list=20API=20=ED=86=B5=EC=9D=BC?= =?UTF-8?q?=20=EB=B0=91=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../problem/enums/ProblemListStatus.java | 8 ++++++++ .../problem/service/ProblemService.java | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java b/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java new file mode 100644 index 00000000..b63822a1 --- /dev/null +++ b/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java @@ -0,0 +1,8 @@ +package com.gamzabat.algohub.feature.problem.enums; + +public enum ProblemListStatus { + IN_PROGRESS, + EXPIRED, + DEADLINE_REACHED, + QUEUED +} diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java b/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java index 9f75d26a..62c2d60c 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java @@ -35,6 +35,7 @@ import com.gamzabat.algohub.feature.problem.dto.CreateProblemRequest; import com.gamzabat.algohub.feature.problem.dto.EditProblemRequest; import com.gamzabat.algohub.feature.problem.dto.GetProblemResponse; +import com.gamzabat.algohub.feature.problem.enums.ProblemListStatus; import com.gamzabat.algohub.feature.problem.exception.NotBojLinkException; import com.gamzabat.algohub.feature.problem.exception.SolvedAcApiErrorException; import com.gamzabat.algohub.feature.problem.repository.ProblemRepository; @@ -148,6 +149,24 @@ private void checkProblemStartDate(EditProblemRequest request, Problem problem) "문제 시작 날짜는 마감 날짜 이후로 수정할 수 없습니다."); } + @Transactional(readOnly = true) + public Page getProblems(User user, Long groupId, Boolean unsolvedOnly, ProblemListStatus status, Pageable pageable) { + Page response; + if (status == ProblemListStatus.IN_PROGRESS) { + response = getInProgressProblems(user, groupId, unsolvedOnly, pageable); + } else if (status == ProblemListStatus.EXPIRED) { + response = getExpiredProblems(user, groupId, pageable); + } else { + response = getQueuedProblems(user, groupId, pageable); + } + /* + else if (status == ProblemListStatus.DEADLINE_REACHED) { + response = getDeadlineReachedProblemList(user,groupId); + } + */ + return response; + } + @Transactional(readOnly = true) public Page getInProgressProblems(User user, Long groupId, Boolean unsolvedOnly, Pageable pageable) { From f21c44082b7b9e2b1a1a012171d9636090ad2760 Mon Sep 17 00:00:00 2001 From: sh0723 Date: Wed, 20 Aug 2025 12:33:11 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=EB=A7=88=EA=B0=90=20=EA=B8=B0=ED=95=9C?= =?UTF-8?q?=EC=9D=B4=20=EB=82=B4=EC=9D=BC=EA=B9=8C=EC=A7=80=EC=9D=B8=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=EB=93=A4=20=EC=A1=B0=ED=9A=8C=20API=20?= =?UTF-8?q?=EC=A0=9C=EC=99=B8=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../problem/controller/ProblemController.java | 41 +++++++------------ .../exception/InvalidRequestException.java | 16 ++++++++ .../problem/service/ProblemService.java | 2 +- 3 files changed, 32 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/gamzabat/algohub/feature/problem/exception/InvalidRequestException.java diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java b/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java index 9bd25039..a413d6b4 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java @@ -6,7 +6,9 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.parameters.P; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -23,6 +25,8 @@ import com.gamzabat.algohub.feature.problem.dto.CreateProblemRequest; import com.gamzabat.algohub.feature.problem.dto.EditProblemRequest; import com.gamzabat.algohub.feature.problem.dto.GetProblemResponse; +import com.gamzabat.algohub.feature.problem.enums.ProblemListStatus; +import com.gamzabat.algohub.feature.problem.exception.InvalidRequestException; import com.gamzabat.algohub.feature.problem.service.ProblemService; import com.gamzabat.algohub.feature.user.domain.User; @@ -59,26 +63,21 @@ public ResponseEntity editProblemDeadline(@AuthedUser User user, return ResponseEntity.ok().build(); } - @GetMapping(value = "/groups/{groupId}/problems/in-progress") - @Operation(summary = "진행 중인 문제 목록 조회 API", description = "특정 그룹에 대한 문제를 모두 조회하는 API") - public ResponseEntity> getInProgressProblemList(@AuthedUser User user, + @GetMapping(value = "/groups/{groupId}/problems") + @Operation(summary = "문제 목록 조회 API", description = "특정 그룹에 대한 문제를 부분 조회하는 API") + public ResponseEntity> getProblems(@AuthedUser User user, @PathVariable Long groupId, - @RequestParam(name = "unsolved-only") Boolean unsolvedOnly, + @RequestParam ProblemListStatus status, + @RequestParam(name = "unsolved-only", required = false) Boolean unsolvedOnly, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { Pageable pageable = PageRequest.of(page, size, Sort.by(PROBLEM_SORT_BY).descending()); - Page response = problemService.getInProgressProblems(user, groupId, unsolvedOnly, pageable); - return ResponseEntity.ok().body(response); - } - - @GetMapping(value = "/groups/{groupId}/problems/expired") - @Operation(summary = "마감 된 문제 목록 조회 API", description = "특정 그룹에 대한 문제를 모두 조회하는 API") - public ResponseEntity> getExpiredProblemList(@AuthedUser User user, - @PathVariable Long groupId, - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") int size) { - Pageable pageable = PageRequest.of(page, size, Sort.by(PROBLEM_SORT_BY).descending()); - Page response = problemService.getExpiredProblems(user, groupId, pageable); + Page response = problemService.getProblems(user, groupId, status, unsolvedOnly, pageable); + if (status == ProblemListStatus.IN_PROGRESS) { + if (unsolvedOnly == null) { + throw new InvalidRequestException(HttpStatus.BAD_REQUEST, "IN_PROGRESS 상태에서는 unsolvedOnly 는 필수입니다."); + } + } return ResponseEntity.ok().body(response); } @@ -96,16 +95,6 @@ public ResponseEntity> getDeadlineReachedProblemList(@A return ResponseEntity.ok().body(problemService.getDeadlineReachedProblemList(user, groupId)); } - @GetMapping("/groups/{groupId}/problems/queued") - @Operation(summary = "시작 예정인 문제들 조회 API") - public ResponseEntity> getQueuedProblemList(@AuthedUser User user, - @PathVariable Long groupId, - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") int size) { - Pageable pageable = PageRequest.of(page, size, Sort.by(PROBLEM_SORT_BY).descending()); - return ResponseEntity.ok().body(problemService.getQueuedProblems(user, groupId, pageable)); - } - @DeleteMapping(value = "/problems/{problemId}") @Operation(summary = "문제 삭제 API") public ResponseEntity deleteProblem(@AuthedUser User user, @PathVariable Long problemId) { diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/exception/InvalidRequestException.java b/src/main/java/com/gamzabat/algohub/feature/problem/exception/InvalidRequestException.java new file mode 100644 index 00000000..4344c820 --- /dev/null +++ b/src/main/java/com/gamzabat/algohub/feature/problem/exception/InvalidRequestException.java @@ -0,0 +1,16 @@ +package com.gamzabat.algohub.feature.problem.exception; + +import org.springframework.http.HttpStatus; + +import lombok.Getter; + +@Getter +public class InvalidRequestException extends RuntimeException { + private final HttpStatus status; + private final String error; + + public InvalidRequestException(HttpStatus status, String error) { + this.status = status; + this.error = error; + } +} \ No newline at end of file diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java b/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java index 62c2d60c..ba9b20de 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java @@ -150,7 +150,7 @@ private void checkProblemStartDate(EditProblemRequest request, Problem problem) } @Transactional(readOnly = true) - public Page getProblems(User user, Long groupId, Boolean unsolvedOnly, ProblemListStatus status, Pageable pageable) { + public Page getProblems(User user, Long groupId, ProblemListStatus status, Boolean unsolvedOnly, Pageable pageable) { Page response; if (status == ProblemListStatus.IN_PROGRESS) { response = getInProgressProblems(user, groupId, unsolvedOnly, pageable); From c083218c2c9f4798908d059822f83bf6dc45654b Mon Sep 17 00:00:00 2001 From: sh0723 Date: Wed, 20 Aug 2025 12:37:56 +0900 Subject: [PATCH 3/8] =?UTF-8?q?InvalidRequestException=20handler=EC=97=90?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../algohub/exception/CustomExceptionHandler.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java b/src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java index 81a842b9..5e04e312 100644 --- a/src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java +++ b/src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java @@ -20,6 +20,7 @@ import com.gamzabat.algohub.feature.notification.exception.CannotFoundNotificationException; import com.gamzabat.algohub.feature.notification.exception.CannotFoundNotificationSettingException; import com.gamzabat.algohub.feature.notification.exception.NotificationValidationException; +import com.gamzabat.algohub.feature.problem.exception.InvalidRequestException; import com.gamzabat.algohub.feature.problem.exception.NotBojLinkException; import com.gamzabat.algohub.feature.problem.exception.SolvedAcApiErrorException; import com.gamzabat.algohub.feature.solution.exception.CannotFoundSolutionException; @@ -231,4 +232,12 @@ protected ResponseEntity handleCannotFoundVerificationCodeExcepti .status(HttpStatus.BAD_REQUEST) .body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null)); } + + @ExceptionHandler(InvalidRequestException.class) + protected ResponseEntity handleInvalidRequestException( + InvalidRequestException e) { + return ResponseEntity + .status(e.getStatus()) + .body(new ErrorResponse(e.getStatus().value(), e.getError(), null)); + } } From a641cf4f463751386c7b9192e4db85ba63ec043d Mon Sep 17 00:00:00 2001 From: sh0723 Date: Wed, 20 Aug 2025 14:09:03 +0900 Subject: [PATCH 4/8] =?UTF-8?q?controller=20test=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../problem/controller/ProblemController.java | 4 ++- .../controller/ProblemControllerTest.java | 31 ++++++++++--------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java b/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java index a413d6b4..02451e27 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java @@ -72,12 +72,14 @@ public ResponseEntity> getProblems(@AuthedUser User use @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { Pageable pageable = PageRequest.of(page, size, Sort.by(PROBLEM_SORT_BY).descending()); - Page response = problemService.getProblems(user, groupId, status, unsolvedOnly, pageable); if (status == ProblemListStatus.IN_PROGRESS) { if (unsolvedOnly == null) { throw new InvalidRequestException(HttpStatus.BAD_REQUEST, "IN_PROGRESS 상태에서는 unsolvedOnly 는 필수입니다."); } } + + Page response = problemService.getProblems(user, groupId, status, unsolvedOnly, pageable); + return ResponseEntity.ok().body(response); } diff --git a/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java b/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java index 59d7bb7c..f2f64d7b 100644 --- a/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java +++ b/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.internal.matchers.Null; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -41,6 +42,8 @@ import com.gamzabat.algohub.feature.problem.dto.CreateProblemRequest; import com.gamzabat.algohub.feature.problem.dto.EditProblemRequest; import com.gamzabat.algohub.feature.problem.dto.GetProblemResponse; +import com.gamzabat.algohub.feature.problem.enums.ProblemListStatus; +import com.gamzabat.algohub.feature.problem.exception.InvalidRequestException; import com.gamzabat.algohub.feature.problem.exception.SolvedAcApiErrorException; import com.gamzabat.algohub.feature.problem.repository.ProblemRepository; import com.gamzabat.algohub.feature.problem.service.ProblemService; @@ -300,38 +303,37 @@ void editProblemDeadlineFailed_6() throws Exception { } @Test - @DisplayName("진행 중인 문제 목록 조회 성공") + @DisplayName("문제 목록 조회 성공") void getProblemList() throws Exception { // given Pageable pageable = PageRequest.of(0, 20, Sort.by("endDate").descending()); Page response = new PageImpl<>(new ArrayList<>()); - when(problemService.getInProgressProblems(any(User.class), anyLong(), eq(false), + when(problemService.getProblems(any(User.class), anyLong(), eq(ProblemListStatus.IN_PROGRESS) ,eq(false), any(Pageable.class))).thenReturn( response); // when, then - mockMvc.perform(get("/api/groups/{groupId}/problems/in-progress", groupId) + mockMvc.perform(get("/api/groups/{groupId}/problems", groupId) .header("Authorization", token) - .param("unsolved-only", String.valueOf(false))) + .param("unsolved-only", String.valueOf(false)) + .param("status", String.valueOf(ProblemListStatus.IN_PROGRESS))) .andExpect(status().isOk()) .andExpect(content().string(objectMapper.writeValueAsString(response))); - verify(problemService, times(1)).getInProgressProblems(user, groupId, false, pageable); + verify(problemService, times(1)).getProblems(user, groupId,ProblemListStatus.IN_PROGRESS,false, pageable); } @Test - @DisplayName("문제 목록 조회 실패 : 권한 없음") + @DisplayName("문제 목록 조회 실패 : 올바르지 않은 요청") void getProblemListFailed_1() throws Exception { // given Pageable pageable = PageRequest.of(0, 20, Sort.by("endDate").descending()); - when( - problemService.getInProgressProblems(any(User.class), anyLong(), eq(false), any(Pageable.class))).thenThrow( - new ProblemValidationException(HttpStatus.FORBIDDEN.value(), "문제를 조회할 권한이 없습니다.")); + // when, then - mockMvc.perform(get("/api/groups/{groupId}/problems/in-progress", groupId) + mockMvc.perform(get("/api/groups/{groupId}/problems", groupId) .header("Authorization", token) - .param("unsolved-only", String.valueOf(false))) - .andExpect(status().isForbidden()) - .andExpect(jsonPath("$.error").value("문제를 조회할 권한이 없습니다.")); - verify(problemService, times(1)).getInProgressProblems(user, groupId, false, pageable); + .param("status", String.valueOf(ProblemListStatus.IN_PROGRESS))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.error").value("IN_PROGRESS 상태에서는 unsolvedOnly 는 필수입니다.")); + verifyNoInteractions(problemService); } @Test @@ -343,6 +345,7 @@ void deleteProblem() throws Exception { mockMvc.perform(delete("/api/problems/{problemId}", problemId) .header("Authorization", token) .param("problemId", String.valueOf(problemId))) + .andExpect(status().isOk()); verify(problemService, times(1)).deleteProblem(user, problemId); } From 6d3140f21c9d173633391efecd395b1016dfffdc Mon Sep 17 00:00:00 2001 From: sh0723 Date: Tue, 26 Aug 2025 12:23:19 +0900 Subject: [PATCH 5/8] =?UTF-8?q?deadlineReached=20API=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../problem/controller/ProblemController.java | 13 ++----- .../problem/enums/ProblemListStatus.java | 1 - .../problem/service/ProblemService.java | 36 ------------------- .../controller/ProblemControllerTest.java | 2 ++ 4 files changed, 5 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java b/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java index 02451e27..eb395add 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java @@ -6,6 +6,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.parameters.P; @@ -69,9 +70,8 @@ public ResponseEntity> getProblems(@AuthedUser User use @PathVariable Long groupId, @RequestParam ProblemListStatus status, @RequestParam(name = "unsolved-only", required = false) Boolean unsolvedOnly, - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") int size) { - Pageable pageable = PageRequest.of(page, size, Sort.by(PROBLEM_SORT_BY).descending()); + @PageableDefault(page = 0, size = 20, sort = "endDate", direction = Sort.Direction.DESC) + Pageable pageable) { if (status == ProblemListStatus.IN_PROGRESS) { if (unsolvedOnly == null) { throw new InvalidRequestException(HttpStatus.BAD_REQUEST, "IN_PROGRESS 상태에서는 unsolvedOnly 는 필수입니다."); @@ -90,13 +90,6 @@ public ResponseEntity getProblem(@AuthedUser User user, @Pat return ResponseEntity.ok().body(response); } - @GetMapping("/groups/{groupId}/problems/deadline-reached") - @Operation(summary = "마감 기한이 내일까지인 문제들 조회 API") - public ResponseEntity> getDeadlineReachedProblemList(@AuthedUser User user, - @PathVariable Long groupId) { - return ResponseEntity.ok().body(problemService.getDeadlineReachedProblemList(user, groupId)); - } - @DeleteMapping(value = "/problems/{problemId}") @Operation(summary = "문제 삭제 API") public ResponseEntity deleteProblem(@AuthedUser User user, @PathVariable Long problemId) { diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java b/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java index b63822a1..f34eb019 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java @@ -3,6 +3,5 @@ public enum ProblemListStatus { IN_PROGRESS, EXPIRED, - DEADLINE_REACHED, QUEUED } diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java b/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java index ba9b20de..43d4a997 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java @@ -159,11 +159,6 @@ public Page getProblems(User user, Long groupId, ProblemList } else { response = getQueuedProblems(user, groupId, pageable); } - /* - else if (status == ProblemListStatus.DEADLINE_REACHED) { - response = getDeadlineReachedProblemList(user,groupId); - } - */ return response; } @@ -232,37 +227,6 @@ public void deleteProblem(User user, Long problemId) { log.info("success to delete problem user_id={} , problem_id = {}", user.getId(), problemId); } - @Transactional(readOnly = true) - public List getDeadlineReachedProblemList(User user, Long groupId) { - StudyGroup group = getGroup(groupId); - if (!groupMemberRepository.existsByUserAndStudyGroup(user, group)) - throw new ProblemValidationException(HttpStatus.FORBIDDEN.value(), "문제를 조회할 권한이 없습니다."); - - List problems = problemRepository.findAllByStudyGroupAndEndDateBetween(group, LocalDate.now(), - LocalDate.now().plusDays(1)); - problems.sort(Comparator.comparing(Problem::getEndDate)); - - return problems.stream().map(problem -> { - Integer correctCount = solutionRepository.countDistinctUsersWithCorrectSolutionsByProblemId(problem.getId(), - BOJResultConstants.CORRECT); - Integer submitMemberCount = solutionRepository.countDistinctUsersByProblem(problem); - Integer groupMemberCount = groupMemberRepository.countMembersByStudyGroup(group); - Integer accuracy = calculateAccuracy(submitMemberCount, correctCount); - - return new GetProblemResponse( - problem.getTitle(), - problem.getId(), - problem.getLink(), - problem.getStartDate(), - problem.getEndDate(), - problem.getLevel(), - solutionRepository.existsByUserAndProblemAndResult(user, problem, BOJResultConstants.CORRECT), - submitMemberCount, - groupMemberCount, - accuracy); - }).toList(); - } - @Transactional(readOnly = true) public Page getQueuedProblems(User user, Long groupId, Pageable pageable) { StudyGroup group = getGroup(groupId); diff --git a/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java b/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java index f2f64d7b..6b05e063 100644 --- a/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java +++ b/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java @@ -314,6 +314,8 @@ void getProblemList() throws Exception { // when, then mockMvc.perform(get("/api/groups/{groupId}/problems", groupId) .header("Authorization", token) + .param("page", "0") + .param("size", "20") .param("unsolved-only", String.valueOf(false)) .param("status", String.valueOf(ProblemListStatus.IN_PROGRESS))) .andExpect(status().isOk()) From e6482c3a0f1740c9c4d394fbabd6edf51d5a5700 Mon Sep 17 00:00:00 2001 From: sh0723 Date: Tue, 26 Aug 2025 12:25:05 +0900 Subject: [PATCH 6/8] =?UTF-8?q?ProblemLisStatus=20=ED=95=98=EB=8B=A8=20?= =?UTF-8?q?=EA=B3=B5=EB=B0=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../algohub/feature/problem/enums/ProblemListStatus.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java b/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java index f34eb019..da4a1859 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/enums/ProblemListStatus.java @@ -4,4 +4,5 @@ public enum ProblemListStatus { IN_PROGRESS, EXPIRED, QUEUED + } From 2028451097cbe7096d4ee93716423daf2f3f54c7 Mon Sep 17 00:00:00 2001 From: sh0723 Date: Sun, 7 Sep 2025 20:18:09 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=EC=BD=94=EB=A6=AC=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/CustomExceptionHandler.java | 8 -------- .../problem/controller/ProblemController.java | 6 ------ .../exception/InvalidRequestException.java | 16 ---------------- .../feature/problem/service/ProblemService.java | 4 +++- .../controller/ProblemControllerTest.java | 1 - 5 files changed, 3 insertions(+), 32 deletions(-) delete mode 100644 src/main/java/com/gamzabat/algohub/feature/problem/exception/InvalidRequestException.java diff --git a/src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java b/src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java index 5e04e312..6df7dbc9 100644 --- a/src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java +++ b/src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java @@ -20,7 +20,6 @@ import com.gamzabat.algohub.feature.notification.exception.CannotFoundNotificationException; import com.gamzabat.algohub.feature.notification.exception.CannotFoundNotificationSettingException; import com.gamzabat.algohub.feature.notification.exception.NotificationValidationException; -import com.gamzabat.algohub.feature.problem.exception.InvalidRequestException; import com.gamzabat.algohub.feature.problem.exception.NotBojLinkException; import com.gamzabat.algohub.feature.problem.exception.SolvedAcApiErrorException; import com.gamzabat.algohub.feature.solution.exception.CannotFoundSolutionException; @@ -233,11 +232,4 @@ protected ResponseEntity handleCannotFoundVerificationCodeExcepti .body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null)); } - @ExceptionHandler(InvalidRequestException.class) - protected ResponseEntity handleInvalidRequestException( - InvalidRequestException e) { - return ResponseEntity - .status(e.getStatus()) - .body(new ErrorResponse(e.getStatus().value(), e.getError(), null)); - } } diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java b/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java index eb395add..4b3f23ed 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java @@ -27,7 +27,6 @@ import com.gamzabat.algohub.feature.problem.dto.EditProblemRequest; import com.gamzabat.algohub.feature.problem.dto.GetProblemResponse; import com.gamzabat.algohub.feature.problem.enums.ProblemListStatus; -import com.gamzabat.algohub.feature.problem.exception.InvalidRequestException; import com.gamzabat.algohub.feature.problem.service.ProblemService; import com.gamzabat.algohub.feature.user.domain.User; @@ -72,11 +71,6 @@ public ResponseEntity> getProblems(@AuthedUser User use @RequestParam(name = "unsolved-only", required = false) Boolean unsolvedOnly, @PageableDefault(page = 0, size = 20, sort = "endDate", direction = Sort.Direction.DESC) Pageable pageable) { - if (status == ProblemListStatus.IN_PROGRESS) { - if (unsolvedOnly == null) { - throw new InvalidRequestException(HttpStatus.BAD_REQUEST, "IN_PROGRESS 상태에서는 unsolvedOnly 는 필수입니다."); - } - } Page response = problemService.getProblems(user, groupId, status, unsolvedOnly, pageable); diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/exception/InvalidRequestException.java b/src/main/java/com/gamzabat/algohub/feature/problem/exception/InvalidRequestException.java deleted file mode 100644 index 4344c820..00000000 --- a/src/main/java/com/gamzabat/algohub/feature/problem/exception/InvalidRequestException.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gamzabat.algohub.feature.problem.exception; - -import org.springframework.http.HttpStatus; - -import lombok.Getter; - -@Getter -public class InvalidRequestException extends RuntimeException { - private final HttpStatus status; - private final String error; - - public InvalidRequestException(HttpStatus status, String error) { - this.status = status; - this.error = error; - } -} \ No newline at end of file diff --git a/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java b/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java index 43d4a997..fcb56c99 100644 --- a/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java +++ b/src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java @@ -3,7 +3,6 @@ import static com.gamzabat.algohub.constants.ApiConstants.*; import java.time.LocalDate; -import java.util.Comparator; import java.util.List; import org.springframework.data.domain.Page; @@ -153,6 +152,9 @@ private void checkProblemStartDate(EditProblemRequest request, Problem problem) public Page getProblems(User user, Long groupId, ProblemListStatus status, Boolean unsolvedOnly, Pageable pageable) { Page response; if (status == ProblemListStatus.IN_PROGRESS) { + if (unsolvedOnly == null) { + unsolvedOnly = false; + } response = getInProgressProblems(user, groupId, unsolvedOnly, pageable); } else if (status == ProblemListStatus.EXPIRED) { response = getExpiredProblems(user, groupId, pageable); diff --git a/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java b/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java index 6b05e063..afca1f1f 100644 --- a/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java +++ b/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java @@ -43,7 +43,6 @@ import com.gamzabat.algohub.feature.problem.dto.EditProblemRequest; import com.gamzabat.algohub.feature.problem.dto.GetProblemResponse; import com.gamzabat.algohub.feature.problem.enums.ProblemListStatus; -import com.gamzabat.algohub.feature.problem.exception.InvalidRequestException; import com.gamzabat.algohub.feature.problem.exception.SolvedAcApiErrorException; import com.gamzabat.algohub.feature.problem.repository.ProblemRepository; import com.gamzabat.algohub.feature.problem.service.ProblemService; From 74628fc2831fedb7e5d7050040862271d8a39a1a Mon Sep 17 00:00:00 2001 From: sh0723 Date: Sun, 7 Sep 2025 20:23:12 +0900 Subject: [PATCH 8/8] =?UTF-8?q?test=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../problem/controller/ProblemControllerTest.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java b/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java index afca1f1f..391856d0 100644 --- a/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java +++ b/src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java @@ -322,21 +322,6 @@ void getProblemList() throws Exception { verify(problemService, times(1)).getProblems(user, groupId,ProblemListStatus.IN_PROGRESS,false, pageable); } - @Test - @DisplayName("문제 목록 조회 실패 : 올바르지 않은 요청") - void getProblemListFailed_1() throws Exception { - // given - Pageable pageable = PageRequest.of(0, 20, Sort.by("endDate").descending()); - - // when, then - mockMvc.perform(get("/api/groups/{groupId}/problems", groupId) - .header("Authorization", token) - .param("status", String.valueOf(ProblemListStatus.IN_PROGRESS))) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.error").value("IN_PROGRESS 상태에서는 unsolvedOnly 는 필수입니다.")); - verifyNoInteractions(problemService); - } - @Test @DisplayName("문제 삭제 성공") void deleteProblem() throws Exception {