Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public DataResponse<ReviewHelpfulResponse> toggleHelpful(
@PathVariable Long reviewId,
@AuthenticationPrincipal Long userId
) {
ReviewHelpfulResponse response = reviewQueryService.toggleHelpful(reviewId, userId);
ReviewHelpfulResponse response = reviewCommandService.toggleHelpful(reviewId, userId);
return DataResponse.from(response);
}

Expand Down
10 changes: 0 additions & 10 deletions src/main/java/com/ongil/backend/domain/review/entity/Review.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,6 @@ public class Review extends BaseEntity {
@JoinColumn(name = "product_id", nullable = false)
private Product product;

public void incrementHelpfulCount() {
this.helpfulCount++;
}

public void decrementHelpfulCount() {
if (this.helpfulCount > 0) {
this.helpfulCount--;
}
}

public void updateStep1(int rating, SizeAnswer sizeAnswer, ColorAnswer colorAnswer, MaterialAnswer materialAnswer) {
this.rating = rating;
this.sizeAnswer = sizeAnswer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -17,8 +16,6 @@
import com.ongil.backend.domain.review.enums.ReviewStatus;
import com.ongil.backend.domain.review.enums.ReviewType;

import jakarta.persistence.LockModeType;

public interface ReviewRepository extends JpaRepository<Review, Long> {

// 상품별 리뷰 목록 조회 (필터 없음)
Expand Down Expand Up @@ -189,9 +186,13 @@ List<Long> findReviewedOrderItemIds(
@Param("reviewType") ReviewType reviewType
);

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT r FROM Review r WHERE r.id = :reviewId")
Optional<Review> findByIdWithLock(@Param("reviewId") Long reviewId);
@Modifying(clearAutomatically = true)
@Query("UPDATE Review r SET r.helpfulCount = r.helpfulCount + 1 WHERE r.id = :reviewId")
void incrementHelpfulCount(@Param("reviewId") Long reviewId);

@Modifying(clearAutomatically = true)
@Query("UPDATE Review r SET r.helpfulCount = r.helpfulCount - 1 WHERE r.id = :reviewId AND r.helpfulCount > 0")
void decrementHelpfulCount(@Param("reviewId") Long reviewId);

@Modifying
@Query("DELETE FROM Review r WHERE r.reviewStatus = 'DRAFT' AND r.createdAt < :threshold")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
import com.ongil.backend.domain.review.dto.request.ReviewStep2MaterialRequest;
import com.ongil.backend.domain.review.dto.request.ReviewStep2SizeRequest;
import com.ongil.backend.domain.review.dto.response.AiReviewResponse;
import com.ongil.backend.domain.review.dto.response.ReviewHelpfulResponse;
import com.ongil.backend.domain.review.dto.response.ReviewStep1Response;
import com.ongil.backend.domain.review.entity.Review;
import com.ongil.backend.domain.review.entity.ReviewHelpful;
import com.ongil.backend.domain.review.enums.ClothingCategory;
import com.ongil.backend.domain.review.enums.MaterialAnswer;
import com.ongil.backend.domain.review.enums.MaterialFeatureType;
import com.ongil.backend.domain.review.enums.ReviewStatus;
import com.ongil.backend.domain.review.enums.ReviewType;
import com.ongil.backend.domain.review.repository.ReviewHelpfulRepository;
import com.ongil.backend.domain.review.repository.ReviewRepository;
import com.ongil.backend.domain.review.validator.ReviewValidator;
import com.ongil.backend.domain.user.entity.User;
Expand All @@ -42,6 +45,7 @@ public class ReviewCommandService {
private static final int REVIEW_REWARD_POINTS = 500;

private final ReviewRepository reviewRepository;
private final ReviewHelpfulRepository reviewHelpfulRepository;
private final UserRepository userRepository;
private final OrderItemRepository orderItemRepository;
private final ProductRepository productRepository;
Expand Down Expand Up @@ -177,6 +181,36 @@ public void submitReview(Long userId, Long reviewId, ReviewFinalSubmitRequest re
productRepository.updateReviewStats(review.getProduct().getId());
}

public ReviewHelpfulResponse toggleHelpful(Long reviewId, Long userId) {
Review review = reviewRepository.findById(reviewId)
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.REVIEW_NOT_FOUND));

boolean exists = reviewHelpfulRepository.existsByReviewIdAndUserId(reviewId, userId);

if (exists) {
reviewHelpfulRepository.deleteByReviewIdAndUserId(reviewId, userId);
reviewRepository.decrementHelpfulCount(reviewId);
} else {
User user = getUserOrThrow(userId);
ReviewHelpful helpful = ReviewHelpful.builder()
.review(review)
.user(user)
.build();
reviewHelpfulRepository.save(helpful);
reviewRepository.incrementHelpfulCount(reviewId);
}

int updatedCount = exists
? Math.max(0, review.getHelpfulCount() - 1)
: review.getHelpfulCount() + 1;

return ReviewHelpfulResponse.builder()
.reviewId(reviewId)
.isHelpful(!exists)
.helpfulCount(updatedCount)
.build();
}

private Review getReviewOrThrow(Long reviewId) {
return reviewRepository.findById(reviewId)
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.REVIEW_NOT_FOUND));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import com.ongil.backend.domain.review.dto.request.ReviewListRequest;
import com.ongil.backend.domain.review.dto.response.*;
import com.ongil.backend.domain.review.entity.Review;
import com.ongil.backend.domain.review.entity.ReviewHelpful;
import com.ongil.backend.domain.review.enums.ColorAnswer;
import com.ongil.backend.domain.review.enums.MaterialAnswer;
import com.ongil.backend.domain.review.enums.ReviewSortType;
Expand Down Expand Up @@ -215,36 +214,6 @@ public int getPendingReviewCount(Long userId) {
return count;
}

// 6. 리뷰 도움돼요 토글
@Transactional
public ReviewHelpfulResponse toggleHelpful(Long reviewId, Long userId) {
// 리뷰에 대한 PESSIMISTIC WRITE 락 획득
Review review = reviewRepository.findByIdWithLock(reviewId)
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.REVIEW_NOT_FOUND));

User user = getUserOrThrow(userId);

boolean exists = reviewHelpfulRepository.existsByReviewIdAndUserId(reviewId, userId);

if (exists) {
reviewHelpfulRepository.deleteByReviewIdAndUserId(reviewId, userId);
review.decrementHelpfulCount();
} else {
ReviewHelpful helpful = ReviewHelpful.builder()
.review(review)
.user(user)
.build();
reviewHelpfulRepository.save(helpful);
review.incrementHelpfulCount();
}

return ReviewHelpfulResponse.builder()
.reviewId(reviewId)
.isHelpful(!exists)
.helpfulCount(review.getHelpfulCount())
.build();
}

// 정렬 기준에 따른 Pageable 생성
private Pageable createPageable(int page, int size, ReviewSortType sortType) {
if (size <= 0) size = 10;
Expand Down