Skip to content

Commit e9b4595

Browse files
sh0723hwangjokim
authored andcommitted
refactor : getProblems (#398)
1 parent 1c46447 commit e9b4595

File tree

5 files changed

+51
-90
lines changed

5 files changed

+51
-90
lines changed

src/main/java/com/gamzabat/algohub/exception/CustomExceptionHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ protected ResponseEntity<ErrorResponse> handleCannotFoundVerificationCodeExcepti
233233
.status(HttpStatus.BAD_REQUEST)
234234
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
235235
}
236-
236+
237237
@ExceptionHandler(CannotFoundEdgeCaseException.class)
238238
protected ResponseEntity<ErrorResponse> handleCannotFoundEdgeCaseException(
239239
CannotFoundEdgeCaseException e) {
@@ -249,4 +249,5 @@ protected ResponseEntity<ErrorResponse> handleNotAuthorizedUserException(
249249
.status(e.getHttpStatus())
250250
.body(new ErrorResponse(e.getHttpStatus().value(), e.getError(), null));
251251
}
252+
252253
}

src/main/java/com/gamzabat/algohub/feature/problem/controller/ProblemController.java

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
import org.springframework.data.domain.PageRequest;
77
import org.springframework.data.domain.Pageable;
88
import org.springframework.data.domain.Sort;
9+
import org.springframework.data.web.PageableDefault;
10+
import org.springframework.http.HttpStatus;
911
import org.springframework.http.ResponseEntity;
12+
import org.springframework.security.core.parameters.P;
1013
import org.springframework.validation.Errors;
1114
import org.springframework.web.bind.annotation.DeleteMapping;
1215
import org.springframework.web.bind.annotation.GetMapping;
@@ -23,6 +26,7 @@
2326
import com.gamzabat.algohub.feature.problem.dto.CreateProblemRequest;
2427
import com.gamzabat.algohub.feature.problem.dto.EditProblemRequest;
2528
import com.gamzabat.algohub.feature.problem.dto.GetProblemResponse;
29+
import com.gamzabat.algohub.feature.problem.enums.ProblemListStatus;
2630
import com.gamzabat.algohub.feature.problem.service.ProblemService;
2731
import com.gamzabat.algohub.feature.user.domain.User;
2832

@@ -59,26 +63,17 @@ public ResponseEntity<Void> editProblemDeadline(@AuthedUser User user,
5963
return ResponseEntity.ok().build();
6064
}
6165

