diff --git a/backend/src/main/java/com/funeat/auth/util/AuthHandlerInterceptor.java b/backend/src/main/java/com/funeat/auth/util/AuthHandlerInterceptor.java index 1f68a9e02..1cddeee46 100644 --- a/backend/src/main/java/com/funeat/auth/util/AuthHandlerInterceptor.java +++ b/backend/src/main/java/com/funeat/auth/util/AuthHandlerInterceptor.java @@ -3,6 +3,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.springframework.http.HttpMethod; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; @@ -11,9 +12,12 @@ public class AuthHandlerInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { - final HttpSession session = request.getSession(); - if (session.getAttribute("member") == null) { - throw new IllegalArgumentException("login error"); + final HttpMethod httpMethod = HttpMethod.valueOf(request.getMethod()); + if (httpMethod.equals(HttpMethod.POST) || httpMethod.equals(HttpMethod.PATCH)) { + final HttpSession session = request.getSession(); + if (session.getAttribute("member") == null) { + throw new IllegalArgumentException("login error"); + } } return true; } diff --git a/backend/src/main/java/com/funeat/common/WebConfig.java b/backend/src/main/java/com/funeat/common/WebConfig.java index 737af66f5..31af5acbb 100644 --- a/backend/src/main/java/com/funeat/common/WebConfig.java +++ b/backend/src/main/java/com/funeat/common/WebConfig.java @@ -1,11 +1,13 @@ package com.funeat.common; import com.funeat.auth.util.AuthArgumentResolver; +import com.funeat.auth.util.AuthHandlerInterceptor; import java.util.List; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @@ -13,11 +15,20 @@ public class WebConfig implements WebMvcConfigurer { private final CustomPageableHandlerMethodArgumentResolver customPageableHandlerMethodArgumentResolver; private final AuthArgumentResolver authArgumentResolver; + private final AuthHandlerInterceptor authHandlerInterceptor; public WebConfig(final CustomPageableHandlerMethodArgumentResolver customPageableHandlerMethodArgumentResolver, - final AuthArgumentResolver authArgumentResolver) { + final AuthArgumentResolver authArgumentResolver, + final AuthHandlerInterceptor authHandlerInterceptor) { this.customPageableHandlerMethodArgumentResolver = customPageableHandlerMethodArgumentResolver; this.authArgumentResolver = authArgumentResolver; + this.authHandlerInterceptor = authHandlerInterceptor; + } + + @Override + public void addInterceptors(final InterceptorRegistry registry) { + registry.addInterceptor(authHandlerInterceptor) + .addPathPatterns("/api/products/*/reviews/*"); } @Override diff --git a/backend/src/main/java/com/funeat/member/domain/favorite/ReviewFavorite.java b/backend/src/main/java/com/funeat/member/domain/favorite/ReviewFavorite.java index 5bae5ddc6..a74f4df2f 100644 --- a/backend/src/main/java/com/funeat/member/domain/favorite/ReviewFavorite.java +++ b/backend/src/main/java/com/funeat/member/domain/favorite/ReviewFavorite.java @@ -29,10 +29,6 @@ public class ReviewFavorite { protected ReviewFavorite() { } - public ReviewFavorite(final Boolean favorite) { - this.checked = favorite; - } - public ReviewFavorite(final Member member, final Review review) { this.member = member; this.review = review; diff --git a/backend/src/main/java/com/funeat/review/application/ReviewService.java b/backend/src/main/java/com/funeat/review/application/ReviewService.java index 7399ad09e..7af4cf14c 100644 --- a/backend/src/main/java/com/funeat/review/application/ReviewService.java +++ b/backend/src/main/java/com/funeat/review/application/ReviewService.java @@ -55,8 +55,9 @@ public ReviewService(final ReviewRepository reviewRepository, final TagRepositor } @Transactional - public void create(final Long productId, final MultipartFile image, final ReviewCreateRequest reviewRequest) { - final Member findMember = memberRepository.findById(reviewRequest.getMemberId()) + public void create(final Long productId, final Long memberId, final MultipartFile image, + final ReviewCreateRequest reviewRequest) { + final Member findMember = memberRepository.findById(memberId) .orElseThrow(IllegalArgumentException::new); final Product findProduct = productRepository.findById(productId) .orElseThrow(IllegalArgumentException::new); @@ -86,8 +87,8 @@ public void create(final Long productId, final MultipartFile image, final Review } @Transactional - public void likeReview(final Long reviewId, final ReviewFavoriteRequest request) { - final Member findMember = memberRepository.findById(request.getMemberId()) + public void likeReview(final Long reviewId, final Long memberId, final ReviewFavoriteRequest request) { + final Member findMember = memberRepository.findById(memberId) .orElseThrow(IllegalArgumentException::new); final Review findReview = reviewRepository.findById(reviewId) .orElseThrow(IllegalArgumentException::new); @@ -95,8 +96,8 @@ public void likeReview(final Long reviewId, final ReviewFavoriteRequest request) final ReviewFavorite reviewFavorite = ReviewFavorite.createReviewFavoriteByMemberAndReview(findMember, findReview, request.getFavorite()); - final ReviewFavorite findReviewFavorite = reviewFavoriteRepository.findByMemberAndReview(findMember, - findReview).orElse(reviewFavoriteRepository.save(reviewFavorite)); + final ReviewFavorite findReviewFavorite = reviewFavoriteRepository.findByMemberAndReview(findMember, findReview) + .orElse(reviewFavoriteRepository.save(reviewFavorite)); findReviewFavorite.updateChecked(request.getFavorite()); } diff --git a/backend/src/main/java/com/funeat/review/presentation/ReviewApiController.java b/backend/src/main/java/com/funeat/review/presentation/ReviewApiController.java index 971b4eb40..cd3b1eac2 100644 --- a/backend/src/main/java/com/funeat/review/presentation/ReviewApiController.java +++ b/backend/src/main/java/com/funeat/review/presentation/ReviewApiController.java @@ -1,5 +1,7 @@ package com.funeat.review.presentation; +import com.funeat.auth.dto.LoginRequest; +import com.funeat.auth.util.AuthenticationPrincipal; import com.funeat.review.application.ReviewService; import com.funeat.review.presentation.dto.RankingReviewsResponse; import com.funeat.review.presentation.dto.ReviewCreateRequest; @@ -30,23 +32,26 @@ public ReviewApiController(final ReviewService reviewService) { @PostMapping(value = "/api/products/{productId}/reviews", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE}) - public ResponseEntity writeReview(@PathVariable Long productId, @RequestPart MultipartFile image, - @RequestPart ReviewCreateRequest reviewRequest) { - reviewService.create(productId, image, reviewRequest); + public ResponseEntity writeReview(@PathVariable final Long productId, + @AuthenticationPrincipal final LoginRequest loginInfo, + @RequestPart(required = false) final MultipartFile image, + @RequestPart final ReviewCreateRequest reviewRequest) { + reviewService.create(productId, loginInfo.getId(), image, reviewRequest); return ResponseEntity.created(URI.create("/api/products/" + productId)).build(); } @PatchMapping("/api/products/{productId}/reviews/{reviewId}") public ResponseEntity toggleLikeReview(@PathVariable Long reviewId, + @AuthenticationPrincipal LoginRequest loginInfo, @RequestBody ReviewFavoriteRequest request) { - reviewService.likeReview(reviewId, request); + reviewService.likeReview(reviewId, loginInfo.getId(), request); return ResponseEntity.noContent().build(); } - @GetMapping(value = "/api/products/{productId}/reviews") + @GetMapping("/api/products/{productId}/reviews") public ResponseEntity getSortingReviews(@PathVariable Long productId, @PageableDefault Pageable pageable) { final SortingReviewsResponse response = reviewService.sortingReviews(productId, pageable); diff --git a/backend/src/main/java/com/funeat/review/presentation/ReviewController.java b/backend/src/main/java/com/funeat/review/presentation/ReviewController.java index f419d7143..527085aec 100644 --- a/backend/src/main/java/com/funeat/review/presentation/ReviewController.java +++ b/backend/src/main/java/com/funeat/review/presentation/ReviewController.java @@ -1,5 +1,7 @@ package com.funeat.review.presentation; +import com.funeat.auth.dto.LoginRequest; +import com.funeat.auth.util.AuthenticationPrincipal; import com.funeat.review.presentation.dto.RankingReviewsResponse; import com.funeat.review.presentation.dto.ReviewCreateRequest; import com.funeat.review.presentation.dto.ReviewFavoriteRequest; @@ -27,8 +29,8 @@ public interface ReviewController { description = "리뷰 작성 성공." ) @PostMapping - ResponseEntity writeReview(@PathVariable Long productId, @RequestPart MultipartFile image, - @RequestPart ReviewCreateRequest reviewRequest); + ResponseEntity writeReview(@PathVariable Long productId, @AuthenticationPrincipal LoginRequest loginInfo, + @RequestPart MultipartFile image, @RequestPart ReviewCreateRequest reviewRequest); @Operation(summary = "리뷰 좋아요", description = "리뷰에 좋아요 또는 취소를 한다.") @ApiResponse( @@ -36,7 +38,8 @@ ResponseEntity writeReview(@PathVariable Long productId, @RequestPart Mult description = "리뷰 좋아요(취소) 성공." ) @PatchMapping - ResponseEntity toggleLikeReview(@PathVariable Long reviewId, @RequestBody ReviewFavoriteRequest request); + ResponseEntity toggleLikeReview(@PathVariable Long reviewId, @AuthenticationPrincipal LoginRequest loginInfo, + @RequestBody ReviewFavoriteRequest request); @Operation(summary = "리뷰를 정렬후 조회", description = "리뷰를 정렬후 조회한다.") @ApiResponse( diff --git a/backend/src/main/java/com/funeat/review/presentation/dto/ReviewCreateRequest.java b/backend/src/main/java/com/funeat/review/presentation/dto/ReviewCreateRequest.java index 7fc4ca181..b48805578 100644 --- a/backend/src/main/java/com/funeat/review/presentation/dto/ReviewCreateRequest.java +++ b/backend/src/main/java/com/funeat/review/presentation/dto/ReviewCreateRequest.java @@ -8,15 +8,12 @@ public class ReviewCreateRequest { private final List tagIds; private final String content; private final Boolean reBuy; - private final Long memberId; - public ReviewCreateRequest(final Long rating, final List tagIds, final String content, final Boolean reBuy, - final Long memberId) { + public ReviewCreateRequest(final Long rating, final List tagIds, final String content, final Boolean reBuy) { this.rating = rating; this.tagIds = tagIds; this.content = content; this.reBuy = reBuy; - this.memberId = memberId; } public Long getRating() { @@ -31,10 +28,6 @@ public Boolean getReBuy() { return reBuy; } - public Long getMemberId() { - return memberId; - } - public List getTagIds() { return tagIds; } diff --git a/backend/src/main/java/com/funeat/review/presentation/dto/ReviewFavoriteRequest.java b/backend/src/main/java/com/funeat/review/presentation/dto/ReviewFavoriteRequest.java index 6d1a974c9..6dce84076 100644 --- a/backend/src/main/java/com/funeat/review/presentation/dto/ReviewFavoriteRequest.java +++ b/backend/src/main/java/com/funeat/review/presentation/dto/ReviewFavoriteRequest.java @@ -1,20 +1,18 @@ package com.funeat.review.presentation.dto; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + public class ReviewFavoriteRequest { private final Boolean favorite; - private final Long memberId; - public ReviewFavoriteRequest(final Boolean favorite, final Long memberId) { + @JsonCreator + public ReviewFavoriteRequest(@JsonProperty("favorite") final Boolean favorite) { this.favorite = favorite; - this.memberId = memberId; } public Boolean getFavorite() { return favorite; } - - public Long getMemberId() { - return memberId; - } } diff --git a/backend/src/test/java/com/funeat/acceptance/common/LoginSteps.java b/backend/src/test/java/com/funeat/acceptance/common/LoginSteps.java index f97507e3d..cb746bfd3 100644 --- a/backend/src/test/java/com/funeat/acceptance/common/LoginSteps.java +++ b/backend/src/test/java/com/funeat/acceptance/common/LoginSteps.java @@ -1,21 +1,18 @@ package com.funeat.acceptance.common; import io.restassured.RestAssured; -import io.restassured.http.Cookies; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; @SuppressWarnings("NonAsciiCharacters") public class LoginSteps { - public static Cookies 로그인_쿠키를_얻는다() { - final ExtractableResponse response = RestAssured.given() + public static String 로그인_쿠키를_얻는다() { + return RestAssured.given() .queryParam("code", "test") .when() - .get("/login/oauth2/code/kakao") + .post("/api/login/oauth2/code/kakao") .then() - .extract(); - - return response.detailedCookies(); + .extract() + .response() + .getCookie("JSESSIONID"); } } diff --git a/backend/src/test/java/com/funeat/acceptance/product/ProductAcceptanceTest.java b/backend/src/test/java/com/funeat/acceptance/product/ProductAcceptanceTest.java index 3cc9d47ca..ffb63973a 100644 --- a/backend/src/test/java/com/funeat/acceptance/product/ProductAcceptanceTest.java +++ b/backend/src/test/java/com/funeat/acceptance/product/ProductAcceptanceTest.java @@ -2,6 +2,7 @@ import static com.funeat.acceptance.common.CommonSteps.STATUS_CODE를_검증한다; import static com.funeat.acceptance.common.CommonSteps.정상_처리; +import static com.funeat.acceptance.common.LoginSteps.로그인_쿠키를_얻는다; import static com.funeat.acceptance.product.ProductSteps.CU; import static com.funeat.acceptance.product.ProductSteps.간편식사; import static com.funeat.acceptance.product.ProductSteps.공통_상품_카테고리_목록_조회_요청; @@ -379,14 +380,15 @@ class 리뷰수_기준_내림차순으로_카테고리별_상품_목록_조회 { final MultiPartSpecification image = 리뷰_사진_명세_요청(); final ReviewCreateRequest request1 = new ReviewCreateRequest(4L, - List.of(tag1.getId(), tag2.getId(), tag3.getId()), "request1", true, memberId); + List.of(tag1.getId(), tag2.getId(), tag3.getId()), "request1", true); final ReviewCreateRequest request2 = new ReviewCreateRequest(4L, List.of(tag2.getId(), tag3.getId()), - "request2", true, memberId); - final ReviewCreateRequest request3 = new ReviewCreateRequest(3L, List.of(tag2.getId()), "request3", true, - memberId); - 리뷰_추가_요청(productId, image, request1); - 리뷰_추가_요청(productId, image, request2); - 리뷰_추가_요청(productId, image, request3); + "request2", true); + final ReviewCreateRequest request3 = new ReviewCreateRequest(3L, List.of(tag2.getId()), "request3", true); + + final var loginCookie = 로그인_쿠키를_얻는다(); + 리뷰_추가_요청(productId, image, request1, loginCookie); + 리뷰_추가_요청(productId, image, request2, loginCookie); + 리뷰_추가_요청(productId, image, request3, loginCookie); // when final var response = 상품_상세_조회_요청(productId); diff --git a/backend/src/test/java/com/funeat/acceptance/review/ReviewAcceptanceTest.java b/backend/src/test/java/com/funeat/acceptance/review/ReviewAcceptanceTest.java index ac3205f3f..56a437d98 100644 --- a/backend/src/test/java/com/funeat/acceptance/review/ReviewAcceptanceTest.java +++ b/backend/src/test/java/com/funeat/acceptance/review/ReviewAcceptanceTest.java @@ -4,6 +4,7 @@ import static com.funeat.acceptance.common.CommonSteps.정상_생성; import static com.funeat.acceptance.common.CommonSteps.정상_처리; import static com.funeat.acceptance.common.CommonSteps.정상_처리_NO_CONTENT; +import static com.funeat.acceptance.common.LoginSteps.로그인_쿠키를_얻는다; import static com.funeat.acceptance.review.ReviewSteps.리뷰_사진_명세_요청; import static com.funeat.acceptance.review.ReviewSteps.리뷰_좋아요_요청; import static com.funeat.acceptance.review.ReviewSteps.리뷰_추가_요청; @@ -38,15 +39,15 @@ class ReviewAcceptanceTest extends AcceptanceTest { @Test void 리뷰를_작성한다() { // given - final Long savedMemberId = 멤버_추가_요청(); final Long savedProductId = 상품_추가_요청(); final List savedTagIds = 태그_추가_요청(); final MultiPartSpecification image = 리뷰_사진_명세_요청(); + final var loginCookie = 로그인_쿠키를_얻는다(); - final var request = new ReviewCreateRequest(4L, savedTagIds, "test content", true, savedMemberId); + final var request = new ReviewCreateRequest(4L, savedTagIds, "test content", true); // when - final var response = 리뷰_추가_요청(savedProductId, image, request); + final var response = 리뷰_추가_요청(savedProductId, image, request, loginCookie); // then STATUS_CODE를_검증한다(response, 정상_생성); @@ -59,14 +60,16 @@ class ReviewAcceptanceTest extends AcceptanceTest { final Long savedProductId = 상품_추가_요청(); final List savedTagIds = 태그_추가_요청(); final MultiPartSpecification image = 리뷰_사진_명세_요청(); - final var reviewRequest = new ReviewCreateRequest(4L, savedTagIds, "test content", true, savedMemberId); - final var favoriteRequest = new ReviewFavoriteRequest(true, savedMemberId); + final var reviewRequest = new ReviewCreateRequest(4L, savedTagIds, "test content", true); + final var favoriteRequest = new ReviewFavoriteRequest(true); + + final var loginCookie = 로그인_쿠키를_얻는다(); - 리뷰_추가_요청(savedProductId, image, reviewRequest); + 리뷰_추가_요청(savedProductId, image, reviewRequest, loginCookie); final var savedReviewId = reviewRepository.findAll().get(0).getId(); // when - final var response = 리뷰_좋아요_요청(savedProductId, savedReviewId, favoriteRequest); + final var response = 리뷰_좋아요_요청(savedProductId, savedReviewId, favoriteRequest, loginCookie); final var result = reviewFavoriteRepository.findAll().get(0); // then @@ -82,16 +85,17 @@ class ReviewAcceptanceTest extends AcceptanceTest { final Long savedProductId = 상품_추가_요청(); final List savedTagIds = 태그_추가_요청(); final MultiPartSpecification image = 리뷰_사진_명세_요청(); - final var reviewRequest = new ReviewCreateRequest(4L, savedTagIds, "test content", true, savedMemberId); - final var favoriteRequest = new ReviewFavoriteRequest(true, savedMemberId); - final var favoriteCancelRequest = new ReviewFavoriteRequest(false, savedMemberId); + final var reviewRequest = new ReviewCreateRequest(4L, savedTagIds, "test content", true); + final var favoriteRequest = new ReviewFavoriteRequest(true); + final var favoriteCancelRequest = new ReviewFavoriteRequest(false); + final var loginCookie = 로그인_쿠키를_얻는다(); - 리뷰_추가_요청(savedProductId, image, reviewRequest); + 리뷰_추가_요청(savedProductId, image, reviewRequest, loginCookie); final var savedReview = reviewRepository.findAll().get(0); - 리뷰_좋아요_요청(savedProductId, savedReview.getId(), favoriteRequest); + 리뷰_좋아요_요청(savedProductId, savedReview.getId(), favoriteRequest, loginCookie); // when - final var response = 리뷰_좋아요_요청(savedProductId, savedReview.getId(), favoriteCancelRequest); + final var response = 리뷰_좋아요_요청(savedProductId, savedReview.getId(), favoriteCancelRequest, loginCookie); final var result = reviewFavoriteRepository.findAll().get(0); // then diff --git a/backend/src/test/java/com/funeat/acceptance/review/ReviewSteps.java b/backend/src/test/java/com/funeat/acceptance/review/ReviewSteps.java index fbff6d548..525f18306 100644 --- a/backend/src/test/java/com/funeat/acceptance/review/ReviewSteps.java +++ b/backend/src/test/java/com/funeat/acceptance/review/ReviewSteps.java @@ -13,8 +13,9 @@ public class ReviewSteps { public static ExtractableResponse 리뷰_추가_요청(final Long productId, final MultiPartSpecification image, - final ReviewCreateRequest request) { + final ReviewCreateRequest request, final String loginCookie) { return given() + .cookie("JSESSIONID", loginCookie) .multiPart(image) .multiPart("reviewRequest", request, "application/json") .when() @@ -24,8 +25,10 @@ public class ReviewSteps { } public static ExtractableResponse 리뷰_좋아요_요청(final Long productId, final Long reviewId, - final ReviewFavoriteRequest request) { + final ReviewFavoriteRequest request, + final String loginCookie) { return given() + .cookie("JSESSIONID", loginCookie) .contentType("application/json") .body(request) .when() diff --git a/backend/src/test/java/com/funeat/review/application/ReviewServiceTest.java b/backend/src/test/java/com/funeat/review/application/ReviewServiceTest.java index 085b74f47..100280d35 100644 --- a/backend/src/test/java/com/funeat/review/application/ReviewServiceTest.java +++ b/backend/src/test/java/com/funeat/review/application/ReviewServiceTest.java @@ -82,10 +82,10 @@ void init() { .map(Tag::getId) .collect(Collectors.toList()); final var image = 리뷰_페이크_사진_요청(); - final var request = new ReviewCreateRequest(4L, tagIds, "review", true, member.getId()); + final var request = new ReviewCreateRequest(4L, tagIds, "review", true); // when - reviewService.create(product.getId(), image, request); + reviewService.create(product.getId(), member.getId(), image, request); final var result = reviewRepository.findAll(); // then @@ -108,14 +108,14 @@ void init() { .map(Tag::getId) .collect(Collectors.toList()); final var image = 리뷰_페이크_사진_요청(); - final var reviewCreaterequest = new ReviewCreateRequest(4L, tagIds, "review", true, member.getId()); + final var reviewCreaterequest = new ReviewCreateRequest(4L, tagIds, "review", true); - reviewService.create(product.getId(), image, reviewCreaterequest); + reviewService.create(product.getId(), member.getId(), image, reviewCreaterequest); final var savedReview = reviewRepository.findAll().get(0); // when - final var favoriteRequest = new ReviewFavoriteRequest(true, member.getId()); - reviewService.likeReview(savedReview.getId(), favoriteRequest); + final var favoriteRequest = new ReviewFavoriteRequest(true); + reviewService.likeReview(savedReview.getId(), member.getId(), favoriteRequest); final var reviewFavoriteResult = reviewFavoriteRepository.findAll().get(0); final var reviewResult = reviewRepository.findAll().get(0); @@ -138,17 +138,17 @@ void init() { .map(Tag::getId) .collect(Collectors.toList()); final var image = 리뷰_페이크_사진_요청(); - final var reviewCreaterequest = new ReviewCreateRequest(4L, tagIds, "review", true, member.getId()); + final var reviewCreaterequest = new ReviewCreateRequest(4L, tagIds, "review", true); - reviewService.create(product.getId(), image, reviewCreaterequest); + reviewService.create(product.getId(), member.getId(), image, reviewCreaterequest); final var savedReview = reviewRepository.findAll().get(0); - final var favoriteRequest = new ReviewFavoriteRequest(true, member.getId()); - reviewService.likeReview(savedReview.getId(), favoriteRequest); + final var favoriteRequest = new ReviewFavoriteRequest(true); + reviewService.likeReview(savedReview.getId(), member.getId(), favoriteRequest); // when - final var cancelFavoriteRequest = new ReviewFavoriteRequest(false, member.getId()); - reviewService.likeReview(savedReview.getId(), cancelFavoriteRequest); + final var cancelFavoriteRequest = new ReviewFavoriteRequest(false); + reviewService.likeReview(savedReview.getId(), member.getId(), cancelFavoriteRequest); final var reviewFavoriteResult = reviewFavoriteRepository.findAll().get(0); final var reviewResult = reviewRepository.findAll().get(0);