From 8ac2fa106cee3dfcd307336b7fc501ea48f4fa74 Mon Sep 17 00:00:00 2001 From: SonMinGyu Date: Fri, 28 Jul 2023 15:33:51 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9E=A5=EC=86=8C=20ID=EB=A1=9C=20revi?= =?UTF-8?q?ew=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20API,?= =?UTF-8?q?=20test=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 장소 ID로 review를 검색하는 기능 및 test를 구현함 --- .../review/application/ReviewService.java | 6 ++ .../ReviewRepositoryCustom.java | 1 + .../infrastructure/ReviewRepositoryImpl.java | 20 ++++++- .../review/ui/ReviewV1Controller.java | 16 +++-- .../acceptance/AcceptanceTestFixture.java | 17 ++++++ .../review/ReviewAcceptanceTest.java | 53 ++++++++++++++++- .../review/application/ReviewServiceTest.java | 58 +++++++++++++++++++ 7 files changed, 165 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/prography/kagongsillok/review/application/ReviewService.java b/src/main/java/org/prography/kagongsillok/review/application/ReviewService.java index fd0fe70..4c0f0f1 100644 --- a/src/main/java/org/prography/kagongsillok/review/application/ReviewService.java +++ b/src/main/java/org/prography/kagongsillok/review/application/ReviewService.java @@ -60,6 +60,12 @@ public List getAllReviewsByMemberId(final Long memberId) { return CustomListUtils.mapTo(reviews, ReviewDto::from); } + public List getAllReviewsByPlaceId(final Long placeId) { + final List reviews = reviewRepository.findAllByPlaceId(placeId); + + return CustomListUtils.mapTo(reviews, ReviewDto::from); + } + @Transactional public ReviewDto updateReview(final Long id, final ReviewUpdateCommand reviewUpdateCommand) { final Review review = reviewRepository.findById(id) diff --git a/src/main/java/org/prography/kagongsillok/review/infrastructure/ReviewRepositoryCustom.java b/src/main/java/org/prography/kagongsillok/review/infrastructure/ReviewRepositoryCustom.java index c2ce1f4..aa35137 100644 --- a/src/main/java/org/prography/kagongsillok/review/infrastructure/ReviewRepositoryCustom.java +++ b/src/main/java/org/prography/kagongsillok/review/infrastructure/ReviewRepositoryCustom.java @@ -7,4 +7,5 @@ public interface ReviewRepositoryCustom { List findAllByMemberId(final Long memberId); + List findAllByPlaceId(final Long placeId); } diff --git a/src/main/java/org/prography/kagongsillok/review/infrastructure/ReviewRepositoryImpl.java b/src/main/java/org/prography/kagongsillok/review/infrastructure/ReviewRepositoryImpl.java index af9e68e..f5ccf77 100644 --- a/src/main/java/org/prography/kagongsillok/review/infrastructure/ReviewRepositoryImpl.java +++ b/src/main/java/org/prography/kagongsillok/review/infrastructure/ReviewRepositoryImpl.java @@ -1,7 +1,9 @@ package org.prography.kagongsillok.review.infrastructure; +import static org.prography.kagongsillok.record.domain.QStudyRecord.studyRecord; import static org.prography.kagongsillok.review.domain.QReview.review; +import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; import lombok.RequiredArgsConstructor; @@ -22,9 +24,25 @@ public List findAllByMemberId(final Long memberId) { .selectFrom(review) .where( review.memberId.eq(memberId), - review.isDeleted.eq(Boolean.FALSE) + isNotDeleted() ) .limit(DEFAULT_SEARCH_RESULT_SIZE) .fetch(); } + + @Override + public List findAllByPlaceId(final Long placeId) { + return queryFactory + .selectFrom(review) + .where( + review.placeId.eq(placeId), + isNotDeleted() + ) + .limit(DEFAULT_SEARCH_RESULT_SIZE) + .fetch(); + } + + private BooleanExpression isNotDeleted() { + return review.isDeleted.eq(Boolean.FALSE); + } } diff --git a/src/main/java/org/prography/kagongsillok/review/ui/ReviewV1Controller.java b/src/main/java/org/prography/kagongsillok/review/ui/ReviewV1Controller.java index 6f82f92..a571774 100644 --- a/src/main/java/org/prography/kagongsillok/review/ui/ReviewV1Controller.java +++ b/src/main/java/org/prography/kagongsillok/review/ui/ReviewV1Controller.java @@ -34,9 +34,9 @@ public ResponseEntity> createReview( return CommonResponse.success(ReviewResponse.from(createdReview)); } - @GetMapping("/{id}") + @GetMapping("/{reviewId}") public ResponseEntity> getReview( - @PathVariable("id") Long id + @PathVariable("reviewId") Long id ) { final ReviewDto reviewDto = reviewService.getReview(id); return CommonResponse.success(ReviewResponse.from(reviewDto)); @@ -50,6 +50,14 @@ public ResponseEntity> getAllReviews( return CommonResponse.success(ReviewListResponse.of(reviewDtos)); } + @GetMapping("/place/{placeId}") + public ResponseEntity> getAllPlaceReviews( + @PathVariable("placeId") Long placeId + ) { + final List reviewDtos = reviewService.getAllReviewsByPlaceId(placeId); + return CommonResponse.success(ReviewListResponse.of(reviewDtos)); + } + @PutMapping public ResponseEntity> updateReview( @RequestBody ReviewUpdateRequest reviewUpdateRequest @@ -61,8 +69,8 @@ public ResponseEntity> updateReview( return CommonResponse.success(ReviewResponse.from(updatedReview)); } - @DeleteMapping("/{id}") - public ResponseEntity deleteReview(@PathVariable("id") final Long id) { + @DeleteMapping("/{reviewId}") + public ResponseEntity deleteReview(@PathVariable("reviewId") final Long id) { reviewService.deleteReview(id); return ResponseEntity.ok().build(); } diff --git a/src/test/java/org/prography/kagongsillok/acceptance/AcceptanceTestFixture.java b/src/test/java/org/prography/kagongsillok/acceptance/AcceptanceTestFixture.java index e36140c..f8170cb 100644 --- a/src/test/java/org/prography/kagongsillok/acceptance/AcceptanceTestFixture.java +++ b/src/test/java/org/prography/kagongsillok/acceptance/AcceptanceTestFixture.java @@ -157,6 +157,23 @@ public class AcceptanceTestFixture { .build(); } + public static ReviewCreateRequest 이미지_두개_태그_두개_장소_ID로_리뷰_생성_요청_바디( + final Long memberId, + final String content, + final List tagIds, + final Long placeId + ) { + return ReviewCreateRequest + .builder() + .rating(5) + .memberId(memberId) + .placeId(placeId) + .content(content) + .imageIds(List.of(1L, 2L)) + .reviewTagIds(tagIds) + .build(); + } + public static ReviewUpdateRequest 리뷰_수정_요청_바디( final Long id, final int rating, diff --git a/src/test/java/org/prography/kagongsillok/acceptance/review/ReviewAcceptanceTest.java b/src/test/java/org/prography/kagongsillok/acceptance/review/ReviewAcceptanceTest.java index d392e02..1ee4dda 100644 --- a/src/test/java/org/prography/kagongsillok/acceptance/review/ReviewAcceptanceTest.java +++ b/src/test/java/org/prography/kagongsillok/acceptance/review/ReviewAcceptanceTest.java @@ -5,6 +5,7 @@ import static org.prography.kagongsillok.acceptance.AcceptanceTestFixture.기본_닉네임_이메일_가입_요청_바디; import static org.prography.kagongsillok.acceptance.AcceptanceTestFixture.리뷰_수정_요청_바디; import static org.prography.kagongsillok.acceptance.AcceptanceTestFixture.이미지_두개_태그_두개_리뷰_생성_요청_바디; +import static org.prography.kagongsillok.acceptance.AcceptanceTestFixture.이미지_두개_태그_두개_장소_ID로_리뷰_생성_요청_바디; import static org.prography.kagongsillok.acceptance.AcceptanceTestFixture.태그_생성_요청_바디; import java.util.List; @@ -111,7 +112,6 @@ public class ReviewAcceptanceTest extends AcceptanceTest { final Long 생성된_태그4_id = 태그_생성_요청(태그_생성_요청_바디4).getId(); final var 입력_태그1 = 입력_태그_두개_생성(생성된_태그1_id, 생성된_태그2_id); final var 입력_태그2 = 입력_태그_두개_생성(생성된_태그3_id, 생성된_태그4_id); -// final var memberId = 1L; final var 리뷰_생성_요청_바디1 = 이미지_두개_태그_두개_리뷰_생성_요청_바디(생성된_멤버_id, "test review1", 입력_태그1); final var 리뷰_생성_요청_바디2 = 이미지_두개_태그_두개_리뷰_생성_요청_바디(생성된_멤버_id, "test review2", 입력_태그2); 리뷰_생성_요청(리뷰_생성_요청_바디1); @@ -122,6 +122,31 @@ public class ReviewAcceptanceTest extends AcceptanceTest { 멤버_id로_생성한_리뷰_조회_검증(생성된_멤버_id, 멤버_id로_리뷰_조회_응답, 입력_태그1, 입력_태그2); } + @Test + void 장소_id로_생성한_리뷰들을_조회한다() { + final var 멤버_생성_요청_바디 = 기본_닉네임_이메일_가입_요청_바디("닉네임", "test@test.com"); + final var 생성된_멤버_id = 멤버_생성_요청(멤버_생성_요청_바디).getId(); + final var 태그_생성_요청_바디1 = 태그_생성_요청_바디("#tag1", "test tag1"); + final var 태그_생성_요청_바디2 = 태그_생성_요청_바디("#tag2", "test tag2"); + final var 태그_생성_요청_바디3 = 태그_생성_요청_바디("#tag3", "test tag3"); + final var 태그_생성_요청_바디4 = 태그_생성_요청_바디("#tag4", "test tag4"); + final var 생성된_태그1_id = 태그_생성_요청(태그_생성_요청_바디1).getId(); + final var 생성된_태그2_id = 태그_생성_요청(태그_생성_요청_바디2).getId(); + final var 생성된_태그3_id = 태그_생성_요청(태그_생성_요청_바디3).getId(); + final var 생성된_태그4_id = 태그_생성_요청(태그_생성_요청_바디4).getId(); + final var 입력_태그1 = 입력_태그_두개_생성(생성된_태그1_id, 생성된_태그2_id); + final var 입력_태그2 = 입력_태그_두개_생성(생성된_태그3_id, 생성된_태그4_id); + final var 장소_id = 1L; + final var 리뷰_생성_요청_바디1 = 이미지_두개_태그_두개_장소_ID로_리뷰_생성_요청_바디(생성된_멤버_id, "test review1", 입력_태그1, 장소_id); + final var 리뷰_생성_요청_바디2 = 이미지_두개_태그_두개_장소_ID로_리뷰_생성_요청_바디(생성된_멤버_id, "test review2", 입력_태그2, 장소_id); + 리뷰_생성_요청(리뷰_생성_요청_바디1); + 리뷰_생성_요청(리뷰_생성_요청_바디2); + + final var 장소_id로_리뷰_조회_응답 = 멤버_id로_리뷰_조회_요청(장소_id); + + 장소_id로_생성한_리뷰_조회_검증(생성된_멤버_id, 장소_id로_리뷰_조회_응답, 입력_태그1, 입력_태그2, 장소_id); + } + private MemberResponse 멤버_생성_요청(final LocalJoinRequest 멤버_생성_요청_바디) { return 응답_바디_추출(post(AUTH_API_BASE_URL_V1 + "/local/join", 멤버_생성_요청_바디), MemberResponse.class); } @@ -149,10 +174,36 @@ public class ReviewAcceptanceTest extends AcceptanceTest { ); } + private static void 장소_id로_생성한_리뷰_조회_검증( + final Long memberId, + final ReviewListResponse 장소_id로_리뷰_조회_요청, + final List 입력_태그1, + final List 입력_태그2, + final Long 장소_id + ) { + assertAll( + () -> assertThat(장소_id로_리뷰_조회_요청.getReviews().size()).isEqualTo(2), + () -> assertThat(장소_id로_리뷰_조회_요청.getReviews()).extracting("memberId") + .containsAll(List.of(memberId, memberId)), + () -> assertThat(장소_id로_리뷰_조회_요청.getReviews()).extracting("content") + .containsAll(List.of("test review1", "test review2")), + () -> assertThat(장소_id로_리뷰_조회_요청.getReviews()).extracting("tagIds") + .containsAll(List.of(입력_태그1, 입력_태그2)), + () -> assertThat(장소_id로_리뷰_조회_요청.getReviews()).extracting("memberNickName") + .containsAll(List.of("닉네임", "닉네임")), + () -> assertThat(장소_id로_리뷰_조회_요청.getReviews()).extracting("placeId") + .containsAll(List.of(장소_id, 장소_id)) + ); + } + private ReviewListResponse 멤버_id로_리뷰_조회_요청(final Long memberId) { return 응답_바디_추출(get(REVIEW_API_BASE_URL_V1 + "/member/" + memberId), ReviewListResponse.class); } + private ReviewListResponse 장소_id로_리뷰_조회_요청(final Long placeId) { + return 응답_바디_추출(get(REVIEW_API_BASE_URL_V1 + "/place/" + placeId), ReviewListResponse.class); + } + private static void 리뷰_삭제_검증(final int 리뷰_삭제_응답, final int 삭제후_리뷰_조회_응답코드) { assertAll( () -> assertThat(리뷰_삭제_응답).isEqualTo(200), diff --git a/src/test/java/org/prography/kagongsillok/review/application/ReviewServiceTest.java b/src/test/java/org/prography/kagongsillok/review/application/ReviewServiceTest.java index be166a3..d80a275 100644 --- a/src/test/java/org/prography/kagongsillok/review/application/ReviewServiceTest.java +++ b/src/test/java/org/prography/kagongsillok/review/application/ReviewServiceTest.java @@ -192,6 +192,64 @@ public class ReviewServiceTest { ); } + @Test + void 장소_ID로_작성한_리뷰들을_조회한다() { + final Long memberId = saveMemberAndGetMemberId(); + final Long placeId = 1L; + final Long tagId1 = saveTagAndGetTagId("#tag1"); + final Long tagId2 = saveTagAndGetTagId("#tag2"); + final Long tagId3 = saveTagAndGetTagId("#tag3"); + final Long tagId4 = saveTagAndGetTagId("#tag4"); + final ReviewCreateCommand reviewCreateCommand1 = ReviewCreateCommand + .builder() + .memberId(memberId) + .placeId(placeId) + .rating(5) + .content("test review1") + .imageIds(List.of(1L, 2L)) + .reviewTagIds(List.of(tagId1, tagId3)) + .build(); + final ReviewCreateCommand reviewCreateCommand2 = ReviewCreateCommand + .builder() + .memberId(memberId) + .placeId(placeId) + .rating(1) + .content("test review2") + .imageIds(List.of(3L, 4L)) + .reviewTagIds(List.of(tagId4)) + .build(); + final ReviewCreateCommand reviewCreateCommand3 = ReviewCreateCommand + .builder() + .memberId(memberId) + .placeId(placeId) + .rating(3) + .content("test review3") + .imageIds(List.of(5L)) + .reviewTagIds(List.of(tagId2, tagId3)) + .build(); + reviewService.createReview(reviewCreateCommand1); + reviewService.createReview(reviewCreateCommand2); + reviewService.createReview(reviewCreateCommand3); + + final List reviewDtos = reviewService.getAllReviewsByMemberId(memberId); + + assertAll( + () -> assertThat(reviewDtos.size()).isEqualTo(3), + () -> assertThat(reviewDtos).extracting("placeId") + .containsAll(List.of(placeId, placeId, placeId)), + () -> assertThat(reviewDtos).extracting("rating") + .containsAll(List.of(5, 1, 3)), + () -> assertThat(reviewDtos).extracting("memberNickName") + .containsAll(List.of("닉네임", "닉네임", "닉네임")), + () -> assertThat(reviewDtos).extracting("content") + .containsAll(List.of("test review1", "test review2", "test review3")), + () -> assertThat(reviewDtos).extracting("imageIds") + .containsAll(List.of(List.of(1L, 2L), List.of(3L, 4L), List.of(5L))), + () -> assertThat(reviewDtos).extracting("tagIds") + .containsAll(List.of(List.of(tagId1, tagId3), List.of(tagId4), List.of(tagId2, tagId3))) + ); + } + private Long saveTagAndGetTagId(final String tagName) { final ReviewTag reviewTag1 = new ReviewTag(tagName, "test tag"); return reviewTagRepository.save(reviewTag1).getId();