62-
@GetMapping(value = "/groups/{groupId}/problems/in-progress")
63-
@Operation(summary = "진행 중인 문제 목록 조회 API", description = "특정 그룹에 대한 문제를 모두 조회하는 API")
64-
public ResponseEntity<Page<GetProblemResponse>> getInProgressProblemList(@AuthedUser User user,
66+
@GetMapping(value = "/groups/{groupId}/problems")
67+
@Operation(summary = "문제 목록 조회 API", description = "특정 그룹에 대한 문제를 부분 조회하는 API")
68+
public ResponseEntity<Page<GetProblemResponse>> getProblems(@AuthedUser User user,
6569
@PathVariable Long groupId,
66-
@RequestParam(name = "unsolved-only") Boolean unsolvedOnly,
67-
@RequestParam(defaultValue = "0") int page,
68-
@RequestParam(defaultValue = "20") int size) {
69-
Pageable pageable = PageRequest.of(page, size, Sort.by(PROBLEM_SORT_BY).descending());
70-
Page<GetProblemResponse> response = problemService.getInProgressProblems(user, groupId, unsolvedOnly, pageable);
71-
return ResponseEntity.ok().body(response);
72-
}
70+
@RequestParam ProblemListStatus status,
71+
@RequestParam(name = "unsolved-only", required = false) Boolean unsolvedOnly,
72+
@PageableDefault(page = 0, size = 20, sort = "endDate", direction = Sort.Direction.DESC)
73+
Pageable pageable) {
74+
75+
Page<GetProblemResponse> response = problemService.getProblems(user, groupId, status, unsolvedOnly, pageable);
7376

74-
@GetMapping(value = "/groups/{groupId}/problems/expired")
75-
@Operation(summary = "마감 된 문제 목록 조회 API", description = "특정 그룹에 대한 문제를 모두 조회하는 API")
76-
public ResponseEntity<Page<GetProblemResponse>> getExpiredProblemList(@AuthedUser User user,
77-
@PathVariable Long groupId,
78-
@RequestParam(defaultValue = "0") int page,
79-
@RequestParam(defaultValue = "20") int size) {
80-
Pageable pageable = PageRequest.of(page, size, Sort.by(PROBLEM_SORT_BY).descending());
81-
Page<GetProblemResponse> response = problemService.getExpiredProblems(user, groupId, pageable);
8277
return ResponseEntity.ok().body(response);
8378
}
8479

@@ -89,23 +84,6 @@ public ResponseEntity<GetProblemResponse> getProblem(@AuthedUser User user, @Pat
8984
return ResponseEntity.ok().body(response);
9085
}
9186

92-
@GetMapping("/groups/{groupId}/problems/deadline-reached")
93-
@Operation(summary = "마감 기한이 내일까지인 문제들 조회 API")
94-
public ResponseEntity<List<GetProblemResponse>> getDeadlineReachedProblemList(@AuthedUser User user,
95-
@PathVariable Long groupId) {
96-
return ResponseEntity.ok().body(problemService.getDeadlineReachedProblemList(user, groupId));
97-
}
98-
99-
@GetMapping("/groups/{groupId}/problems/queued")
100-
@Operation(summary = "시작 예정인 문제들 조회 API")
101-
public ResponseEntity<Page<GetProblemResponse>> getQueuedProblemList(@AuthedUser User user,
102-
@PathVariable Long groupId,
103-
@RequestParam(defaultValue = "0") int page,
104-
@RequestParam(defaultValue = "20") int size) {
105-
Pageable pageable = PageRequest.of(page, size, Sort.by(PROBLEM_SORT_BY).descending());
106-
return ResponseEntity.ok().body(problemService.getQueuedProblems(user, groupId, pageable));
107-
}
108-
10987
@DeleteMapping(value = "/problems/{problemId}")
11088
@Operation(summary = "문제 삭제 API")
11189
public ResponseEntity<Void> deleteProblem(@AuthedUser User user, @PathVariable Long problemId) {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.gamzabat.algohub.feature.problem.enums;
2+
3+
public enum ProblemListStatus {
4+
IN_PROGRESS,
5+
EXPIRED,
6+
QUEUED
7+
8+
}

src/main/java/com/gamzabat/algohub/feature/problem/service/ProblemService.java

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import static com.gamzabat.algohub.constants.ApiConstants.*;
44

55
import java.time.LocalDate;
6-
import java.util.Comparator;
76
import java.util.List;
87

98
import org.springframework.data.domain.Page;
@@ -37,6 +36,7 @@
3736
import com.gamzabat.algohub.feature.problem.dto.CreateProblemRequest;
3837
import com.gamzabat.algohub.feature.problem.dto.EditProblemRequest;
3938
import com.gamzabat.algohub.feature.problem.dto.GetProblemResponse;
39+
import com.gamzabat.algohub.feature.problem.enums.ProblemListStatus;
4040
import com.gamzabat.algohub.feature.problem.exception.NotBojLinkException;
4141
import com.gamzabat.algohub.feature.problem.exception.SolvedAcApiErrorException;
4242
import com.gamzabat.algohub.feature.problem.repository.ProblemRepository;
@@ -151,6 +151,22 @@ private void checkProblemStartDate(EditProblemRequest request, Problem problem)
151151
"문제 시작 날짜는 마감 날짜 이후로 수정할 수 없습니다.");
152152
}
153153

