From 9e7ec5a8147ea50174813e063da3b4bc6de4ce44 Mon Sep 17 00:00:00 2001 From: feel-coding Date: Fri, 12 Jan 2024 00:49:37 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EB=A6=AC=EB=B7=B0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20API=20=EC=B6=94=EA=B0=80=20#113?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/cvsgo/controller/ReviewController.java | 6 ++++++ .../java/com/cvsgo/service/ReviewService.java | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/main/java/com/cvsgo/controller/ReviewController.java b/src/main/java/com/cvsgo/controller/ReviewController.java index a255eda2..855917a9 100644 --- a/src/main/java/com/cvsgo/controller/ReviewController.java +++ b/src/main/java/com/cvsgo/controller/ReviewController.java @@ -62,6 +62,12 @@ public SuccessResponse updateReview(@LoginUser User user, @PathVariable Lo return SuccessResponse.create(); } + @DeleteMapping("/reviews/{reviewId}") + public SuccessResponse deleteReview(@LoginUser User user, @PathVariable Long reviewId) { + reviewService.deleteReview(user, reviewId); + return SuccessResponse.create(); + } + @PostMapping("/reviews/{reviewId}/likes") @ResponseStatus(HttpStatus.CREATED) public SuccessResponse createReviewLike(@LoginUser User user, diff --git a/src/main/java/com/cvsgo/service/ReviewService.java b/src/main/java/com/cvsgo/service/ReviewService.java index 65302096..3207da42 100644 --- a/src/main/java/com/cvsgo/service/ReviewService.java +++ b/src/main/java/com/cvsgo/service/ReviewService.java @@ -119,6 +119,21 @@ public void updateReview(User user, Long reviewId, UpdateReviewRequestDto reques review.updateRating(request.getRating()); } + /** + * 리뷰를 삭제합니다. + * + * @param user 현재 로그인한 사용자 + * @param reviewId 삭제하려는 리뷰 ID + */ + @Transactional + public void deleteReview(User user, Long reviewId) { + Review review = reviewRepository.findById(reviewId).orElseThrow(() -> NOT_FOUND_REVIEW); + if (!review.getUser().equals(user)) { + throw FORBIDDEN_REVIEW; + } + reviewRepository.delete(review); + } + /** * 필터를 적용하여 리뷰를 조회합니다. * From a060e7d494b0237784dc8d4b01638ebe559f6ae4 Mon Sep 17 00:00:00 2001 From: feel-coding Date: Sun, 14 Jan 2024 02:18:55 +0900 Subject: [PATCH 2/3] =?UTF-8?q?test:=20=EB=A6=AC=EB=B7=B0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20#113?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewControllerTest.java | 20 +++++++++++-- .../com/cvsgo/service/ReviewServiceTest.java | 30 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/cvsgo/controller/ReviewControllerTest.java b/src/test/java/com/cvsgo/controller/ReviewControllerTest.java index 8d570bdd..a6debf80 100644 --- a/src/test/java/com/cvsgo/controller/ReviewControllerTest.java +++ b/src/test/java/com/cvsgo/controller/ReviewControllerTest.java @@ -92,7 +92,7 @@ class ReviewControllerTest { private static final String PRODUCT_REVIEW_API_PATH = "/api/products/{productId}/reviews"; - private static final String UPDATE_REVIEW_API_PATH = "/api/reviews/{reviewId}"; + private static final String REVIEW_API_PATH = "/api/reviews/{reviewId}"; private static final String SEARCH_REVIEW_API_PATH = "/api/reviews"; @@ -267,7 +267,7 @@ void respond_200_when_succeed_to_update_review() throws Exception { UpdateReviewRequestDto requestDto = new UpdateReviewRequestDto(5, "맛있어요", List.of("리뷰 이미지 URL 1", "리뷰 이미지 URL 2")); - mockMvc.perform(put(UPDATE_REVIEW_API_PATH, 1) + mockMvc.perform(put(REVIEW_API_PATH, 1) .content(objectMapper.writeValueAsString(requestDto)) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()).andDo(print()) @@ -450,6 +450,22 @@ void respond_500_when_delete_review_like_but_concurrency_issue_occurs() throws E .andDo(print()); } + @Test + @DisplayName("리뷰 삭제에 성공하면 HTTP 200을 응답한다") + void respond_200_when_succeed_to_delete_review() throws Exception { + mockMvc.perform(delete(REVIEW_API_PATH, 1) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andDo(print()) + .andDo(document(documentIdentifier, + getDocumentRequest(), + getDocumentResponse(), + pathParameters( + parameterWithName("reviewId").description("리뷰 ID") + ) + )); + } + ReviewDto responseDto1 = ReviewDto.builder() .productId(13L) .productName("불닭볶음면큰컵") diff --git a/src/test/java/com/cvsgo/service/ReviewServiceTest.java b/src/test/java/com/cvsgo/service/ReviewServiceTest.java index e2282e12..ded34953 100644 --- a/src/test/java/com/cvsgo/service/ReviewServiceTest.java +++ b/src/test/java/com/cvsgo/service/ReviewServiceTest.java @@ -432,6 +432,36 @@ void succeed_to_read_user_review() { assertThat(reviews.size()).isEqualTo(1); } + @Test + @DisplayName("특정 리뷰를 정상적으로 삭제한다.") + void succeed_to_delete_review() { + given(reviewRepository.findById(any())).willReturn(Optional.of(review)); + + reviewService.deleteReview(user2, 1L); + + then(reviewRepository).should(times(1)).findById(anyLong()); + then(reviewRepository).should(times(1)).delete(any()); + } + + @Test + @DisplayName("리뷰 작성자가 아닌 사용자가 리뷰 삭제를 시도하면 ForbiddenException이 발생한다.") + void should_throw_ForbiddenException_when_delete_review_but_review_does_not_exist() { + given(reviewRepository.findById(any())).willReturn(Optional.of(review)); + + assertThrows(ForbiddenException.class, + () -> reviewService.deleteReview(user1, 1L)); + } + + @Test + @DisplayName("존재하지 않는 리뷰를 삭제하면 NotFoundException이 발생한다.") + void should_throw_NotFoundException_when_delete_review_but_review_does_not_exist() { + given(reviewRepository.findById(any())).willReturn(Optional.empty()); + + assertThrows(NotFoundException.class, + () -> reviewService.deleteReview(user1, 1000L)); + } + + User user1 = User.builder() .id(1L) .userId("abc@naver.com") From ede7e9e1c821313dbce72b90b551648d57c05df1 Mon Sep 17 00:00:00 2001 From: feel-coding Date: Sun, 14 Jan 2024 02:26:57 +0900 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20=EB=A6=AC=EB=B7=B0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20API=20=EB=AC=B8=EC=84=9C=20=EC=B6=94=EA=B0=80=20#11?= =?UTF-8?q?3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/api-doc.adoc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/docs/asciidoc/api-doc.adoc b/src/docs/asciidoc/api-doc.adoc index 42dbc188..3996856f 100644 --- a/src/docs/asciidoc/api-doc.adoc +++ b/src/docs/asciidoc/api-doc.adoc @@ -425,6 +425,22 @@ include::{snippets}/review-controller-test/respond_200_when_succeed_to_delete_re | `404 NOT FOUND` | `NOT_FOUND_REVIEW` | 해당하는 리뷰가 없는 경우 | `404 NOT FOUND` | `NOT_FOUND_REVIEW_LIKE` | 해당하는 리뷰 좋아요가 없는 경우 |=== + +=== 4-7. 리뷰 삭제 +==== Path Parameters +include::{snippets}/review-controller-test/respond_200_when_succeed_to_delete_review/path-parameters.adoc[] +==== Sample Request +include::{snippets}/review-controller-test/respond_200_when_succeed_to_delete_review/http-request.adoc[] +==== Sample Response +include::{snippets}/review-controller-test/respond_200_when_succeed_to_delete_review/http-response.adoc[] +==== Error Response +|=== +| HTTP Status | Error Code | Detail + +| `403 FORBIDDEN` | `FORBIDDEN_REVIEW` | 해당 리뷰에 대한 삭제 권한이 없는 경우 +| `404 NOT FOUND` | `NOT_FOUND_REVIEW` | 해당하는 리뷰가 없는 경우 +|=== + == 5. 이미지 === 5-1. 이미지 업로드 ==== Path Parameters