From f603bfb40d5d435d5571ef3f9d17b9584398bf51 Mon Sep 17 00:00:00 2001 From: HongGit Date: Thu, 6 Feb 2025 16:00:15 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[chore/#33]=20local=20env=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 227c6ad..7c43360 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ build/ !**/src/main/**/build/ !**/src/test/**/build/ .env +local.env ### STS ### .apt_generated From d520a95d12ebc991e8e7b7e476c3df6df0578a5d Mon Sep 17 00:00:00 2001 From: HongGit Date: Thu, 6 Feb 2025 16:01:15 +0900 Subject: [PATCH 2/9] =?UTF-8?q?[feat/#33]=20=EB=AC=B8=ED=95=AD=EC=84=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ConceptTagRepository.java | 9 ++ .../controller/ProblemSetController.java | 18 ++- .../dto/response/ProblemSetGetResponse.java | 24 +++ .../dto/response/ProblemSummaryResponse.java | 29 ++++ .../service/ProblemSetGetService.java | 45 ++++++ .../problemset/ProblemSetServiceTest.java | 1 - .../service/ProblemSetGetServiceTest.java | 151 ++++++++++++++++++ 7 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java create mode 100644 src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSummaryResponse.java create mode 100644 src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetService.java create mode 100644 src/test/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetServiceTest.java diff --git a/src/main/java/com/moplus/moplus_server/domain/concept/repository/ConceptTagRepository.java b/src/main/java/com/moplus/moplus_server/domain/concept/repository/ConceptTagRepository.java index 682a2f3..4f2eafc 100644 --- a/src/main/java/com/moplus/moplus_server/domain/concept/repository/ConceptTagRepository.java +++ b/src/main/java/com/moplus/moplus_server/domain/concept/repository/ConceptTagRepository.java @@ -18,4 +18,13 @@ default void existsByIdElseThrow(Set ids) { throw new NotFoundException(ErrorCode.CONCEPT_TAG_NOT_FOUND_IN_LIST); } } + + + default List findByIdInElseThrow(Set ids) { + List conceptTags = findAllById(ids); + if (conceptTags.size() != ids.size()) { + throw new NotFoundException(ErrorCode.CONCEPT_TAG_NOT_FOUND_IN_LIST); + } + return conceptTags; + } } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetController.java b/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetController.java index d101b45..1abe73f 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetController.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetController.java @@ -4,13 +4,16 @@ import com.moplus.moplus_server.domain.problemset.dto.request.ProblemReorderRequest; import com.moplus.moplus_server.domain.problemset.dto.request.ProblemSetPostRequest; import com.moplus.moplus_server.domain.problemset.dto.request.ProblemSetUpdateRequest; +import com.moplus.moplus_server.domain.problemset.dto.response.ProblemSetGetResponse; import com.moplus.moplus_server.domain.problemset.service.ProblemSetDeleteService; +import com.moplus.moplus_server.domain.problemset.service.ProblemSetGetService; import com.moplus.moplus_server.domain.problemset.service.ProblemSetSaveService; import com.moplus.moplus_server.domain.problemset.service.ProblemSetUpdateService; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; @@ -26,6 +29,7 @@ public class ProblemSetController { private final ProblemSetSaveService problemSetSaveService; private final ProblemSetUpdateService problemSetUpdateService; private final ProblemSetDeleteService problemSetDeleteService; + private final ProblemSetGetService problemSetGetService; @PostMapping("") @Operation(summary = "문항세트 생성", description = "문항세트를 생성합니다. 문항은 요청 순서대로 저장합니다.") @@ -65,7 +69,17 @@ public ResponseEntity deleteProblemSet( @PutMapping("/{problemSetId}/confirm") @Operation(summary = "문항세트 컨펌 토글", description = "문항세트의 컨펌 상태를 토글합니다.") - public ResponseEntity toggleConfirmProblemSet(@PathVariable Long problemSetId) { + public ResponseEntity toggleConfirmProblemSet( + @PathVariable Long problemSetId + ) { return ResponseEntity.ok(problemSetUpdateService.toggleConfirmProblemSet(problemSetId)); } -} + + @GetMapping("/{problemSetId}") + @Operation(summary = "문항세트 개별 조회", description = "문항세트를 조회합니다.") + public ResponseEntity getProblemSet( + @PathVariable Long problemSetId + ) { + return ResponseEntity.ok(problemSetGetService.getProblemSet(problemSetId)); + } +} \ No newline at end of file diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java new file mode 100644 index 0000000..df68bc2 --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java @@ -0,0 +1,24 @@ +package com.moplus.moplus_server.domain.problemset.dto.response; + +import com.moplus.moplus_server.domain.problemset.domain.ProblemSet; +import com.moplus.moplus_server.domain.problemset.domain.ProblemSetConfirmStatus; +import java.util.List; +import lombok.Builder; + +@Builder +public record ProblemSetGetResponse( + Long id, + String name, + ProblemSetConfirmStatus confirmStatus, + List problemSummaries +) { + public static ProblemSetGetResponse of(ProblemSet problemSet, List problemSummaries) { + + return ProblemSetGetResponse.builder() + .id(problemSet.getId()) + .name(problemSet.getName()) + .confirmStatus(problemSet.getConfirmStatus()) + .problemSummaries(problemSummaries) + .build(); + } +} diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSummaryResponse.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSummaryResponse.java new file mode 100644 index 0000000..78251b2 --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSummaryResponse.java @@ -0,0 +1,29 @@ +package com.moplus.moplus_server.domain.problemset.dto.response; + +import com.moplus.moplus_server.domain.problem.domain.problem.Problem; +import java.util.List; +import lombok.Builder; + +@Builder +public record ProblemSummaryResponse( + String problemId, + int number, + String practiceTestName, + String comment, + String mainProblemImageUrl, + List tagNames, + int sequence +) { + public static ProblemSummaryResponse of(Problem problem, int sequence, String practiceTestName, List tagNames) { + + return ProblemSummaryResponse.builder() + .problemId(problem.getId().toString()) + .number(problem.getNumber()) + .comment(problem.getComment()) + .mainProblemImageUrl(problem.getMainProblemImageUrl()) + .sequence(sequence) + .practiceTestName(practiceTestName) + .tagNames(tagNames) + .build(); + } +} diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetService.java b/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetService.java new file mode 100644 index 0000000..d704b7b --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetService.java @@ -0,0 +1,45 @@ +package com.moplus.moplus_server.domain.problemset.service; + +import com.moplus.moplus_server.domain.concept.domain.ConceptTag; +import com.moplus.moplus_server.domain.concept.repository.ConceptTagRepository; +import com.moplus.moplus_server.domain.problem.domain.practiceTest.PracticeTestTag; +import com.moplus.moplus_server.domain.problem.domain.problem.Problem; +import com.moplus.moplus_server.domain.problem.repository.PracticeTestTagRepository; +import com.moplus.moplus_server.domain.problem.repository.ProblemRepository; +import com.moplus.moplus_server.domain.problemset.domain.ProblemSet; +import com.moplus.moplus_server.domain.problemset.dto.response.ProblemSetGetResponse; +import com.moplus.moplus_server.domain.problemset.dto.response.ProblemSummaryResponse; +import com.moplus.moplus_server.domain.problemset.repository.ProblemSetRepository; +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class ProblemSetGetService { + + private final ProblemSetRepository problemSetRepository; + private final ProblemRepository problemRepository; + private final PracticeTestTagRepository practiceTestTagRepository; + private final ConceptTagRepository conceptTagRepository; + + @Transactional(readOnly = true) + public ProblemSetGetResponse getProblemSet(Long problemSetId) { + + ProblemSet problemSet = problemSetRepository.findByIdElseThrow(problemSetId); + + List problemSummaries = new ArrayList<>(); + for (int i = 0; i < problemSet.getProblemIds().size(); i++) { + Problem problem = problemRepository.findByIdElseThrow(problemSet.getProblemIds().get(i)); + PracticeTestTag practiceTestTag = practiceTestTagRepository.findByIdElseThrow(problem.getPracticeTestId()); + List tagNames = conceptTagRepository.findByIdInElseThrow(problem.getConceptTagIds()) + .stream() + .map(ConceptTag::getName) + .toList(); + problemSummaries.add(ProblemSummaryResponse.of(problem, i, practiceTestTag.getName(), tagNames)); + } + return ProblemSetGetResponse.of(problemSet, problemSummaries); + } +} diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java index e7c95ca..83c9388 100644 --- a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java @@ -18,7 +18,6 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.Rollback; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.jdbc.Sql; import org.springframework.transaction.annotation.Transactional; diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetServiceTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetServiceTest.java new file mode 100644 index 0000000..3bca81f --- /dev/null +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetServiceTest.java @@ -0,0 +1,151 @@ +package com.moplus.moplus_server.domain.problemset.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import com.moplus.moplus_server.domain.problem.domain.problem.Problem; +import com.moplus.moplus_server.domain.problem.domain.problem.ProblemId; +import com.moplus.moplus_server.domain.problem.dto.request.ProblemPostRequest; +import com.moplus.moplus_server.domain.problem.repository.PracticeTestTagRepository; +import com.moplus.moplus_server.domain.problem.repository.ProblemRepository; +import com.moplus.moplus_server.domain.problemset.domain.ProblemSet; +import com.moplus.moplus_server.domain.problemset.dto.response.ProblemSetGetResponse; +import com.moplus.moplus_server.domain.problemset.repository.ProblemSetRepository; +import com.moplus.moplus_server.global.error.exception.NotFoundException; +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +@ActiveProfiles("h2test") +@Sql({"/practice-test-tag.sql", "/concept-tag.sql"}) +@SpringBootTest +public class ProblemSetGetServiceTest { + + @Autowired + private ProblemSetGetService problemSetGetService; + + @Autowired + private ProblemSetRepository problemSetRepository; + + @Autowired + private ProblemRepository problemRepository; + + @Autowired + private PracticeTestTagRepository practiceTestTagRepository; + + private ProblemSet savedProblemSet; + private Problem savedProblem; + + @BeforeEach + void setUp() { + // 문제 생성 요청 데이터 준비 + ProblemPostRequest problemPostRequest = new ProblemPostRequest( + Set.of(1L, 2L), + 1L, + 1, + "1", + "문제 설명", + "mainProblem.png", + "mainAnalysis.png", + "readingTip.png", + "seniorTip.png", + "prescription.png", + List.of() + ); + + // 문제 저장 + ProblemId createdProblemId = problemRepository.save( + new Problem( + new ProblemId("24052001001"), + practiceTestTagRepository.findByIdElseThrow(1L), + 1, + "1", + "문제 설명", + "mainProblem.png", + "mainAnalysis.png", + "readingTip.png", + "seniorTip.png", + "prescription.png", + Set.of(1L, 2L) + ) + ).getId(); + + savedProblem = problemRepository.findByIdElseThrow(createdProblemId); + + // 문항세트 저장 + savedProblemSet = problemSetRepository.save( + new ProblemSet("테스트 문항세트", List.of(savedProblem.getId())) + ); + } + + @Test + void 문항세트_조회_성공_테스트() { + // when + ProblemSetGetResponse response = problemSetGetService.getProblemSet(savedProblemSet.getId()); + + // then + assertThat(response).isNotNull(); + assertThat(response.name()).isEqualTo("테스트 문항세트"); + assertThat(response.problemSummaries()).hasSize(1); + assertThat(response.problemSummaries().get(0).problemId()).isEqualTo(savedProblem.getId().toString()); + assertThat(response.problemSummaries().get(0).practiceTestName()).isEqualTo("2025년 5월 고2 모의고사"); + assertThat(response.problemSummaries().get(0).tagNames()).contains("미분 개념", "적분 개념"); + } + + @Test + void 존재하지_않는_문항세트_조회_실패_테스트() { + // when & then + assertThatThrownBy(() -> problemSetGetService.getProblemSet(999L)) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("해당 문항세트를 찾을 수 없습니다"); + } + + @Test + void 문항세트_조회_성공_테스트_여러개() { + // given: 여러 개의 문제를 저장 + Problem savedProblem2 = problemRepository.save( + new Problem( + new ProblemId("24052001002"), + practiceTestTagRepository.findByIdElseThrow(1L), + 2, + "2", + "문제 설명2", + "mainProblem2.png", + "mainAnalysis2.png", + "readingTip2.png", + "seniorTip2.png", + "prescription2.png", + Set.of(3L, 4L) + ) + ); + + ProblemSet multipleProblemSet = problemSetRepository.save( + new ProblemSet("여러 문항 테스트 문항세트", List.of(savedProblem.getId(), savedProblem2.getId())) + ); + + // when + ProblemSetGetResponse response = problemSetGetService.getProblemSet(multipleProblemSet.getId()); + + // then + assertThat(response).isNotNull(); + assertThat(response.name()).isEqualTo("여러 문항 테스트 문항세트"); + assertThat(response.problemSummaries()).hasSize(2); + + // 첫 번째 문제 검증 + assertThat(response.problemSummaries().get(0).problemId()).isEqualTo(savedProblem.getId().toString()); + assertThat(response.problemSummaries().get(0).practiceTestName()).isEqualTo("2025년 5월 고2 모의고사"); + assertThat(response.problemSummaries().get(0).tagNames()).contains("미분 개념", "적분 개념"); + + // 두 번째 문제 검증 + assertThat(response.problemSummaries().get(1).problemId()).isEqualTo(savedProblem2.getId().toString()); + assertThat(response.problemSummaries().get(1).practiceTestName()).isEqualTo("2025년 5월 고2 모의고사"); + assertThat(response.problemSummaries().get(1).tagNames()).contains("삼각함수 개념", "행렬 개념"); + } +} \ No newline at end of file From ba49c981c4535f25cd71d45dc476590ac8790466 Mon Sep 17 00:00:00 2001 From: HongGit Date: Thu, 6 Feb 2025 18:40:34 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[fix/#33]=20=EB=AC=B8=ED=95=AD=EC=84=B8?= =?UTF-8?q?=ED=8A=B8=20title=EB=A1=9C=20=ED=95=84=EB=93=9C=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../problemset/controller/ProblemSetSearchController.java | 2 ++ .../domain/problemset/domain/ProblemSet.java | 8 ++++---- .../problemset/dto/request/ProblemSetPostRequest.java | 4 ++-- .../problemset/dto/request/ProblemSetUpdateRequest.java | 2 +- .../problemset/dto/response/ProblemSetGetResponse.java | 4 ++-- .../problemset/service/ProblemSetUpdateService.java | 4 +--- 6 files changed, 12 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetSearchController.java diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetSearchController.java b/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetSearchController.java new file mode 100644 index 0000000..7f1b865 --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetSearchController.java @@ -0,0 +1,2 @@ +package com.moplus.moplus_server.domain.problemset.controller;public class ProblemSetSearchController { +} diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java b/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java index 4b2e7d9..775ba79 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java @@ -33,7 +33,7 @@ public class ProblemSet extends BaseEntity { @Column(name = "problem_set_id") Long id; - private String name; + private String title; private boolean isDeleted; @Enumerated(EnumType.STRING) @@ -46,8 +46,8 @@ public class ProblemSet extends BaseEntity { private List problemIds = new ArrayList<>(); @Builder - public ProblemSet(String name, List problemIds) { - this.name = name; + public ProblemSet(String title, List problemIds) { + this.title = title; this.isDeleted = false; this.confirmStatus = ProblemSetConfirmStatus.NOT_CONFIRMED; this.problemIds = problemIds; @@ -74,7 +74,7 @@ public void toggleConfirm(List problems) { } public void updateProblemSet(String name, List newProblems) { - this.name = name; + this.title = title; this.problemIds = newProblems; } } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java index 0401915..eb50f4d 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java @@ -5,12 +5,12 @@ import java.util.List; public record ProblemSetPostRequest( - String problemSetName, + String problemSetTitle, List problems ) { public ProblemSet toEntity(List problemIdList) { return ProblemSet.builder() - .name(this.problemSetName) + .title(this.problemSetTitle) .problemIds(problemIdList) .build(); } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetUpdateRequest.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetUpdateRequest.java index a0e4745..6752f0e 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetUpdateRequest.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetUpdateRequest.java @@ -3,7 +3,7 @@ import java.util.List; public record ProblemSetUpdateRequest( - String problemSetName, + String problemSetTitle, List problems ) { } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java index df68bc2..c6fa190 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java @@ -8,7 +8,7 @@ @Builder public record ProblemSetGetResponse( Long id, - String name, + String title, ProblemSetConfirmStatus confirmStatus, List problemSummaries ) { @@ -16,7 +16,7 @@ public static ProblemSetGetResponse of(ProblemSet problemSet, List Date: Fri, 7 Feb 2025 12:23:22 +0900 Subject: [PATCH 4/9] =?UTF-8?q?[feat/#33]=20=EB=AC=B8=ED=95=AD=EC=84=B8?= =?UTF-8?q?=ED=8A=B8=20=EA=B2=80=EC=83=89=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProblemSetSearchController.java | 35 +++++- .../response/ProblemSetSearchGetResponse.java | 18 +++ .../response/ProblemThumbnailResponse.java | 17 +++ .../ProblemSetSearchRepositoryCustom.java | 78 ++++++++++++ .../problemset/ProblemSetServiceTest.java | 6 +- .../ProblemSetSearchRepositoryCustomTest.java | 117 ++++++++++++++++++ .../service/ProblemSetGetServiceTest.java | 4 +- src/test/resources/insert-problem-set.sql | 11 ++ src/test/resources/insert-problem.sql | 14 +-- ...ert-problemset.sql => insert-problem2.sql} | 0 10 files changed, 287 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetSearchGetResponse.java create mode 100644 src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemThumbnailResponse.java create mode 100644 src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java create mode 100644 src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java create mode 100644 src/test/resources/insert-problem-set.sql rename src/test/resources/{insert-problemset.sql => insert-problem2.sql} (100%) diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetSearchController.java b/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetSearchController.java index 7f1b865..405a66f 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetSearchController.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetSearchController.java @@ -1,2 +1,35 @@ -package com.moplus.moplus_server.domain.problemset.controller;public class ProblemSetSearchController { +package com.moplus.moplus_server.domain.problemset.controller; + + +import com.moplus.moplus_server.domain.problemset.dto.response.ProblemSetSearchGetResponse; +import com.moplus.moplus_server.domain.problemset.repository.ProblemSetSearchRepositoryCustom; +import io.swagger.v3.oas.annotations.Operation; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v1/problemSet") +@RequiredArgsConstructor +public class ProblemSetSearchController { + + private final ProblemSetSearchRepositoryCustom problemSetSearchRepository; + + @GetMapping("/search") + @Operation( + summary = "문항세트 검색", + description = "문항세트 타이틀, 문항세트 내 포함된 개념태그, 문항세트 내 포함된 문항 타이틀로 검색합니다." + ) + public ResponseEntity> search( + @RequestParam(value = "problemSetTitle", required = false) String problemSetTitle, + @RequestParam(value = "problemTitle", required = false) String problemTitle, + @RequestParam(value = "conceptTagNames", required = false) List conceptTagNames + ) { + List problemSets = problemSetSearchRepository.search(problemSetTitle, problemTitle, conceptTagNames); + return ResponseEntity.ok(problemSets); + } } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetSearchGetResponse.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetSearchGetResponse.java new file mode 100644 index 0000000..392783c --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetSearchGetResponse.java @@ -0,0 +1,18 @@ +package com.moplus.moplus_server.domain.problemset.dto.response; + +import java.util.List; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class ProblemSetSearchGetResponse { + private String problemSetTitle; + private List problemThumbnailResponses; + + public ProblemSetSearchGetResponse(String problemSetTitle, + List problemThumbnailResponses) { + this.problemSetTitle = problemSetTitle; + this.problemThumbnailResponses = problemThumbnailResponses; + } +} diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemThumbnailResponse.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemThumbnailResponse.java new file mode 100644 index 0000000..b4b4b94 --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemThumbnailResponse.java @@ -0,0 +1,17 @@ +package com.moplus.moplus_server.domain.problemset.dto.response; + +import java.util.List; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class ProblemThumbnailResponse { + private String mainProblemImageUrl; + private List tagNames; + + public ProblemThumbnailResponse(String mainProblemImageUrl, List tagNames) { + this.mainProblemImageUrl = mainProblemImageUrl; + this.tagNames = tagNames; + } +} diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java b/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java new file mode 100644 index 0000000..31720c7 --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java @@ -0,0 +1,78 @@ +package com.moplus.moplus_server.domain.problemset.repository; + +import static com.moplus.moplus_server.domain.concept.domain.QConceptTag.conceptTag; +import static com.moplus.moplus_server.domain.problem.domain.problem.QProblem.problem; +import static com.moplus.moplus_server.domain.problemset.domain.QProblemSet.problemSet; + +import com.moplus.moplus_server.domain.problem.domain.problem.Problem; +import com.moplus.moplus_server.domain.problemset.dto.response.ProblemSetSearchGetResponse; +import com.moplus.moplus_server.domain.problemset.dto.response.ProblemThumbnailResponse; +import com.moplus.moplus_server.domain.problemset.domain.QProblemSet; +import com.moplus.moplus_server.domain.problem.domain.problem.QProblem; +import com.moplus.moplus_server.domain.concept.domain.QConceptTag; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class ProblemSetSearchRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + public List search(String problemSetTitle, String problemTitle, List conceptTagNames) { + + return queryFactory + .select(problemSet) + .from(problemSet) + .leftJoin(problem).on(problem.id.in(problemSet.problemIds)) + .leftJoin(conceptTag).on(conceptTag.id.in(problem.conceptTagIds)) + .where( + problemSetTitleContains(problemSetTitle), + problemTitleContains(problemTitle), + conceptTagNamesIn(conceptTagNames) + ) + .fetch() + .stream() + .map(ps -> new ProblemSetSearchGetResponse( + ps.getTitle(), + ps.getProblemIds().stream() + .map(pid -> { + Problem p = queryFactory + .select(problem) + .from(problem) + .where(problem.id.eq(pid)) + .fetchOne(); + return new ProblemThumbnailResponse( + p != null ? p.getMainProblemImageUrl() : null, + p != null ? p.getConceptTagIds().stream() + .map(tagId -> queryFactory + .select(conceptTag.name) + .from(conceptTag) + .where(conceptTag.id.eq(tagId)) + .fetchOne()) + .collect(Collectors.toList()) + : List.of() + ); + }) + .collect(Collectors.toList()) + )) + .collect(Collectors.toList()); + } + + private BooleanExpression problemSetTitleContains(String problemSetTitle) { + return problemSetTitle != null ? QProblemSet.problemSet.title.contains(problemSetTitle) : null; + } + + private BooleanExpression problemTitleContains(String problemTitle) { + return problemTitle != null ? QProblem.problem.comment.contains(problemTitle) : null; + } + + private BooleanExpression conceptTagNamesIn(List conceptTagNames) { + return (conceptTagNames != null && !conceptTagNames.isEmpty()) ? + QConceptTag.conceptTag.name.in(conceptTagNames) : null; + } +} \ No newline at end of file diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java index 83c9388..bf89640 100644 --- a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java @@ -24,7 +24,7 @@ @Transactional @ActiveProfiles("h2test") -@Sql({"/insert-problemset.sql"}) +@Sql({"/insert-problem2.sql"}) @SpringBootTest public class ProblemSetServiceTest { @@ -58,7 +58,7 @@ void setUp() { .orElseThrow(() -> new IllegalArgumentException("문항세트를 찾을 수 없습니다.")); assertThat(savedProblemSet).isNotNull(); - assertThat(savedProblemSet.getName()).isEqualTo("초기 문항세트"); + assertThat(savedProblemSet.getTitle()).isEqualTo("초기 문항세트"); assertThat(savedProblemSet.getProblemIds()).hasSize(3); assertThat(savedProblemSet.getProblemIds().get(0).getId()).isEqualTo("24052001001"); assertThat(savedProblemSet.getProblemIds().get(1).getId()).isEqualTo("24052001002"); @@ -101,7 +101,7 @@ void setUp() { ProblemSet updatedProblemSet = problemSetRepository.findById(problemSetId) .orElseThrow(() -> new IllegalArgumentException("문항세트를 찾을 수 없습니다.")); - assertThat(updatedProblemSet.getName()).isEqualTo("업데이트된 문항세트"); + assertThat(updatedProblemSet.getTitle()).isEqualTo("업데이트된 문항세트"); assertThat(updatedProblemSet.getProblemIds()).hasSize(2); assertThat(updatedProblemSet.getProblemIds().get(0).getId()).isEqualTo("24052001002"); assertThat(updatedProblemSet.getProblemIds().get(1).getId()).isEqualTo("24052001003"); diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java new file mode 100644 index 0000000..17be096 --- /dev/null +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java @@ -0,0 +1,117 @@ +package com.moplus.moplus_server.domain.problemset.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.moplus.moplus_server.domain.problemset.dto.response.ProblemSetSearchGetResponse; +import com.moplus.moplus_server.domain.problemset.dto.response.ProblemThumbnailResponse; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +@SpringBootTest +@ActiveProfiles("h2test") +@Sql({"/practice-test-tag.sql", "/concept-tag.sql", "/insert-problem.sql", "/insert-problem-set.sql"}) +public class ProblemSetSearchRepositoryCustomTest { + + @Autowired + private ProblemSetSearchRepositoryCustom problemSetSearchRepository; + + @Test + void 문항세트_타이틀_일부_포함_검색() { + // when + List result = problemSetSearchRepository.search("고2 모의고사", null, null); + + // then + assertThat(result).hasSize(1); + assertThat(result.get(0).getProblemSetTitle()).isEqualTo("2025년 5월 고2 모의고사 문제 세트"); + } + + @Test + void 문항타이틀_포함_검색() { + // when + List result = problemSetSearchRepository.search(null, "코멘트1", null); + + // then + assertThat(result).hasSize(1); + assertThat(result.get(0).getProblemSetTitle()).isEqualTo("2025년 5월 고2 모의고사 문제 세트"); + } + + @Test + void 개념태그_하나라도_포함되면_조회() { + // when + List result = problemSetSearchRepository.search(null, null, List.of("미분 개념")); + + // then + assertThat(result).hasSize(1); + assertThat(result.get(0).getProblemSetTitle()).isEqualTo("2025년 5월 고2 모의고사 문제 세트"); + } + + @Test + void 모두_적용된_검색() { + // when + List result = problemSetSearchRepository.search("고2", "코멘트1", List.of("미분 개념")); + + // then + assertThat(result).hasSize(1); + assertThat(result.get(0).getProblemSetTitle()).isEqualTo("2025년 5월 고2 모의고사 문제 세트"); + } + + @Test + void 아무_조건도_없으면_모든_데이터_조회() { + // when + List result = problemSetSearchRepository.search(null, null, null); + + // then + assertThat(result).hasSize(1); + } + + @Test + void 문항_여러개_문항세트_검색_조회() { + // when + List result = problemSetSearchRepository.search("고2 모의고사", null, null); + + // then + assertThat(result).hasSize(1); + ProblemSetSearchGetResponse response = result.get(0); + assertThat(response.getProblemSetTitle()).isEqualTo("2025년 5월 고2 모의고사 문제 세트"); + + // ✅ 문항이 2개 존재하는지 확인 + List problems = response.getProblemThumbnailResponses(); + assertThat(problems).hasSize(2); + + // ✅ 문항의 이미지 URL이 올바르게 매핑되었는지 확인 + assertThat(problems.get(0).getMainProblemImageUrl()).isEqualTo("mainProblem.png1"); + assertThat(problems.get(1).getMainProblemImageUrl()).isEqualTo("mainProblem.png2"); + } + + @Test + void 문항태그_조회_테스트() { + // when + List result = problemSetSearchRepository.search("고2 모의고사", null, null); + + // then + assertThat(result).hasSize(1); + ProblemSetSearchGetResponse response = result.get(0); + assertThat(response.getProblemSetTitle()).isEqualTo("2025년 5월 고2 모의고사 문제 세트"); + + // ✅ 문항별 개념 태그 확인 + List problems = response.getProblemThumbnailResponses(); + assertThat(problems).hasSize(2); + + // ✅ 첫 번째 문제(240520012001)의 개념 태그 확인 + List firstProblemTags = new ArrayList<>(problems.get(0).getTagNames()); + + assertThat(firstProblemTags).containsExactlyInAnyOrder("미분 개념", "적분 개념", "삼각함수 개념"); + + // ✅ 두 번째 문제(240520012002)의 개념 태그 확인 + List secondProblemTags = new ArrayList<>(problems.get(1).getTagNames()); + + assertThat(secondProblemTags).containsExactlyInAnyOrder("미분 개념", "삼각함수 개념"); + } +} \ No newline at end of file diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetServiceTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetServiceTest.java index 3bca81f..85e7e40 100644 --- a/src/test/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetServiceTest.java +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetServiceTest.java @@ -92,7 +92,7 @@ void setUp() { // then assertThat(response).isNotNull(); - assertThat(response.name()).isEqualTo("테스트 문항세트"); + assertThat(response.title()).isEqualTo("테스트 문항세트"); assertThat(response.problemSummaries()).hasSize(1); assertThat(response.problemSummaries().get(0).problemId()).isEqualTo(savedProblem.getId().toString()); assertThat(response.problemSummaries().get(0).practiceTestName()).isEqualTo("2025년 5월 고2 모의고사"); @@ -135,7 +135,7 @@ void setUp() { // then assertThat(response).isNotNull(); - assertThat(response.name()).isEqualTo("여러 문항 테스트 문항세트"); + assertThat(response.title()).isEqualTo("여러 문항 테스트 문항세트"); assertThat(response.problemSummaries()).hasSize(2); // 첫 번째 문제 검증 diff --git a/src/test/resources/insert-problem-set.sql b/src/test/resources/insert-problem-set.sql new file mode 100644 index 0000000..e9c8af1 --- /dev/null +++ b/src/test/resources/insert-problem-set.sql @@ -0,0 +1,11 @@ +DELETE FROM problem_set_problems; +DELETE FROM problem_set; + +-- 문제 세트 추가 +INSERT INTO problem_set (problem_set_id, title, is_deleted, confirm_status) +VALUES (1, '2025년 5월 고2 모의고사 문제 세트', false, 'NOT_CONFIRMED'); + +-- 문제 세트에 포함된 문제 추가 +INSERT INTO problem_set_problems (problem_set_id, problem_id, sequence) +VALUES (1, '240520012001', 0), + (1, '240520012002', 1); \ No newline at end of file diff --git a/src/test/resources/insert-problem.sql b/src/test/resources/insert-problem.sql index 530736b..f6ac713 100644 --- a/src/test/resources/insert-problem.sql +++ b/src/test/resources/insert-problem.sql @@ -6,18 +6,18 @@ FROM child_problem; INSERT INTO problem (problem_id, practice_test_id, number, answer, comment, main_problem_image_url, main_analysis_image_url, reading_tip_image_url, senior_tip_image_url, prescription_image_url, is_published, is_variation) -VALUES ('240520012001', 1, 1, '1', '기존 문제 설명 1', - 'mainProblem.png', 'mainAnalysis.png', 'readingTip.png', 'seniorTip.png', 'prescription.png', +VALUES ('240520012001', 1, 1, '1', '기존 문제 코멘트1', + 'mainProblem.png1', 'mainAnalysis.png1', 'readingTip.png1', 'seniorTip.png1', 'prescription.png1', false, false), - ('240520012002', 1, 1, '1', '기존 문제 설명 2', - 'mainProblem.png', 'mainAnalysis.png', 'readingTip.png', 'seniorTip.png', 'prescription.png', + ('240520012002', 1, 1, '1', '기존 문제 코멘트2', + 'mainProblem.png2', 'mainAnalysis.png2', 'readingTip.png2', 'seniorTip.png2', 'prescription.png2', false, false); --- ✅ 기존 자식 문제(ChildProblem) 삽입 +-- 기존 자식 문제(ChildProblem) 삽입 INSERT INTO child_problem (child_problem_id, problem_id, image_url, problem_type, answer, sequence) VALUES (1, '240520012001', 'child1.png', 'MULTIPLE_CHOICE', '1', 0), (2, '240520012001', 'child2.png', 'SHORT_STRING_ANSWER', '정답2', 0); --- ✅ 문제-컨셉 태그 연결 (기존 문제의 ConceptTag) +-- 문제-컨셉 태그 연결 (기존 문제의 ConceptTag) INSERT INTO problem_concept (problem_id, concept_tag_id) VALUES ('240520012001', 1), ('240520012001', 2), @@ -25,7 +25,7 @@ VALUES ('240520012001', 1), ('240520012002', 1), ('240520012002', 3); --- ✅ 자식 문제-컨셉 태그 연결 +-- 자식 문제-컨셉 태그 연결 INSERT INTO child_problem_concept (child_problem_id, concept_tag_id) VALUES (1, 3), (1, 4), diff --git a/src/test/resources/insert-problemset.sql b/src/test/resources/insert-problem2.sql similarity index 100% rename from src/test/resources/insert-problemset.sql rename to src/test/resources/insert-problem2.sql From 7cfcf710be7ecb9f01de25ff5229f3dcf560a10e Mon Sep 17 00:00:00 2001 From: HongGit Date: Fri, 7 Feb 2025 12:50:41 +0900 Subject: [PATCH 5/9] =?UTF-8?q?[fix/#33]=20=EB=AC=B8=ED=95=AD=EC=84=B8?= =?UTF-8?q?=ED=8A=B8=20=EA=B2=80=EC=83=89=EC=8B=9C=20=ED=83=9C=EA=B7=B8?= =?UTF-8?q?=EB=AA=85=20=ED=95=84=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/ProblemThumbnailResponse.java | 5 +- .../ProblemSetSearchRepositoryCustom.java | 69 +++++++------------ .../ProblemSetSearchRepositoryCustomTest.java | 26 ------- 3 files changed, 25 insertions(+), 75 deletions(-) diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemThumbnailResponse.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemThumbnailResponse.java index b4b4b94..0848eba 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemThumbnailResponse.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemThumbnailResponse.java @@ -1,6 +1,5 @@ package com.moplus.moplus_server.domain.problemset.dto.response; -import java.util.List; import lombok.Getter; import lombok.NoArgsConstructor; @@ -8,10 +7,8 @@ @NoArgsConstructor public class ProblemThumbnailResponse { private String mainProblemImageUrl; - private List tagNames; - public ProblemThumbnailResponse(String mainProblemImageUrl, List tagNames) { + public ProblemThumbnailResponse(String mainProblemImageUrl) { this.mainProblemImageUrl = mainProblemImageUrl; - this.tagNames = tagNames; } } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java b/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java index 31720c7..dcd9661 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java @@ -4,16 +4,13 @@ import static com.moplus.moplus_server.domain.problem.domain.problem.QProblem.problem; import static com.moplus.moplus_server.domain.problemset.domain.QProblemSet.problemSet; -import com.moplus.moplus_server.domain.problem.domain.problem.Problem; import com.moplus.moplus_server.domain.problemset.dto.response.ProblemSetSearchGetResponse; import com.moplus.moplus_server.domain.problemset.dto.response.ProblemThumbnailResponse; -import com.moplus.moplus_server.domain.problemset.domain.QProblemSet; -import com.moplus.moplus_server.domain.problem.domain.problem.QProblem; -import com.moplus.moplus_server.domain.concept.domain.QConceptTag; +import com.querydsl.core.group.GroupBy; +import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -24,55 +21,37 @@ public class ProblemSetSearchRepositoryCustom { private final JPAQueryFactory queryFactory; public List search(String problemSetTitle, String problemTitle, List conceptTagNames) { - return queryFactory - .select(problemSet) .from(problemSet) - .leftJoin(problem).on(problem.id.in(problemSet.problemIds)) - .leftJoin(conceptTag).on(conceptTag.id.in(problem.conceptTagIds)) + .leftJoin(problem).on(problem.id.in(problemSet.problemIds)) // 문제 세트 내 포함된 문항과 조인 + .leftJoin(conceptTag).on(conceptTag.id.in(problem.conceptTagIds)) // 문제의 개념 태그 조인 .where( - problemSetTitleContains(problemSetTitle), - problemTitleContains(problemTitle), - conceptTagNamesIn(conceptTagNames) + containsProblemSetTitle(problemSetTitle), + containsProblemTitle(problemTitle), + containsConceptTagNames(conceptTagNames) ) - .fetch() - .stream() - .map(ps -> new ProblemSetSearchGetResponse( - ps.getTitle(), - ps.getProblemIds().stream() - .map(pid -> { - Problem p = queryFactory - .select(problem) - .from(problem) - .where(problem.id.eq(pid)) - .fetchOne(); - return new ProblemThumbnailResponse( - p != null ? p.getMainProblemImageUrl() : null, - p != null ? p.getConceptTagIds().stream() - .map(tagId -> queryFactory - .select(conceptTag.name) - .from(conceptTag) - .where(conceptTag.id.eq(tagId)) - .fetchOne()) - .collect(Collectors.toList()) - : List.of() - ); - }) - .collect(Collectors.toList()) - )) - .collect(Collectors.toList()); + .distinct() + .transform(GroupBy.groupBy(problemSet.id).list( + Projections.constructor(ProblemSetSearchGetResponse.class, + problemSet.title, + GroupBy.list( + Projections.constructor(ProblemThumbnailResponse.class, + problem.mainProblemImageUrl + ) + ) + ) + )); } - private BooleanExpression problemSetTitleContains(String problemSetTitle) { - return problemSetTitle != null ? QProblemSet.problemSet.title.contains(problemSetTitle) : null; + private BooleanExpression containsProblemSetTitle(String problemSetTitle) { + return (problemSetTitle == null || problemSetTitle.isEmpty()) ? null : problemSet.title.containsIgnoreCase(problemSetTitle); } - private BooleanExpression problemTitleContains(String problemTitle) { - return problemTitle != null ? QProblem.problem.comment.contains(problemTitle) : null; + private BooleanExpression containsProblemTitle(String problemTitle) { + return (problemTitle == null || problemTitle.isEmpty()) ? null : problem.comment.containsIgnoreCase(problemTitle); } - private BooleanExpression conceptTagNamesIn(List conceptTagNames) { - return (conceptTagNames != null && !conceptTagNames.isEmpty()) ? - QConceptTag.conceptTag.name.in(conceptTagNames) : null; + private BooleanExpression containsConceptTagNames(List conceptTagNames) { + return (conceptTagNames == null || conceptTagNames.isEmpty()) ? null : conceptTag.name.in(conceptTagNames); } } \ No newline at end of file diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java index 17be096..e394d6d 100644 --- a/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java @@ -4,7 +4,6 @@ import com.moplus.moplus_server.domain.problemset.dto.response.ProblemSetSearchGetResponse; import com.moplus.moplus_server.domain.problemset.dto.response.ProblemThumbnailResponse; -import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -89,29 +88,4 @@ public class ProblemSetSearchRepositoryCustomTest { assertThat(problems.get(0).getMainProblemImageUrl()).isEqualTo("mainProblem.png1"); assertThat(problems.get(1).getMainProblemImageUrl()).isEqualTo("mainProblem.png2"); } - - @Test - void 문항태그_조회_테스트() { - // when - List result = problemSetSearchRepository.search("고2 모의고사", null, null); - - // then - assertThat(result).hasSize(1); - ProblemSetSearchGetResponse response = result.get(0); - assertThat(response.getProblemSetTitle()).isEqualTo("2025년 5월 고2 모의고사 문제 세트"); - - // ✅ 문항별 개념 태그 확인 - List problems = response.getProblemThumbnailResponses(); - assertThat(problems).hasSize(2); - - // ✅ 첫 번째 문제(240520012001)의 개념 태그 확인 - List firstProblemTags = new ArrayList<>(problems.get(0).getTagNames()); - - assertThat(firstProblemTags).containsExactlyInAnyOrder("미분 개념", "적분 개념", "삼각함수 개념"); - - // ✅ 두 번째 문제(240520012002)의 개념 태그 확인 - List secondProblemTags = new ArrayList<>(problems.get(1).getTagNames()); - - assertThat(secondProblemTags).containsExactlyInAnyOrder("미분 개념", "삼각함수 개념"); - } } \ No newline at end of file From 685cd61ca5bae9fbce37b147e9b9f6936b5ff785 Mon Sep 17 00:00:00 2001 From: HongGit Date: Fri, 7 Feb 2025 15:59:11 +0900 Subject: [PATCH 6/9] =?UTF-8?q?[fix/#33]=20=EB=AC=B8=ED=95=AD=EC=84=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=88=9C=EC=84=9C=20api=20swagger=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/problemset/controller/ProblemSetController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetController.java b/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetController.java index 1abe73f..8b13e35 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetController.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/controller/ProblemSetController.java @@ -9,6 +9,7 @@ import com.moplus.moplus_server.domain.problemset.service.ProblemSetGetService; import com.moplus.moplus_server.domain.problemset.service.ProblemSetSaveService; import com.moplus.moplus_server.domain.problemset.service.ProblemSetUpdateService; +import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -39,6 +40,7 @@ public ResponseEntity createProblemSet( return ResponseEntity.ok(problemSetSaveService.createProblemSet(request)); } + @Hidden @PutMapping("/{problemSetId}/sequence") @Operation(summary = "세트 문항순서 변경", description = "문항세트 내의 문항 리스트의 순서를 변경합니다.") public ResponseEntity reorderProblems( From 3d6f968c6c82e06dfbfa706bdddf09dcfdcef851 Mon Sep 17 00:00:00 2001 From: HongGit Date: Fri, 7 Feb 2025 16:38:17 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[fix/#33]=20=EB=AC=B8=ED=95=AD=EC=84=B8?= =?UTF-8?q?=ED=8A=B8=20=EB=B3=80=EA=B2=BD=EC=82=AC=ED=95=AD=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/ProblemSetPostRequest.java | 7 ++- .../service/ProblemSetSaveService.java | 11 +++- .../service/ProblemSetUpdateService.java | 7 +++ .../global/error/exception/ErrorCode.java | 1 + .../problemset/ProblemSetServiceTest.java | 56 +++++++++++++++++++ 5 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java index eb50f4d..a8a614a 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java @@ -10,8 +10,13 @@ public record ProblemSetPostRequest( ) { public ProblemSet toEntity(List problemIdList) { return ProblemSet.builder() - .title(this.problemSetTitle) + .title(verifyTitle(this.problemSetTitle)) .problemIds(problemIdList) .build(); } + + // 빈 타이틀 "제목 없음"으로 임시 세팅 + private static String verifyTitle(String title) { + return (title == null || title.trim().isEmpty()) ? "제목 없음" : title; + } } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetSaveService.java b/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetSaveService.java index 3805f6e..c363815 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetSaveService.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetSaveService.java @@ -3,12 +3,11 @@ import com.moplus.moplus_server.domain.problem.domain.problem.ProblemId; import com.moplus.moplus_server.domain.problem.repository.ProblemRepository; import com.moplus.moplus_server.domain.problemset.domain.ProblemSet; -import com.moplus.moplus_server.domain.problemset.dto.request.ProblemReorderRequest; import com.moplus.moplus_server.domain.problemset.dto.request.ProblemSetPostRequest; -import com.moplus.moplus_server.domain.problemset.dto.request.ProblemSetUpdateRequest; import com.moplus.moplus_server.domain.problemset.repository.ProblemSetRepository; +import com.moplus.moplus_server.global.error.exception.ErrorCode; +import com.moplus.moplus_server.global.error.exception.InvalidValueException; import java.util.List; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,6 +21,11 @@ public class ProblemSetSaveService { @Transactional public Long createProblemSet(ProblemSetPostRequest request) { + // 빈 문항 유효성 검증 + if (request.problems().isEmpty()) { + throw new InvalidValueException(ErrorCode.EMPTY_PROBLEMS_ERROR); + } + // 문제 ID 리스트를 ProblemId 객체로 변환 List problemIdList = request.problems().stream() .map(ProblemId::new) @@ -35,4 +39,5 @@ public Long createProblemSet(ProblemSetPostRequest request) { return problemSetRepository.save(problemSet).getId(); } + } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetUpdateService.java b/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetUpdateService.java index 9f63f11..92134ac 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetUpdateService.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetUpdateService.java @@ -8,6 +8,8 @@ import com.moplus.moplus_server.domain.problemset.dto.request.ProblemReorderRequest; import com.moplus.moplus_server.domain.problemset.dto.request.ProblemSetUpdateRequest; import com.moplus.moplus_server.domain.problemset.repository.ProblemSetRepository; +import com.moplus.moplus_server.global.error.exception.ErrorCode; +import com.moplus.moplus_server.global.error.exception.InvalidValueException; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -38,6 +40,11 @@ public void reorderProblems(Long problemSetId, ProblemReorderRequest request) { public void updateProblemSet(Long problemSetId, ProblemSetUpdateRequest request) { ProblemSet problemSet = problemSetRepository.findByIdElseThrow(problemSetId); + // 빈 문항 유효성 검증 + if (request.problems().isEmpty()) { + throw new InvalidValueException(ErrorCode.EMPTY_PROBLEMS_ERROR); + } + // 문항 리스트 검증 List problemIdList = request.problems().stream() .map(ProblemId::new) diff --git a/src/main/java/com/moplus/moplus_server/global/error/exception/ErrorCode.java b/src/main/java/com/moplus/moplus_server/global/error/exception/ErrorCode.java index 93516b5..747ef27 100644 --- a/src/main/java/com/moplus/moplus_server/global/error/exception/ErrorCode.java +++ b/src/main/java/com/moplus/moplus_server/global/error/exception/ErrorCode.java @@ -56,6 +56,7 @@ public enum ErrorCode { //문항세트 PROBLEM_SET_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 문항세트를 찾을 수 없습니다"), + EMPTY_PROBLEMS_ERROR(HttpStatus.BAD_REQUEST, "적어도 1개의 문항을 등록해주세요"), ; diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java index bf89640..8d02621 100644 --- a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java @@ -138,4 +138,60 @@ void setUp() { .isInstanceOf(InvalidValueException.class) .hasMessageContaining(ErrorCode.INVALID_CONFIRM_PROBLEM.getMessage()); } + + @Test + void 빈_문항리스트_문항세트_생성_실패_테스트() { + // given + ProblemSetPostRequest emptyProblemSetRequest = new ProblemSetPostRequest( + "빈 문항세트", + List.of() // 빈 리스트 + ); + + // when & then + assertThatThrownBy(() -> problemSetSaveService.createProblemSet(emptyProblemSetRequest)) + .isInstanceOf(InvalidValueException.class) + .hasMessageContaining(ErrorCode.EMPTY_PROBLEMS_ERROR.getMessage()); + } + + @Test + void 빈_제목_문항세트_생성_테스트() { + // given + ProblemSetPostRequest emptyTitleRequest = new ProblemSetPostRequest( + "", // 빈 문자열 제목 + List.of("24052001001", "24052001002", "24052001003") + ); + + ProblemSetPostRequest nullTitleRequest = new ProblemSetPostRequest( + null, // null 제목 + List.of("24052001001", "24052001002", "24052001003") + ); + + // when + Long emptyTitleProblemSetId = problemSetSaveService.createProblemSet(emptyTitleRequest); + Long nullTitleProblemSetId = problemSetSaveService.createProblemSet(nullTitleRequest); + + // then + ProblemSet emptyTitleSavedProblemSet = problemSetRepository.findByIdElseThrow(emptyTitleProblemSetId); + + ProblemSet nullTitleSavedProblemSet = problemSetRepository.findByIdElseThrow(nullTitleProblemSetId); + + assertThat(emptyTitleSavedProblemSet.getTitle()).isEqualTo("제목 없음"); // 빈 문자열 제목 테스트 + assertThat(nullTitleSavedProblemSet.getTitle()).isEqualTo("제목 없음"); // null 제목 테스트 + } + + @Test + void 문항세트_빈_제목_업데이트_테스트() { + // given + Long problemSetId = problemSetSaveService.createProblemSet(problemSetPostRequest); + + ProblemSetUpdateRequest emptyUpdateRequest = new ProblemSetUpdateRequest( + "업데이트된 빈 문항세트", + List.of() + ); + + // when & then + assertThatThrownBy(() -> problemSetUpdateService.updateProblemSet(problemSetId, emptyUpdateRequest)) + .isInstanceOf(InvalidValueException.class) + .hasMessageContaining(ErrorCode.EMPTY_PROBLEMS_ERROR.getMessage()); + } } \ No newline at end of file From 060d5b2cd0359c1b6f35ce1e66502b6266c9db88 Mon Sep 17 00:00:00 2001 From: HongGit Date: Fri, 7 Feb 2025 16:55:25 +0900 Subject: [PATCH 8/9] =?UTF-8?q?[fix/#33]=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../moplus_server/domain/problemset/domain/ProblemSet.java | 2 +- .../domain/problemset/ProblemSetServiceTest.java | 3 +-- .../repository/ProblemSetSearchRepositoryCustomTest.java | 4 ++-- src/test/resources/insert-problem.sql | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java b/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java index 775ba79..4f331d6 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java @@ -73,7 +73,7 @@ public void toggleConfirm(List problems) { this.confirmStatus = this.confirmStatus.toggle(); } - public void updateProblemSet(String name, List newProblems) { + public void updateProblemSet(String title, List newProblems) { this.title = title; this.problemIds = newProblems; } diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java index 8d02621..f9ce288 100644 --- a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java @@ -98,8 +98,7 @@ void setUp() { problemSetUpdateService.updateProblemSet(problemSetId, updateRequest); // then - ProblemSet updatedProblemSet = problemSetRepository.findById(problemSetId) - .orElseThrow(() -> new IllegalArgumentException("문항세트를 찾을 수 없습니다.")); + ProblemSet updatedProblemSet = problemSetRepository.findByIdElseThrow(problemSetId); assertThat(updatedProblemSet.getTitle()).isEqualTo("업데이트된 문항세트"); assertThat(updatedProblemSet.getProblemIds()).hasSize(2); diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java index e394d6d..9e05157 100644 --- a/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustomTest.java @@ -34,7 +34,7 @@ public class ProblemSetSearchRepositoryCustomTest { @Test void 문항타이틀_포함_검색() { // when - List result = problemSetSearchRepository.search(null, "코멘트1", null); + List result = problemSetSearchRepository.search(null, "설명 1", null); // then assertThat(result).hasSize(1); @@ -54,7 +54,7 @@ public class ProblemSetSearchRepositoryCustomTest { @Test void 모두_적용된_검색() { // when - List result = problemSetSearchRepository.search("고2", "코멘트1", List.of("미분 개념")); + List result = problemSetSearchRepository.search("고2", "설명 1", List.of("미분 개념")); // then assertThat(result).hasSize(1); diff --git a/src/test/resources/insert-problem.sql b/src/test/resources/insert-problem.sql index f6ac713..d9ecdfb 100644 --- a/src/test/resources/insert-problem.sql +++ b/src/test/resources/insert-problem.sql @@ -6,10 +6,10 @@ FROM child_problem; INSERT INTO problem (problem_id, practice_test_id, number, answer, comment, main_problem_image_url, main_analysis_image_url, reading_tip_image_url, senior_tip_image_url, prescription_image_url, is_published, is_variation) -VALUES ('240520012001', 1, 1, '1', '기존 문제 코멘트1', +VALUES ('240520012001', 1, 1, '1', '기존 문제 설명 1', 'mainProblem.png1', 'mainAnalysis.png1', 'readingTip.png1', 'seniorTip.png1', 'prescription.png1', false, false), - ('240520012002', 1, 1, '1', '기존 문제 코멘트2', + ('240520012002', 1, 1, '1', '기존 문제 설명 2', 'mainProblem.png2', 'mainAnalysis.png2', 'readingTip.png2', 'seniorTip.png2', 'prescription.png2', false, false); -- 기존 자식 문제(ChildProblem) 삽입 From f2a110fa6d1111d988213aea5cc4cf87bffa3ef4 Mon Sep 17 00:00:00 2001 From: HongGit Date: Fri, 7 Feb 2025 18:42:55 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[fix/#33]=20=EB=A6=AC=EB=B7=B0=20=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ConceptTagRepository.java | 2 +- .../domain/problemset/domain/ProblemSet.java | 8 +++--- .../domain/problemset/domain/Title.java | 25 +++++++++++++++++++ .../dto/request/ProblemSetPostRequest.java | 7 +----- .../dto/response/ProblemSetGetResponse.java | 2 +- .../response/ProblemSetSearchGetResponse.java | 5 ++-- .../dto/response/ProblemSummaryResponse.java | 6 ++--- .../ProblemSetSearchRepositoryCustom.java | 4 +-- .../service/ProblemSetGetService.java | 9 ++++--- .../problemset/ProblemSetServiceTest.java | 8 +++--- 10 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/moplus/moplus_server/domain/problemset/domain/Title.java diff --git a/src/main/java/com/moplus/moplus_server/domain/concept/repository/ConceptTagRepository.java b/src/main/java/com/moplus/moplus_server/domain/concept/repository/ConceptTagRepository.java index 4f2eafc..66f71a3 100644 --- a/src/main/java/com/moplus/moplus_server/domain/concept/repository/ConceptTagRepository.java +++ b/src/main/java/com/moplus/moplus_server/domain/concept/repository/ConceptTagRepository.java @@ -20,7 +20,7 @@ default void existsByIdElseThrow(Set ids) { } - default List findByIdInElseThrow(Set ids) { + default List findAllByIdsElseThrow(Set ids) { List conceptTags = findAllById(ids); if (conceptTags.size() != ids.size()) { throw new NotFoundException(ErrorCode.CONCEPT_TAG_NOT_FOUND_IN_LIST); diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java b/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java index 4f331d6..cfa041e 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/domain/ProblemSet.java @@ -8,6 +8,7 @@ import jakarta.persistence.CollectionTable; import jakarta.persistence.Column; import jakarta.persistence.ElementCollection; +import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; @@ -33,7 +34,8 @@ public class ProblemSet extends BaseEntity { @Column(name = "problem_set_id") Long id; - private String title; + @Embedded + private Title title; private boolean isDeleted; @Enumerated(EnumType.STRING) @@ -47,7 +49,7 @@ public class ProblemSet extends BaseEntity { @Builder public ProblemSet(String title, List problemIds) { - this.title = title; + this.title = new Title(title); this.isDeleted = false; this.confirmStatus = ProblemSetConfirmStatus.NOT_CONFIRMED; this.problemIds = problemIds; @@ -74,7 +76,7 @@ public void toggleConfirm(List problems) { } public void updateProblemSet(String title, List newProblems) { - this.title = title; + this.title = new Title(title); this.problemIds = newProblems; } } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/domain/Title.java b/src/main/java/com/moplus/moplus_server/domain/problemset/domain/Title.java new file mode 100644 index 0000000..aa91e1c --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/domain/Title.java @@ -0,0 +1,25 @@ +package com.moplus.moplus_server.domain.problemset.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@NoArgsConstructor +public class Title { + + private static final String DEFAULT_TITLE = "제목 없음"; + + @Column(name = "title", nullable = false) + private String value; + + public Title(String title) { + this.value = verifyTitle(title); + } + + private static String verifyTitle(String title) { + return (title == null || title.trim().isEmpty()) ? DEFAULT_TITLE : title; + } +} diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java index a8a614a..eb50f4d 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/request/ProblemSetPostRequest.java @@ -10,13 +10,8 @@ public record ProblemSetPostRequest( ) { public ProblemSet toEntity(List problemIdList) { return ProblemSet.builder() - .title(verifyTitle(this.problemSetTitle)) + .title(this.problemSetTitle) .problemIds(problemIdList) .build(); } - - // 빈 타이틀 "제목 없음"으로 임시 세팅 - private static String verifyTitle(String title) { - return (title == null || title.trim().isEmpty()) ? "제목 없음" : title; - } } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java index c6fa190..704d9af 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSetGetResponse.java @@ -16,7 +16,7 @@ public static ProblemSetGetResponse of(ProblemSet problemSet, List problemThumbnailResponses; - public ProblemSetSearchGetResponse(String problemSetTitle, - List problemThumbnailResponses) { + public ProblemSetSearchGetResponse( + String problemSetTitle, List problemThumbnailResponses + ) { this.problemSetTitle = problemSetTitle; this.problemThumbnailResponses = problemThumbnailResponses; } diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSummaryResponse.java b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSummaryResponse.java index 78251b2..b563593 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSummaryResponse.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/dto/response/ProblemSummaryResponse.java @@ -11,17 +11,15 @@ public record ProblemSummaryResponse( String practiceTestName, String comment, String mainProblemImageUrl, - List tagNames, - int sequence + List tagNames ) { - public static ProblemSummaryResponse of(Problem problem, int sequence, String practiceTestName, List tagNames) { + public static ProblemSummaryResponse of(Problem problem, String practiceTestName, List tagNames) { return ProblemSummaryResponse.builder() .problemId(problem.getId().toString()) .number(problem.getNumber()) .comment(problem.getComment()) .mainProblemImageUrl(problem.getMainProblemImageUrl()) - .sequence(sequence) .practiceTestName(practiceTestName) .tagNames(tagNames) .build(); diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java b/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java index dcd9661..52474a1 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/repository/ProblemSetSearchRepositoryCustom.java @@ -33,7 +33,7 @@ public List search(String problemSetTitle, String p .distinct() .transform(GroupBy.groupBy(problemSet.id).list( Projections.constructor(ProblemSetSearchGetResponse.class, - problemSet.title, + problemSet.title.value, GroupBy.list( Projections.constructor(ProblemThumbnailResponse.class, problem.mainProblemImageUrl @@ -44,7 +44,7 @@ public List search(String problemSetTitle, String p } private BooleanExpression containsProblemSetTitle(String problemSetTitle) { - return (problemSetTitle == null || problemSetTitle.isEmpty()) ? null : problemSet.title.containsIgnoreCase(problemSetTitle); + return (problemSetTitle == null || problemSetTitle.isEmpty()) ? null : problemSet.title.value.containsIgnoreCase(problemSetTitle); } private BooleanExpression containsProblemTitle(String problemTitle) { diff --git a/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetService.java b/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetService.java index d704b7b..20aae25 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetService.java +++ b/src/main/java/com/moplus/moplus_server/domain/problemset/service/ProblemSetGetService.java @@ -4,6 +4,7 @@ import com.moplus.moplus_server.domain.concept.repository.ConceptTagRepository; import com.moplus.moplus_server.domain.problem.domain.practiceTest.PracticeTestTag; import com.moplus.moplus_server.domain.problem.domain.problem.Problem; +import com.moplus.moplus_server.domain.problem.domain.problem.ProblemId; import com.moplus.moplus_server.domain.problem.repository.PracticeTestTagRepository; import com.moplus.moplus_server.domain.problem.repository.ProblemRepository; import com.moplus.moplus_server.domain.problemset.domain.ProblemSet; @@ -31,14 +32,14 @@ public ProblemSetGetResponse getProblemSet(Long problemSetId) { ProblemSet problemSet = problemSetRepository.findByIdElseThrow(problemSetId); List problemSummaries = new ArrayList<>(); - for (int i = 0; i < problemSet.getProblemIds().size(); i++) { - Problem problem = problemRepository.findByIdElseThrow(problemSet.getProblemIds().get(i)); + for (ProblemId problemId : problemSet.getProblemIds()) { + Problem problem = problemRepository.findByIdElseThrow(problemId); PracticeTestTag practiceTestTag = practiceTestTagRepository.findByIdElseThrow(problem.getPracticeTestId()); - List tagNames = conceptTagRepository.findByIdInElseThrow(problem.getConceptTagIds()) + List tagNames = conceptTagRepository.findAllByIdsElseThrow(problem.getConceptTagIds()) .stream() .map(ConceptTag::getName) .toList(); - problemSummaries.add(ProblemSummaryResponse.of(problem, i, practiceTestTag.getName(), tagNames)); + problemSummaries.add(ProblemSummaryResponse.of(problem, practiceTestTag.getName(), tagNames)); } return ProblemSetGetResponse.of(problemSet, problemSummaries); } diff --git a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java index f9ce288..50c5d4e 100644 --- a/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java +++ b/src/test/java/com/moplus/moplus_server/domain/problemset/ProblemSetServiceTest.java @@ -58,7 +58,7 @@ void setUp() { .orElseThrow(() -> new IllegalArgumentException("문항세트를 찾을 수 없습니다.")); assertThat(savedProblemSet).isNotNull(); - assertThat(savedProblemSet.getTitle()).isEqualTo("초기 문항세트"); + assertThat(savedProblemSet.getTitle().getValue()).isEqualTo("초기 문항세트"); assertThat(savedProblemSet.getProblemIds()).hasSize(3); assertThat(savedProblemSet.getProblemIds().get(0).getId()).isEqualTo("24052001001"); assertThat(savedProblemSet.getProblemIds().get(1).getId()).isEqualTo("24052001002"); @@ -100,7 +100,7 @@ void setUp() { // then ProblemSet updatedProblemSet = problemSetRepository.findByIdElseThrow(problemSetId); - assertThat(updatedProblemSet.getTitle()).isEqualTo("업데이트된 문항세트"); + assertThat(updatedProblemSet.getTitle().getValue()).isEqualTo("업데이트된 문항세트"); assertThat(updatedProblemSet.getProblemIds()).hasSize(2); assertThat(updatedProblemSet.getProblemIds().get(0).getId()).isEqualTo("24052001002"); assertThat(updatedProblemSet.getProblemIds().get(1).getId()).isEqualTo("24052001003"); @@ -174,8 +174,8 @@ void setUp() { ProblemSet nullTitleSavedProblemSet = problemSetRepository.findByIdElseThrow(nullTitleProblemSetId); - assertThat(emptyTitleSavedProblemSet.getTitle()).isEqualTo("제목 없음"); // 빈 문자열 제목 테스트 - assertThat(nullTitleSavedProblemSet.getTitle()).isEqualTo("제목 없음"); // null 제목 테스트 + assertThat(emptyTitleSavedProblemSet.getTitle().getValue()).isEqualTo("제목 없음"); // 빈 문자열 제목 테스트 + assertThat(nullTitleSavedProblemSet.getTitle().getValue()).isEqualTo("제목 없음"); // null 제목 테스트 } @Test