154+
@Transactional(readOnly = true)
155+
public Page<GetProblemResponse> getProblems(User user, Long groupId, ProblemListStatus status, Boolean unsolvedOnly, Pageable pageable) {
156+
Page<GetProblemResponse> response;
157+
if (status == ProblemListStatus.IN_PROGRESS) {
158+
if (unsolvedOnly == null) {
159+
unsolvedOnly = false;
160+
}
161+
response = getInProgressProblems(user, groupId, unsolvedOnly, pageable);
162+
} else if (status == ProblemListStatus.EXPIRED) {
163+
response = getExpiredProblems(user, groupId, pageable);
164+
} else {
165+
response = getQueuedProblems(user, groupId, pageable);
166+
}
167+
return response;
168+
}
169+
154170
@Transactional(readOnly = true)
155171
public Page<GetProblemResponse> getInProgressProblems(User user, Long groupId, Boolean unsolvedOnly,
156172
Pageable pageable) {
@@ -216,37 +232,6 @@ public void deleteProblem(User user, Long problemId) {
216232
log.info("success to delete problem user_id={} , problem_id = {}", user.getId(), problemId);
217233
}
218234

219-
@Transactional(readOnly = true)
220-
public List<GetProblemResponse> getDeadlineReachedProblemList(User user, Long groupId) {
221-
StudyGroup group = getGroup(groupId);
222-
if (!groupMemberRepository.existsByUserAndStudyGroup(user, group))
223-
throw new ProblemValidationException(HttpStatus.FORBIDDEN.value(), "문제를 조회할 권한이 없습니다.");
224-
225-
List<Problem> problems = problemRepository.findAllByStudyGroupAndEndDateBetween(group, LocalDate.now(),
226-
LocalDate.now().plusDays(1));
227-
problems.sort(Comparator.comparing(Problem::getEndDate));
228-
229-
return problems.stream().map(problem -> {
230-
Integer correctCount = solutionRepository.countDistinctUsersWithCorrectSolutionsByProblemId(problem.getId(),
231-
BOJResultConstants.CORRECT);
232-
Integer submitMemberCount = solutionRepository.countDistinctUsersByProblem(problem);
233-
Integer groupMemberCount = groupMemberRepository.countMembersByStudyGroup(group);
234-
Integer accuracy = calculateAccuracy(submitMemberCount, correctCount);
235-
236-
return new GetProblemResponse(
237-
problem.getTitle(),
238-
problem.getId(),
239-
problem.getLink(),
240-
problem.getStartDate(),
241-
problem.getEndDate(),
242-
problem.getLevel(),
243-
solutionRepository.existsByUserAndProblemAndResult(user, problem, BOJResultConstants.CORRECT),
244-
submitMemberCount,
245-
groupMemberCount,
246-
accuracy);
247-
}).toList();
248-
}
249-
250235
@Transactional(readOnly = true)
251236
public Page<GetProblemResponse> getQueuedProblems(User user, Long groupId, Pageable pageable) {
252237
StudyGroup group = getGroup(groupId);

src/test/java/com/gamzabat/algohub/feature/problem/controller/ProblemControllerTest.java

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.junit.jupiter.api.Test;
1818
import org.junit.jupiter.params.ParameterizedTest;
1919
import org.junit.jupiter.params.provider.CsvSource;
20+
import org.mockito.internal.matchers.Null;
2021
import org.springframework.beans.factory.annotation.Autowired;
2122
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
2223
import org.springframework.boot.test.mock.mockito.MockBean;
@@ -41,6 +42,7 @@
4142
import com.gamzabat.algohub.feature.problem.dto.CreateProblemRequest;
4243
import com.gamzabat.algohub.feature.problem.dto.EditProblemRequest;
4344
import com.gamzabat.algohub.feature.problem.dto.GetProblemResponse;
45+
import com.gamzabat.algohub.feature.problem.enums.ProblemListStatus;
4446
import com.gamzabat.algohub.feature.problem.exception.SolvedAcApiErrorException;
4547
import com.gamzabat.algohub.feature.problem.repository.ProblemRepository;
4648
import com.gamzabat.algohub.feature.problem.service.ProblemService;
@@ -300,38 +302,24 @@ void editProblemDeadlineFailed_6() throws Exception {
300302
}
301303

302304
@Test
303-
@DisplayName("진행 중인 문제 목록 조회 성공")
305+
@DisplayName("문제 목록 조회 성공")
304306
void getProblemList() throws Exception {
305307
// given
306308
Pageable pageable = PageRequest.of(0, 20, Sort.by("endDate").descending());
307309
Page<GetProblemResponse> response = new PageImpl<>(new ArrayList<>());
308-
when(problemService.getInProgressProblems(any(User.class), anyLong(), eq(false),
310+
when(problemService.getProblems(any(User.class), anyLong(), eq(ProblemListStatus.IN_PROGRESS) ,eq(false),
309311
any(Pageable.class))).thenReturn(
310312
response);
311313
// when, then
312-
mockMvc.perform(get("/api/groups/{groupId}/problems/in-progress", groupId)
314+
mockMvc.perform(get("/api/groups/{groupId}/problems", groupId)
313315
.header("Authorization", token)
314-
.param("unsolved-only", String.valueOf(false)))
316+
.param("page", "0")
317+
.param("size", "20")
318+
.param("unsolved-only", String.valueOf(false))
319+
.param("status", String.valueOf(ProblemListStatus.IN_PROGRESS)))
315320
.andExpect(status().isOk())
316321
.andExpect(content().string(objectMapper.writeValueAsString(response)));
317-
verify(problemService, times(1)).getInProgressProblems(user, groupId, false, pageable);
318-
}
319-
320-
@Test
321-
@DisplayName("문제 목록 조회 실패 : 권한 없음")
322-
void getProblemListFailed_1() throws Exception {
323-
// given
324-
Pageable pageable = PageRequest.of(0, 20, Sort.by("endDate").descending());
325-
when(
326-
problemService.getInProgressProblems(any(User.class), anyLong(), eq(false), any(Pageable.class))).thenThrow(
327-
new ProblemValidationException(HttpStatus.FORBIDDEN.value(), "문제를 조회할 권한이 없습니다."));
328-
// when, then
329-
mockMvc.perform(get("/api/groups/{groupId}/problems/in-progress", groupId)
330-
.header("Authorization", token)
331-
.param("unsolved-only", String.valueOf(false)))
332-
.andExpect(status().isForbidden())
333-
.andExpect(jsonPath("$.error").value("문제를 조회할 권한이 없습니다."));
334-
verify(problemService, times(1)).getInProgressProblems(user, groupId, false, pageable);
322+
verify(problemService, times(1)).getProblems(user, groupId,ProblemListStatus.IN_PROGRESS,false, pageable);
335323
}
336324

337325
@Test
@@ -343,6 +331,7 @@ void deleteProblem() throws Exception {
343331
mockMvc.perform(delete("/api/problems/{problemId}", problemId)
344332
.header("Authorization", token)
345333
.param("problemId", String.valueOf(problemId)))
334+
346335
.andExpect(status().isOk());
347336
verify(problemService, times(1)).deleteProblem(user, problemId);
348337
}

0 commit comments

Comments
 (0)