Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BSVR-257] 리뷰 수정 API 업데이트 - 요청 필드 추가, nullable 처리 #185

Merged
merged 12 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -10,27 +10,34 @@

import org.depromeet.spot.common.exception.review.ReviewException.InvalidReviewDateTimeFormatException;
import org.depromeet.spot.common.exception.review.ReviewException.InvalidReviewKeywordsException;
import org.depromeet.spot.domain.review.Review.ReviewType;
import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase.UpdateReviewCommand;

public record UpdateReviewRequest(
@NotNull Long stadiumId,
@NotNull Long blockId,
@NotNull Integer seatNumber,
Integer rowNumber,
Integer seatNumber,
@Size(min = 1, max = 3) List<String> images,
List<String> good,
List<String> bad,
String content,
@NotNull String dateTime) {
@NotNull String dateTime,
ReviewType reviewType) {

public UpdateReviewCommand toCommand() {
validateGoodAndBad();
return UpdateReviewCommand.builder()
.stadiumId(stadiumId)
.blockId(blockId)
.rowNumber(rowNumber)
.seatNumber(seatNumber)
.images(images)
.good(good)
.bad(bad)
.content(content)
.dateTime(toLocalDateTime(dateTime))
.reviewType(reviewType)
.build();
}

Expand Down
2 changes: 1 addition & 1 deletion application/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ server:
spring:
# 서브모듈 profile
profiles:
active: dev
active: local
group:
local:
- jpa
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.depromeet.spot.domain.review;

import org.depromeet.spot.domain.block.Block;
import org.depromeet.spot.domain.block.BlockRow;
import org.depromeet.spot.domain.seat.Seat;
import org.depromeet.spot.domain.section.Section;

public record ReviewLocationInfo(Section section, Block block, BlockRow row, Seat seat) {}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface BlockRowJpaRepository extends JpaRepository<BlockRowEntity, Lon
"select r from BlockRowEntity r "
+ "join fetch r.block b "
+ "where b.stadiumId = :stadiumId and b.code = :blockCode and r.number = :rowNumber")
BlockRowEntity findByBlockAndNumber(
BlockRowEntity findByCodeAndNumber(
@Param("stadiumId") Long stadiumId,
@Param("blockCode") String blockCode,
@Param("rowNumber") int rowNumber);
Expand All @@ -28,4 +28,6 @@ BlockRowEntity findByBlockAndNumber(
+ "order by r.number asc")
List<BlockRowEntity> findAllByStadiumAndBlock(
@Param("stadiumId") Long stadiumId, @Param("code") String code);

BlockRowEntity findByBlockIdAndNumber(Long blockId, Integer number);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ public List<BlockRow> findAllByBlock(Long blockId) {
@Override
public BlockRow findBy(long stadiumId, String blockCode, int rowNumber) {
BlockRowEntity entity =
blockRowJpaRepository.findByBlockAndNumber(stadiumId, blockCode, rowNumber);
blockRowJpaRepository.findByCodeAndNumber(stadiumId, blockCode, rowNumber);
return entity.toDomain();
}

@Override
public BlockRow findBy(Long blockId, Integer rowNumber) {
BlockRowEntity entity = blockRowJpaRepository.findByBlockIdAndNumber(blockId, rowNumber);
return entity.toDomain();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ public Seat findById(Long seatId) {
}

@Override
public Seat findByIdWith(Long seatId) {
public Seat findByBlockIdAndSeatNumber(Long seatId) {
SeatEntity entity =
seatJpaRepository.findByIdWith(seatId).orElseThrow(SeatNotFoundException::new);
return entity.toDomain();
}

@Override
public Seat findByIdWith(Long blockId, Integer seatNumber) {
public Seat findByBlockIdAndSeatNumber(Long blockId, Integer seatNumber) {
SeatEntity entity =
seatJpaRepository
.findByIdWith(blockId, seatNumber)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.List;

import org.depromeet.spot.domain.review.Review;
import org.depromeet.spot.domain.review.Review.ReviewType;

import lombok.Builder;

Expand All @@ -16,13 +17,16 @@ public interface UpdateReviewUsecase {

@Builder
record UpdateReviewCommand(
Long stadiumId,
Long blockId,
Integer rowNumber,
Integer seatNumber,
List<String> images,
List<String> good,
List<String> bad,
String content,
LocalDateTime dateTime) {}
LocalDateTime dateTime,
ReviewType reviewType) {}

record UpdateReviewResult(Review review) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ public interface BlockRowRepository {
List<BlockRow> findAllByBlock(Long blockId);

BlockRow findBy(long stadiumId, String blockCode, int rowNumber);

BlockRow findBy(Long blockId, Integer rowNumber);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public interface SeatRepository {

Seat findById(Long seatId);

Seat findByIdWith(Long seatId);
Seat findByBlockIdAndSeatNumber(Long seatId);

Seat findByIdWith(Long blockId, Integer seatNumber);
Seat findByBlockIdAndSeatNumber(Long blockId, Integer seatNumber);

Map<BlockRow, List<Seat>> findSeatsGroupByRowInBlock(Block block);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.depromeet.spot.usecase.service.review;

import java.util.List;
import java.util.Map;

import org.depromeet.spot.domain.member.Member;
Expand Down Expand Up @@ -41,7 +40,8 @@ public CreateReviewResult create(Long blockId, Long memberId, CreateReviewComman

Review review = reviewCreationProcessor.createReview(blockId, member, command);

Map<Long, Keyword> keywordMap = processReviewDetails(review, command);
Map<Long, Keyword> keywordMap =
reviewCreationProcessor.processReviewDetails(review, command);

Review savedReview = reviewRepository.save(review);
reviewKeywordProcessor.updateBlockTopKeywords(savedReview);
Expand Down Expand Up @@ -69,30 +69,13 @@ public void createAdmin(
reviewCreationProcessor.createAdminReview(
stadiumId, blockCode, rowNumber, member, command);

Map<Long, Keyword> keywordMap = processAdminReviewDetails(review, command);
Map<Long, Keyword> keywordMap =
reviewCreationProcessor.processAdminReviewDetails(review, command);

Review savedReview = reviewRepository.save(review);
reviewKeywordProcessor.updateBlockTopKeywords(savedReview);
savedReview.setKeywordMap(keywordMap);

memberLevelProcessor.calculateAndUpdateMemberLevel(member);
}

private Map<Long, Keyword> processReviewDetails(Review review, CreateReviewCommand command) {
Map<Long, Keyword> keywordMap =
reviewKeywordProcessor.processKeywords(review, command.good(), command.bad());
review.setKeywordMap(keywordMap);
reviewImageProcessor.processImages(review, command.images());
return keywordMap;
}

private Map<Long, Keyword> processAdminReviewDetails(
Review review, CreateAdminReviewCommand command) {
Map<Long, Keyword> keywordMap =
reviewKeywordProcessor.processKeywords(review, command.good(), command.bad());
review.setKeywordMap(keywordMap);
List<String> imageUrls = reviewImageProcessor.getImageUrl(command.images());
reviewImageProcessor.processImages(review, imageUrls);
return keywordMap;
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
package org.depromeet.spot.usecase.service.review;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.depromeet.spot.common.exception.review.ReviewException.UnauthorizedReviewModificationException;
import org.depromeet.spot.domain.member.Member;
import org.depromeet.spot.domain.review.Review;
import org.depromeet.spot.domain.review.image.ReviewImage;
import org.depromeet.spot.domain.review.keyword.Keyword;
import org.depromeet.spot.domain.review.keyword.ReviewKeyword;
import org.depromeet.spot.domain.seat.Seat;
import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase;
import org.depromeet.spot.usecase.port.out.review.BlockTopKeywordRepository;
import org.depromeet.spot.usecase.port.out.review.KeywordRepository;
import org.depromeet.spot.usecase.port.out.review.ReviewRepository;
import org.depromeet.spot.usecase.port.out.seat.SeatRepository;
import org.depromeet.spot.usecase.service.review.processor.ReviewCreationProcessor;
import org.depromeet.spot.usecase.service.review.processor.ReviewDataProcessor;
import org.depromeet.spot.usecase.service.review.processor.ReviewKeywordProcessor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -33,33 +25,28 @@
public class UpdateReviewService implements UpdateReviewUsecase {

private final ReviewRepository reviewRepository;
private final SeatRepository seatRepository;
private final KeywordRepository keywordRepository;
private final BlockTopKeywordRepository blockTopKeywordRepository;
private final ReviewDataProcessor reviewDataProcessor;
private final ReviewKeywordProcessor reviewKeywordProcessor;
private final ReviewCreationProcessor reviewCreationProcessor;

public UpdateReviewResult updateReview(
Long memberId, Long reviewId, UpdateReviewCommand command) {
// 1. review id로 조회
Review existingReview = reviewRepository.findById(reviewId);

if (!existingReview.getMember().getId().equals(memberId)) {
throw new UnauthorizedReviewModificationException();
}

Member member = existingReview.getMember();
Seat seat = seatRepository.findByIdWith(command.blockId(), command.seatNumber());

// 새로운 Review 객체 생성
Review updatedReview = createUpdatedReview(reviewId, member, seat, command, existingReview);
// 2. 새로운 Review 객체 생성
Review updatedReview = reviewCreationProcessor.updateReviewData(existingReview, command);

// keyword와 image 처리
Map<Long, Keyword> keywordMap =
processKeywords(updatedReview, command.good(), command.bad());
processImages(updatedReview, command.images());
reviewCreationProcessor.processReviewDetails(updatedReview, command);

// 저장 및 blockTopKeyword 업데이트
Review savedReview = reviewRepository.save(updatedReview);
updateBlockTopKeywords(existingReview, savedReview);

reviewKeywordProcessor.updateBlockTopKeywords(existingReview, savedReview);
savedReview.setKeywordMap(keywordMap);

return new UpdateReviewResult(savedReview);
Expand All @@ -74,86 +61,4 @@ public void updateLikesCount(Review review) {
public void updateScrapsCount(Review review) {
reviewRepository.updateScrapsCount(review.getId(), review.getScrapsCount());
}

private Review createUpdatedReview(
Long reviewId,
Member member,
Seat seat,
UpdateReviewCommand command,
Review savedReview) {
return Review.builder()
.id(reviewId)
.member(member)
.stadium(seat.getStadium())
.section(seat.getSection())
.block(seat.getBlock())
.row(seat.getRow())
.seat(seat)
.dateTime(command.dateTime())
.content(command.content())
.likesCount(savedReview.getLikesCount())
.build();
}

private Map<Long, Keyword> processKeywords(
Review review, List<String> goodKeywords, List<String> badKeywords) {
Map<Long, Keyword> keywordMap = new HashMap<>();
processKeywordList(review, goodKeywords, true, keywordMap);
processKeywordList(review, badKeywords, false, keywordMap);

return keywordMap;
}

private void processKeywordList(
Review review,
List<String> keywordContents,
boolean isPositive,
Map<Long, Keyword> keywordMap) {
for (String content : keywordContents) {
Keyword keyword =
keywordRepository
.findByContent(content)
.orElseGet(
() ->
keywordRepository.save(
Keyword.create(null, content, isPositive)));

ReviewKeyword reviewKeyword = ReviewKeyword.create(null, keyword.getId());
review.addKeyword(reviewKeyword);
keywordMap.put(keyword.getId(), keyword);
}
}

private void processImages(Review review, List<String> imageUrls) {
for (String url : imageUrls) {
ReviewImage image = ReviewImage.create(null, review, url);
review.addImage(image);
}
}

private void updateBlockTopKeywords(Review oldReview, Review newReview) {
Set<Long> oldKeywordIds =
oldReview.getKeywords().stream()
.map(ReviewKeyword::getKeywordId)
.collect(Collectors.toSet());
Set<Long> newKeywordIds =
newReview.getKeywords().stream()
.map(ReviewKeyword::getKeywordId)
.collect(Collectors.toSet());

List<Long> decrementIds =
oldKeywordIds.stream()
.filter(id -> !newKeywordIds.contains(id))
.collect(Collectors.toList());

List<Long> incrementIds =
newKeywordIds.stream()
.filter(id -> !oldKeywordIds.contains(id))
.collect(Collectors.toList());

if (!decrementIds.isEmpty() || !incrementIds.isEmpty()) {
blockTopKeywordRepository.batchUpdateCounts(
newReview.getBlock().getId(), incrementIds, decrementIds);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package org.depromeet.spot.usecase.service.review.processor;

import java.util.Map;

import org.depromeet.spot.domain.member.Member;
import org.depromeet.spot.domain.review.Review;
import org.depromeet.spot.domain.review.keyword.Keyword;
import org.depromeet.spot.usecase.port.in.review.CreateReviewUsecase.CreateAdminReviewCommand;
import org.depromeet.spot.usecase.port.in.review.CreateReviewUsecase.CreateReviewCommand;
import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase.UpdateReviewCommand;

public interface ReviewCreationProcessor {
Review createReview(Long blockId, Member member, CreateReviewCommand command);
Expand All @@ -14,4 +18,12 @@ Review createAdminReview(
int rowNumber,
Member member,
CreateAdminReviewCommand command);

Map<Long, Keyword> processReviewDetails(Review review, CreateReviewCommand command);

Map<Long, Keyword> processReviewDetails(Review review, UpdateReviewCommand command);

Map<Long, Keyword> processAdminReviewDetails(Review review, CreateAdminReviewCommand command);

Review updateReviewData(Review existingReview, UpdateReviewCommand command);
}
Loading
Loading