Skip to content

Commit

Permalink
Merge pull request #196 from THEGOODs-repo/feature/184
Browse files Browse the repository at this point in the history
[Feat/184] 리뷰 등록 API 구현
  • Loading branch information
Eunjin3395 authored Jun 26, 2024
2 parents 5ec8b6a + 1dc7f2b commit 12e00e5
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public enum ErrorStatus implements BaseErrorCode {
CART_DETAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "CART4004", "해당 장바구니 상세 내역을 찾을 수 없습니다"),
DELETE_CART_DETAIL_FAILED(HttpStatus.BAD_REQUEST, "CART4005", "장바구니 상세 내역을 삭제할 수 없습니다."),

// 리뷰 관련 에러
REVIEW_ALREADY_EXISTS(HttpStatus.BAD_REQUEST, "REVIEW4001", "이미 리뷰를 작성한 주문내역 입니다."),

// test
TEMP_EXCEPTION(HttpStatus.BAD_REQUEST, "TEMP4001", "테스트"),

Expand All @@ -59,7 +62,7 @@ public enum ErrorStatus implements BaseErrorCode {
MEMBER_ADDRESS_NOT_FOUND(HttpStatus.NOT_FOUND, "MEMBER4009", "주소가 존재하지 않습니다"),
MEMBER_INACTIVATE(HttpStatus.NOT_ACCEPTABLE, "MEMBER4010", "탈퇴한 회원입니다."),
MEMBER_NOT_OWNER(HttpStatus.NOT_ACCEPTABLE, "MEMBER4011", "해당 회원이 아닙니다."),
MEMBER_CONTACT_NOT_FOUND(HttpStatus.NOT_FOUND,"MEMBER4012", "연락 가능 시간을 조회할 수 없습니다."),
MEMBER_CONTACT_NOT_FOUND(HttpStatus.NOT_FOUND, "MEMBER4012", "연락 가능 시간을 조회할 수 없습니다."),
MEMBER_EMAIL_DUPLICATED(HttpStatus.BAD_REQUEST, "MEMBER4013", "중복된 이메일입니다."),
MEMBER_EMAIL_INCORRECT(HttpStatus.BAD_REQUEST, "MEMBER4014", "잘못된 이메일입니다."),

Expand All @@ -77,7 +80,7 @@ public enum ErrorStatus implements BaseErrorCode {
POST_ALREADY_FOLLOW(HttpStatus.BAD_REQUEST, "POST4002", "이미 팔로우 했습니다."),
POST_FOLLOW_NOT_FOUND(HttpStatus.BAD_REQUEST, "POST4003", "해당 팔로우를 찾을수 없습니다."),
POST_NOT_FOUND(HttpStatus.BAD_REQUEST, "POST4004", "포스트를 찾을수 없습니다."),
POST_COMMENT_NOT_FOUND(HttpStatus.BAD_REQUEST,"POST4005", "해당 댓글을 찾을 수 없습니다."),
POST_COMMENT_NOT_FOUND(HttpStatus.BAD_REQUEST, "POST4005", "해당 댓글을 찾을 수 없습니다."),
POST_COMMENT_NOT_UPDATE(HttpStatus.BAD_REQUEST, "POST4006", "해당 댓글을 수정할 수 없습니다."),


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.umc.TheGoods.apiPayload.exception.handler;

import com.umc.TheGoods.apiPayload.code.BaseErrorCode;
import com.umc.TheGoods.apiPayload.exception.GeneralException;

public class ReviewHandler extends GeneralException {
public ReviewHandler(BaseErrorCode code) {
super(code);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.umc.TheGoods.converter.review;

import com.umc.TheGoods.domain.enums.ReviewStatus;
import com.umc.TheGoods.domain.item.Review;
import com.umc.TheGoods.domain.order.OrderItem;
import com.umc.TheGoods.web.dto.review.ReviewResponseDTO;

import java.util.List;
import java.util.stream.Collectors;

public class ReviewConverter {

public static Review toReview(OrderItem orderItem, String text, Integer score) {
return Review.builder()
.text(text)
.score(score)
.orderItem(orderItem)
.status(ReviewStatus.SHOW)
.build();
}

public static ReviewResponseDTO.reviewPostDTO toReviewPostDTO(Review review) {
return ReviewResponseDTO.reviewPostDTO.builder()
.reviewId(review.getId())
.createdAt(review.getCreatedAt())
.itemName(review.getItem().getName())
.score(review.getScore())
.text(review.getText())
.optionStringList(ReviewConverter.toOptionStringList(review.getOrderItem()))
.build();
}

private static List<String> toOptionStringList(OrderItem orderItem) {
return orderItem.getOrderDetailList().stream().map(orderDetail -> {
return orderDetail.getItemOption().getName();
}).collect(Collectors.toList());
}
}
22 changes: 19 additions & 3 deletions src/main/java/com/umc/TheGoods/domain/item/Review.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.umc.TheGoods.domain.common.BaseDateTimeEntity;
import com.umc.TheGoods.domain.enums.ReviewStatus;
import com.umc.TheGoods.domain.images.ReviewImg;
import com.umc.TheGoods.domain.member.Member;
import com.umc.TheGoods.domain.order.OrderItem;
import lombok.*;
Expand Down Expand Up @@ -44,8 +43,25 @@ public class Review extends BaseDateTimeEntity {
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_item_id", nullable = false)
private OrderItem orderItem;
//
// @OneToOne(mappedBy = "review", cascade = CascadeType.ALL)
// private ReviewImg reviewImg;

@OneToOne(mappedBy = "review", cascade = CascadeType.ALL)
private ReviewImg reviewImg;
// 연관관계 메소드
public void setMember(Member member) {
if (this.member != null) {
this.member.getReviewList().remove(this);
}
this.member = member;
this.member.getReviewList().add(this);
}

public void setItem(Item item) {
if (this.item != null) {
this.item.getReviewList().remove(this);
}
this.item = item;
this.item.getReviewList().add(this);
}

}
5 changes: 2 additions & 3 deletions src/main/java/com/umc/TheGoods/domain/order/OrderItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.umc.TheGoods.domain.common.BaseDateTimeEntity;
import com.umc.TheGoods.domain.enums.OrderStatus;
import com.umc.TheGoods.domain.item.Item;
import com.umc.TheGoods.domain.item.Review;
import com.umc.TheGoods.domain.types.DeliveryType;
import com.umc.TheGoods.web.dto.order.OrderRequestDTO;
import lombok.*;
Expand Down Expand Up @@ -87,8 +86,8 @@ public class OrderItem extends BaseDateTimeEntity {
@OneToOne(mappedBy = "orderItem", cascade = CascadeType.ALL)
private OrderCancel orderCancel;

@OneToOne(mappedBy = "orderItem", cascade = CascadeType.ALL)
private Review review;
// @OneToOne(mappedBy = "orderItem", cascade = CascadeType.ALL)
// private Review review;

public void setOrders(Orders orders) {
if (this.orders != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.umc.TheGoods.repository.review;

import com.umc.TheGoods.domain.item.Review;
import com.umc.TheGoods.domain.order.OrderItem;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ReviewRepository extends JpaRepository<Review, Long> {

boolean existsByOrderItem(OrderItem orderItem);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.umc.TheGoods.service.ReviewService;

import com.umc.TheGoods.domain.item.Review;
import com.umc.TheGoods.domain.member.Member;
import com.umc.TheGoods.web.dto.review.ReviewRequestDTO;

public interface ReviewCommandService {

Review create(ReviewRequestDTO.addReviewDTO request, Member member);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.umc.TheGoods.service.ReviewService;

import com.umc.TheGoods.apiPayload.code.status.ErrorStatus;
import com.umc.TheGoods.apiPayload.exception.handler.OrderHandler;
import com.umc.TheGoods.apiPayload.exception.handler.ReviewHandler;
import com.umc.TheGoods.converter.review.ReviewConverter;
import com.umc.TheGoods.domain.item.Review;
import com.umc.TheGoods.domain.member.Member;
import com.umc.TheGoods.domain.order.OrderItem;
import com.umc.TheGoods.repository.order.OrderItemRepository;
import com.umc.TheGoods.repository.review.ReviewRepository;
import com.umc.TheGoods.web.dto.review.ReviewRequestDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional
public class ReviewCommandServiceImpl implements ReviewCommandService {

private final OrderItemRepository orderItemRepository;
private final ReviewRepository reviewRepository;

/**
* 리뷰 등록
*
* @param request
* @param member
* @return
*/
@Override
public Review create(ReviewRequestDTO.addReviewDTO request, Member member) {
// 해당 orderItem이 해당 회원의 것이 맞는지 검증
OrderItem orderItem = orderItemRepository.findById(request.getOrderItemId()).orElseThrow(() -> new OrderHandler(ErrorStatus.ORDER_ITEM_NOT_FOUND));
if (!orderItem.getOrders().getMember().equals(member)) {
throw new ReviewHandler(ErrorStatus.NOT_ORDER_OWNER);
}

// 이미 리뷰를 등록했던 orderItem인지 검증
boolean isExists = reviewRepository.existsByOrderItem(orderItem);
if (isExists) {
throw new ReviewHandler(ErrorStatus.REVIEW_ALREADY_EXISTS);
}

// review 엔티티 생성 및 연관관계 매핑
Review review = ReviewConverter.toReview(orderItem, request.getText(), request.getScore());
review.setMember(member);
review.setItem(orderItem.getItem());

return reviewRepository.save(review);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.umc.TheGoods.web.controller;

import com.umc.TheGoods.apiPayload.ApiResponse;
import com.umc.TheGoods.apiPayload.code.status.ErrorStatus;
import com.umc.TheGoods.apiPayload.exception.handler.MemberHandler;
import com.umc.TheGoods.converter.review.ReviewConverter;
import com.umc.TheGoods.domain.item.Review;
import com.umc.TheGoods.domain.member.Member;
import com.umc.TheGoods.service.MemberService.MemberQueryService;
import com.umc.TheGoods.service.ReviewService.ReviewCommandService;
import com.umc.TheGoods.web.dto.review.ReviewRequestDTO;
import com.umc.TheGoods.web.dto.review.ReviewResponseDTO;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@Slf4j
@Tag(name = "Review", description = "리뷰 관련 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/review")
public class ReviewController {
private final MemberQueryService memberQueryService;
private final ReviewCommandService reviewCommandService;

@PostMapping
public ApiResponse<ReviewResponseDTO.reviewPostDTO> addReview(@RequestBody @Valid ReviewRequestDTO.addReviewDTO request,
Authentication authentication) {
// 비회원인 경우 처리 불가
if (authentication == null) {
throw new MemberHandler(ErrorStatus._UNAUTHORIZED);
}

// request에서 member id 추출해 Member 엔티티 찾기
Member member = memberQueryService.findMemberById(Long.valueOf(authentication.getName().toString())).orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));

// 리뷰 등록
Review review = reviewCommandService.create(request, member);

return ApiResponse.onSuccess(ReviewConverter.toReviewPostDTO(review));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.umc.TheGoods.web.dto.review;

import lombok.Getter;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class ReviewRequestDTO {

@Getter
public static class addReviewDTO {
@NotNull
@Min(1)
@Max(5)
Integer score;

@NotNull
Long orderItemId;

@Size(max = 1500)
String text;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.umc.TheGoods.web.dto.review;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.List;

public class ReviewResponseDTO {
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class reviewPostDTO {
Long reviewId;
LocalDateTime createdAt;
String itemName;
@JsonInclude(JsonInclude.Include.NON_NULL)
List<String> optionStringList;
Integer score;
String text;
}
}

0 comments on commit 12e00e5

Please sign in to comment.