diff --git a/application/src/main/java/org/depromeet/spot/application/review/ReadReviewController.java b/application/src/main/java/org/depromeet/spot/application/review/ReadReviewController.java index e77be6c0..59b5007d 100644 --- a/application/src/main/java/org/depromeet/spot/application/review/ReadReviewController.java +++ b/application/src/main/java/org/depromeet/spot/application/review/ReadReviewController.java @@ -11,9 +11,11 @@ import org.depromeet.spot.application.review.dto.request.MyReviewRequest; import org.depromeet.spot.application.review.dto.response.BaseReviewResponse; import org.depromeet.spot.application.review.dto.response.BlockReviewListResponse; +import org.depromeet.spot.application.review.dto.response.MemberInfoOnMyReviewResponse; import org.depromeet.spot.application.review.dto.response.MyRecentReviewResponse; import org.depromeet.spot.application.review.dto.response.MyReviewListResponse; import org.depromeet.spot.application.review.dto.response.ReviewMonthsResponse; +import org.depromeet.spot.domain.review.Review.ReviewType; import org.depromeet.spot.domain.review.ReviewYearMonth; import org.depromeet.spot.usecase.port.in.review.ReadReviewUsecase; import org.depromeet.spot.usecase.port.in.review.ReadReviewUsecase.BlockReviewListResult; @@ -41,6 +43,7 @@ public class ReadReviewController { @GetMapping("/stadiums/{stadiumId}/blocks/{blockCode}/reviews") @Operation(summary = "특정 야구장의 특정 블록에 대한 리뷰 목록을 조회한다.") public BlockReviewListResponse findReviewsByBlockId( + @Parameter(hidden = true) Long memberId, @PathVariable("stadiumId") @NotNull @Positive @@ -52,6 +55,7 @@ public BlockReviewListResponse findReviewsByBlockId( BlockReviewListResult result = readReviewUsecase.findReviewsByStadiumIdAndBlockCode( + memberId, stadiumId, blockCode, request.rowNumber(), @@ -65,16 +69,38 @@ public BlockReviewListResponse findReviewsByBlockId( result, request.rowNumber(), request.seatNumber(), request.year(), request.month()); } + @CurrentMember + @ResponseStatus(HttpStatus.OK) + @GetMapping("/reviews/recentReview") + @Operation(summary = "자신이 작성한 가장 최근 리뷰 1개를 조회한다.") + public MyRecentReviewResponse findMyRecentReview(@Parameter(hidden = true) Long memberId) { + + MyRecentReviewResult result = readReviewUsecase.findLastReviewByMemberId(memberId); + return MyRecentReviewResponse.from(result); + } + @CurrentMember @ResponseStatus(HttpStatus.OK) @GetMapping("/reviews/months") @Operation(summary = "리뷰가 작성된 년도와 월 정보를 조회한다.") - public ReviewMonthsResponse findReviewMonths(@Parameter(hidden = true) Long memberId) { + public ReviewMonthsResponse findReviewMonths( + @Parameter(hidden = true) Long memberId, + @Parameter(description = "리뷰 타입: VIEW/FEED") ReviewType reviewType) { - List yearMonths = readReviewUsecase.findReviewMonths(memberId); + List yearMonths = readReviewUsecase.findReviewMonths(memberId, reviewType); return ReviewMonthsResponse.from(yearMonths); } + @CurrentMember + @ResponseStatus(HttpStatus.OK) + @GetMapping("/reviews/userInfo") + @Operation(summary = "사용자의 리뷰 관련 정보를 조회한다.") + public MemberInfoOnMyReviewResponse findMemberInfoOnMyReview( + @Parameter(hidden = true) Long memberId) { + return MemberInfoOnMyReviewResponse.from( + readReviewUsecase.findMemberInfoOnMyReview(memberId)); + } + @CurrentMember @ResponseStatus(HttpStatus.OK) @GetMapping("/reviews") @@ -92,20 +118,11 @@ public MyReviewListResponse findMyReviews( request.month(), request.cursor(), request.sortBy(), - request.size()); + request.size(), + request.reviewType()); return MyReviewListResponse.from(result, request.year(), request.month()); } - @CurrentMember - @ResponseStatus(HttpStatus.OK) - @GetMapping("/reviews/recentReview") - @Operation(summary = "자신이 작성한 가장 최근 리뷰 1개를 조회한다.") - public MyRecentReviewResponse findMyRecentReview(@Parameter(hidden = true) Long memberId) { - - MyRecentReviewResult result = readReviewUsecase.findLastReviewByMemberId(memberId); - return MyRecentReviewResponse.from(result); - } - @CurrentMember @ResponseStatus(HttpStatus.OK) @GetMapping("/reviews/{reviewId}") diff --git a/application/src/main/java/org/depromeet/spot/application/review/dto/request/MyReviewRequest.java b/application/src/main/java/org/depromeet/spot/application/review/dto/request/MyReviewRequest.java index 78f5a99e..9c2c7295 100644 --- a/application/src/main/java/org/depromeet/spot/application/review/dto/request/MyReviewRequest.java +++ b/application/src/main/java/org/depromeet/spot/application/review/dto/request/MyReviewRequest.java @@ -3,6 +3,7 @@ import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; +import org.depromeet.spot.domain.review.Review.ReviewType; import org.depromeet.spot.domain.review.Review.SortCriteria; import io.swagger.v3.oas.annotations.Parameter; @@ -12,4 +13,5 @@ public record MyReviewRequest( @Min(1) @Max(12) @Parameter(description = "월 (1-12)") Integer month, @Parameter(description = "다음 페이지 커서") String cursor, @Parameter(description = "정렬 기준", example = "DATE_TIME") SortCriteria sortBy, - @Parameter(description = "페이지 크기") Integer size) {} + @Parameter(description = "페이지 크기") Integer size, + @Parameter(description = "리뷰 타입: VIEW/FEED") ReviewType reviewType) {} diff --git a/application/src/main/java/org/depromeet/spot/application/review/dto/response/BaseReviewResponse.java b/application/src/main/java/org/depromeet/spot/application/review/dto/response/BaseReviewResponse.java index eb627771..21c816cb 100644 --- a/application/src/main/java/org/depromeet/spot/application/review/dto/response/BaseReviewResponse.java +++ b/application/src/main/java/org/depromeet/spot/application/review/dto/response/BaseReviewResponse.java @@ -29,7 +29,9 @@ public record BaseReviewResponse( List keywords, int likesCount, int scrapsCount, - ReviewType reviewType) { + ReviewType reviewType, + boolean isLiked, + boolean isScrapped) { public static BaseReviewResponse from(CreateReviewResult result) { Review review = result.review(); @@ -59,7 +61,9 @@ public static BaseReviewResponse from(CreateReviewResult result) { .toList(), review.getLikesCount(), review.getScrapsCount(), - review.getReviewType()); + review.getReviewType(), + review.isLiked(), + review.isScrapped()); } public static BaseReviewResponse from(Review review) { @@ -89,7 +93,9 @@ public static BaseReviewResponse from(Review review) { .collect(Collectors.toList()), review.getLikesCount(), review.getScrapsCount(), - review.getReviewType()); + review.getReviewType(), + review.isLiked(), + review.isScrapped()); } public record StadiumResponse(Long id, String name) { diff --git a/application/src/main/java/org/depromeet/spot/application/review/dto/response/MemberInfoOnMyReviewResponse.java b/application/src/main/java/org/depromeet/spot/application/review/dto/response/MemberInfoOnMyReviewResponse.java new file mode 100644 index 00000000..eec22fa3 --- /dev/null +++ b/application/src/main/java/org/depromeet/spot/application/review/dto/response/MemberInfoOnMyReviewResponse.java @@ -0,0 +1,31 @@ +package org.depromeet.spot.application.review.dto.response; + +import org.depromeet.spot.usecase.port.in.review.ReadReviewUsecase.MemberInfoOnMyReviewResult; + +import lombok.Builder; + +@Builder +public record MemberInfoOnMyReviewResponse( + Long userId, + String profileImageUrl, + Integer level, + String levelTitle, + String nickname, + Long reviewCount, + Long totalLikes, + Long teamId, + String teamName) { + public static MemberInfoOnMyReviewResponse from(MemberInfoOnMyReviewResult result) { + return MemberInfoOnMyReviewResponse.builder() + .userId(result.userId()) + .profileImageUrl(result.profileImageUrl()) + .level(result.level()) + .levelTitle(result.levelTitle()) + .nickname(result.nickname()) + .reviewCount(result.reviewCount()) + .totalLikes(result.totalLikes()) + .teamId(result.teamId()) + .teamName(result.teamName()) + .build(); + } +} diff --git a/application/src/main/java/org/depromeet/spot/application/review/dto/response/MyReviewListResponse.java b/application/src/main/java/org/depromeet/spot/application/review/dto/response/MyReviewListResponse.java index 60b8be64..4c75fdda 100644 --- a/application/src/main/java/org/depromeet/spot/application/review/dto/response/MyReviewListResponse.java +++ b/application/src/main/java/org/depromeet/spot/application/review/dto/response/MyReviewListResponse.java @@ -5,15 +5,10 @@ import org.depromeet.spot.application.review.dto.response.BlockReviewListResponse.BlockFilter; import org.depromeet.spot.domain.review.Review; -import org.depromeet.spot.usecase.port.in.review.ReadReviewUsecase.MemberInfoOnMyReviewResult; import org.depromeet.spot.usecase.port.in.review.ReadReviewUsecase.MyReviewListResult; public record MyReviewListResponse( - MemberInfoOnMyReviewResult memberInfoOnMyReview, - List reviews, - String nextCursor, - boolean hasNext, - BlockFilter filter) { + List reviews, String nextCursor, boolean hasNext, BlockFilter filter) { public static MyReviewListResponse from( MyReviewListResult result, Integer year, Integer month) { @@ -22,12 +17,7 @@ public static MyReviewListResponse from( result.reviews().stream().map(MyReviewResponse::from).collect(Collectors.toList()); BlockFilter filter = new BlockFilter(null, null, year, month); - return new MyReviewListResponse( - result.memberInfoOnMyReviewResult(), - reviews, - result.nextCursor(), - result.hasNext(), - filter); + return new MyReviewListResponse(reviews, result.nextCursor(), result.hasNext(), filter); } public record MyReviewResponse( diff --git a/application/src/main/java/org/depromeet/spot/application/review/scrap/ReviewScrapController.java b/application/src/main/java/org/depromeet/spot/application/review/scrap/ReviewScrapController.java index 72c72ae8..1d7af9ff 100644 --- a/application/src/main/java/org/depromeet/spot/application/review/scrap/ReviewScrapController.java +++ b/application/src/main/java/org/depromeet/spot/application/review/scrap/ReviewScrapController.java @@ -12,10 +12,8 @@ import org.depromeet.spot.usecase.port.in.review.scrap.ReviewScrapUsecase.MyScrapListResult; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; 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.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @@ -51,8 +49,8 @@ public boolean toggleScrap( description = "stadiumId, months, good, bad로 필터링 가능하다.") public MyScrapListResponse findMyReviews( @Parameter(hidden = true) Long memberId, - @RequestBody @Valid MyScrapRequest request, - @ModelAttribute @Valid PageRequest pageRequest) { + @Valid MyScrapRequest request, + @Valid PageRequest pageRequest) { MyScrapListResult result = reviewScrapUsecase.findMyScrappedReviews( diff --git a/domain/src/main/java/org/depromeet/spot/domain/review/Review.java b/domain/src/main/java/org/depromeet/spot/domain/review/Review.java index 4a20fb07..72b09683 100644 --- a/domain/src/main/java/org/depromeet/spot/domain/review/Review.java +++ b/domain/src/main/java/org/depromeet/spot/domain/review/Review.java @@ -52,6 +52,8 @@ public enum SortCriteria { public static final int DEFAULT_LIKE_COUNT = 0; public static final int DEFAULT_SCRAPS_COUNT = 0; + public boolean isLiked; + public boolean isScrapped; @Builder public Review( @@ -142,6 +144,11 @@ public void setDeletedAt(LocalDateTime now) { this.deletedAt = now; } + public void setLikedAndScrapped(boolean liked, boolean scraped) { + this.isLiked = liked; + this.isScrapped = scraped; + } + public Review withLimitedImages(int limit) { List limitedImages = this.images.stream().limit(limit).collect(Collectors.toList()); diff --git a/domain/src/main/java/org/depromeet/spot/domain/review/ReviewCount.java b/domain/src/main/java/org/depromeet/spot/domain/review/ReviewCount.java new file mode 100644 index 00000000..f46a4d8a --- /dev/null +++ b/domain/src/main/java/org/depromeet/spot/domain/review/ReviewCount.java @@ -0,0 +1,3 @@ +package org.depromeet.spot.domain.review; + +public record ReviewCount(long reviewCount, long totalLikes) {} diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewCustomRepository.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewCustomRepository.java index db7bb66c..e830e8e6 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewCustomRepository.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewCustomRepository.java @@ -86,13 +86,15 @@ public List findAllByUserId( Integer month, String cursor, SortCriteria sortBy, - int size) { + int size, + ReviewType reviewType) { BooleanBuilder builder = new BooleanBuilder(); builder.and(reviewEntity.member.id.eq(userId)); builder.and(eqYear(year)); builder.and(eqMonth(month)); builder.and(reviewEntity.deletedAt.isNull()); + builder.and(reviewEntity.reviewType.eq(reviewType)); OrderSpecifier[] orderBy = getOrderBy(sortBy); BooleanExpression cursorCondition = getCursorCondition(sortBy, cursor); diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewJpaRepository.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewJpaRepository.java index d70549d6..fbfe8c21 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewJpaRepository.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewJpaRepository.java @@ -3,6 +3,8 @@ import java.time.LocalDateTime; import java.util.List; +import org.depromeet.spot.domain.review.Review.ReviewType; +import org.depromeet.spot.domain.review.ReviewCount; import org.depromeet.spot.domain.review.ReviewYearMonth; import org.depromeet.spot.infrastructure.jpa.review.entity.ReviewEntity; import org.springframework.data.jpa.repository.JpaRepository; @@ -17,9 +19,20 @@ public interface ReviewJpaRepository extends JpaRepository { "SELECT new org.depromeet.spot.domain.review.ReviewYearMonth(YEAR(r.dateTime), MONTH(r.dateTime)) " + "FROM ReviewEntity r WHERE r.member.id = :memberId " + "AND r.deletedAt IS NULL " + + "AND r.reviewType = :reviewType " + "GROUP BY YEAR(r.dateTime), MONTH(r.dateTime) " + "ORDER BY YEAR(r.dateTime) DESC, MONTH(r.dateTime) DESC") - List findReviewMonthsByMemberId(@Param("memberId") Long memberId); + List findReviewMonthsByMemberId( + @Param("memberId") Long memberId, @Param("reviewType") ReviewType reviewType); + + @Query( + "SELECT new org.depromeet.spot.domain.review.ReviewCount(" + + "COUNT(r), " + + "COALESCE(SUM(CASE WHEN r.reviewType = :viewType THEN r.likesCount ELSE 0 END), 0)) " + + "FROM ReviewEntity r " + + "WHERE r.member.id = :memberId AND r.deletedAt IS NULL") + ReviewCount countAndSumLikesByMemberId( + @Param("memberId") Long memberId, @Param("viewType") ReviewType viewType); @Modifying @Query( diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewRepositoryImpl.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewRepositoryImpl.java index 07261aa3..f3d6ac3d 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewRepositoryImpl.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/ReviewRepositoryImpl.java @@ -7,6 +7,7 @@ import org.depromeet.spot.domain.review.Review; import org.depromeet.spot.domain.review.Review.ReviewType; import org.depromeet.spot.domain.review.Review.SortCriteria; +import org.depromeet.spot.domain.review.ReviewCount; import org.depromeet.spot.domain.review.ReviewYearMonth; import org.depromeet.spot.infrastructure.jpa.review.entity.ReviewEntity; import org.depromeet.spot.usecase.port.in.review.ReadReviewUsecase.LocationInfo; @@ -55,6 +56,11 @@ public long countByUserId(Long id) { return reviewJpaRepository.countByMemberIdAndDeletedAtIsNull(id); } + @Override + public ReviewCount countAndSumLikesByUserId(Long id) { + return reviewJpaRepository.countAndSumLikesByMemberId(id, ReviewType.VIEW); + } + @Override public List findByStadiumIdAndBlockCode( Long stadiumId, @@ -88,15 +94,17 @@ public List findAllByUserId( Integer month, String cursor, SortCriteria sortBy, - Integer size) { + Integer size, + ReviewType reviewType) { List reviewEntities = - reviewCustomRepository.findAllByUserId(userId, year, month, cursor, sortBy, size); + reviewCustomRepository.findAllByUserId( + userId, year, month, cursor, sortBy, size, reviewType); return reviewEntities.stream().map(ReviewEntity::toDomain).toList(); } @Override - public List findReviewMonthsByMemberId(Long memberId) { - return reviewJpaRepository.findReviewMonthsByMemberId(memberId); + public List findReviewMonthsByMemberId(Long memberId, ReviewType reviewType) { + return reviewJpaRepository.findReviewMonthsByMemberId(memberId, reviewType); } @Override diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/like/ReviewLikeJpaRepository.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/like/ReviewLikeJpaRepository.java index 64df3697..8b395305 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/like/ReviewLikeJpaRepository.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/like/ReviewLikeJpaRepository.java @@ -1,8 +1,12 @@ package org.depromeet.spot.infrastructure.jpa.review.repository.like; +import java.util.List; + import org.depromeet.spot.infrastructure.jpa.review.entity.like.ReviewLikeEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface ReviewLikeJpaRepository extends JpaRepository { @@ -12,4 +16,9 @@ public interface ReviewLikeJpaRepository extends JpaRepository findReviewIdsByMemberIdAndReviewIdIn( + @Param("memberId") Long memberId, @Param("reviewIds") List reviewIds); } diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/like/ReviewLikeRepositoryImpl.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/like/ReviewLikeRepositoryImpl.java index f0eb3b91..a0df4858 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/like/ReviewLikeRepositoryImpl.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/like/ReviewLikeRepositoryImpl.java @@ -1,5 +1,9 @@ package org.depromeet.spot.infrastructure.jpa.review.repository.like; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import org.depromeet.spot.domain.review.like.ReviewLike; import org.depromeet.spot.infrastructure.jpa.review.entity.like.ReviewLikeEntity; import org.depromeet.spot.usecase.port.out.review.ReviewLikeRepository; @@ -33,4 +37,12 @@ public void save(ReviewLike like) { ReviewLikeEntity entity = ReviewLikeEntity.from(like); reviewLikeJpaRepository.save(entity); } + + @Override + public Map existsByMemberIdAndReviewIds(Long memberId, List reviewIds) { + List likedReviewIds = + reviewLikeJpaRepository.findReviewIdsByMemberIdAndReviewIdIn(memberId, reviewIds); + return reviewIds.stream() + .collect(Collectors.toMap(reviewId -> reviewId, likedReviewIds::contains)); + } } diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapCustomRepository.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapCustomRepository.java index 78a41b7c..457c6f9f 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapCustomRepository.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapCustomRepository.java @@ -12,9 +12,9 @@ import org.depromeet.spot.infrastructure.jpa.review.entity.ReviewEntity; import org.springframework.stereotype.Repository; +import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; @@ -35,27 +35,28 @@ public List findScrappedReviewsByMemberId( SortCriteria sortBy, Integer size) { - JPAQuery query = - queryFactory - .selectDistinct(reviewEntity) - .from(reviewEntity) - .join(reviewScrapEntity) - .on(reviewScrapEntity.reviewId.eq(reviewEntity.id)) - .leftJoin(reviewKeywordEntity) - .on(reviewKeywordEntity.review.eq(reviewEntity)) - .leftJoin(keywordEntity) - .on(keywordEntity.id.eq(reviewKeywordEntity.keywordId)) - .where( - reviewScrapEntity.memberId.eq(memberId), - stadiumIdEq(stadiumId), - monthsIn(months), - keywordsIn(good, true), - keywordsIn(bad, false), - cursorCondition(cursor, sortBy)) - .orderBy(getOrderSpecifiers(sortBy)) - .limit(size); - - return query.fetch(); + BooleanBuilder builder = buildConditions(memberId, stadiumId, months, good, bad); + + OrderSpecifier[] orderBy = getOrderBy(sortBy); + BooleanExpression cursorCondition = getCursorCondition(sortBy, cursor); + + if (cursorCondition != null) { + builder.and(cursorCondition); + } + + return queryFactory + .selectDistinct(reviewEntity) + .from(reviewEntity) + .join(reviewScrapEntity) + .on(reviewScrapEntity.reviewId.eq(reviewEntity.id)) + .leftJoin(reviewKeywordEntity) + .on(reviewKeywordEntity.review.eq(reviewEntity)) + .leftJoin(keywordEntity) + .on(keywordEntity.id.eq(reviewKeywordEntity.keywordId)) + .where(builder) + .orderBy(orderBy) + .limit(size) + .fetch(); } public Long getTotalCount( @@ -65,6 +66,8 @@ public Long getTotalCount( List good, List bad) { + BooleanBuilder builder = buildConditions(memberId, stadiumId, months, good, bad); + return queryFactory .select(reviewEntity.countDistinct()) .from(reviewEntity) @@ -74,15 +77,27 @@ public Long getTotalCount( .on(reviewKeywordEntity.review.eq(reviewEntity)) .leftJoin(keywordEntity) .on(keywordEntity.id.eq(reviewKeywordEntity.keywordId)) - .where( - reviewScrapEntity.memberId.eq(memberId), - stadiumIdEq(stadiumId), - monthsIn(months), - keywordsIn(good, true), - keywordsIn(bad, false)) + .where(builder) .fetchOne(); } + private BooleanBuilder buildConditions( + Long memberId, + Long stadiumId, + List months, + List good, + List bad) { + BooleanBuilder builder = new BooleanBuilder(); + + builder.and(reviewScrapEntity.memberId.eq(memberId)); + builder.and(stadiumIdEq(stadiumId)); + builder.and(monthsIn(months)); + builder.and(keywordsIn(good, true)); + builder.and(keywordsIn(bad, false)); + + return builder; + } + private BooleanExpression stadiumIdEq(Long stadiumId) { return stadiumId != null ? reviewEntity.stadium.id.eq(stadiumId) : null; } @@ -101,29 +116,29 @@ private BooleanExpression keywordsIn(List keywords, boolean isPositive) return keywordEntity.content.in(keywords).and(keywordEntity.isPositive.eq(isPositive)); } - private BooleanExpression cursorCondition(String cursor, SortCriteria sortBy) { + private BooleanExpression getCursorCondition(SortCriteria sortBy, String cursor) { if (cursor == null) { return null; } String[] parts = cursor.split("_"); - if (parts.length != 3) { - return null; - } - LocalDateTime dateTime = LocalDateTime.parse(parts[0]); - Integer likesCount = Integer.parseInt(parts[1]); - Long id = Long.parseLong(parts[2]); + LocalDateTime dateTime; + Long id; switch (sortBy) { case LIKES_COUNT: + if (parts.length != 3) return null; + int likeCount = Integer.parseInt(parts[0]); + dateTime = LocalDateTime.parse(parts[1]); + id = Long.parseLong(parts[2]); return reviewEntity .likesCount - .lt(likesCount) + .lt(likeCount) .or( reviewEntity .likesCount - .eq(likesCount) + .eq(likeCount) .and( reviewEntity .dateTime @@ -137,6 +152,9 @@ private BooleanExpression cursorCondition(String cursor, SortCriteria sortBy) { id))))); case DATE_TIME: default: + if (parts.length != 2) return null; + dateTime = LocalDateTime.parse(parts[0]); + id = Long.parseLong(parts[1]); return reviewEntity .dateTime .lt(dateTime) @@ -144,7 +162,7 @@ private BooleanExpression cursorCondition(String cursor, SortCriteria sortBy) { } } - private OrderSpecifier[] getOrderSpecifiers(SortCriteria sortBy) { + private OrderSpecifier[] getOrderBy(SortCriteria sortBy) { switch (sortBy) { case LIKES_COUNT: return new OrderSpecifier[] { diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapJpaRepository.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapJpaRepository.java index 76f66944..db7838c9 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapJpaRepository.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapJpaRepository.java @@ -1,8 +1,12 @@ package org.depromeet.spot.infrastructure.jpa.review.repository.scrap; +import java.util.List; + import org.depromeet.spot.infrastructure.jpa.review.entity.scrap.ReviewScrapEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface ReviewScrapJpaRepository extends JpaRepository { long countByReviewId(long reviewId); @@ -11,4 +15,9 @@ public interface ReviewScrapJpaRepository extends JpaRepository findReviewIdsByMemberIdAndReviewIdIn( + @Param("memberId") Long memberId, @Param("reviewIds") List reviewIds); } diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapRepositoryImpl.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapRepositoryImpl.java index e889e708..fa1bf6ae 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapRepositoryImpl.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/review/repository/scrap/ReviewScrapRepositoryImpl.java @@ -1,6 +1,8 @@ package org.depromeet.spot.infrastructure.jpa.review.repository.scrap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import org.depromeet.spot.domain.review.Review; import org.depromeet.spot.domain.review.Review.SortCriteria; @@ -66,4 +68,12 @@ public void save(ReviewScrap scrap) { ReviewScrapEntity entity = ReviewScrapEntity.from(scrap); reviewScrapJpaRepository.save(entity); } + + @Override + public Map existsByMemberIdAndReviewIds(Long memberId, List reviewIds) { + List scrappedReviewIds = + reviewScrapJpaRepository.findReviewIdsByMemberIdAndReviewIdIn(memberId, reviewIds); + return reviewIds.stream() + .collect(Collectors.toMap(reviewId -> reviewId, scrappedReviewIds::contains)); + } } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/in/review/ReadReviewUsecase.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/review/ReadReviewUsecase.java index 18bdcfc8..4280f65b 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/in/review/ReadReviewUsecase.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/review/ReadReviewUsecase.java @@ -4,7 +4,9 @@ import org.depromeet.spot.domain.member.Member; import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.domain.review.Review.ReviewType; import org.depromeet.spot.domain.review.Review.SortCriteria; +import org.depromeet.spot.domain.review.ReviewCount; import org.depromeet.spot.domain.review.ReviewYearMonth; import lombok.Builder; @@ -12,6 +14,7 @@ public interface ReadReviewUsecase { BlockReviewListResult findReviewsByStadiumIdAndBlockCode( + Long memberId, Long stadiumId, String blockCode, Integer rowNumber, @@ -28,9 +31,12 @@ MyReviewListResult findMyReviewsByUserId( Integer month, String cursor, SortCriteria sortBy, - Integer size); + Integer size, + ReviewType reviewType); + + MemberInfoOnMyReviewResult findMemberInfoOnMyReview(Long memberId); - List findReviewMonths(Long memberId); + List findReviewMonths(Long memberId, ReviewType reviewType); MyRecentReviewResult findLastReviewByMemberId(Long memberId); @@ -73,30 +79,33 @@ record MemberInfoOnMyReviewResult( String levelTitle, String nickname, Long reviewCount, + Long totalLikes, Long teamId, String teamName) { - public static MemberInfoOnMyReviewResult of(Member member, long totalReviewCount) { + public static MemberInfoOnMyReviewResult of(Member member, ReviewCount reviewCount) { return MemberInfoOnMyReviewResult.builder() .userId(member.getId()) .profileImageUrl(member.getProfileImage()) .level(member.getLevel().getValue()) .levelTitle(member.getLevel().getTitle()) .nickname(member.getNickname()) - .reviewCount(totalReviewCount) + .reviewCount(reviewCount.reviewCount()) + .totalLikes(reviewCount.totalLikes()) .teamId(null) .teamName(null) .build(); } public static MemberInfoOnMyReviewResult of( - Member member, long totalReviewCount, String teamName) { + Member member, ReviewCount reviewCount, String teamName) { return MemberInfoOnMyReviewResult.builder() .userId(member.getId()) .profileImageUrl(member.getProfileImage()) .level(member.getLevel().getValue()) .levelTitle(member.getLevel().getTitle()) .nickname(member.getNickname()) - .reviewCount(totalReviewCount) + .reviewCount(reviewCount.reviewCount()) + .totalLikes(reviewCount.totalLikes()) .teamId(member.getTeamId()) .teamName(teamName) .build(); diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewLikeRepository.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewLikeRepository.java index 0dee4d21..41cf1dac 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewLikeRepository.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewLikeRepository.java @@ -1,5 +1,8 @@ package org.depromeet.spot.usecase.port.out.review; +import java.util.List; +import java.util.Map; + import org.depromeet.spot.domain.review.like.ReviewLike; public interface ReviewLikeRepository { @@ -11,4 +14,6 @@ public interface ReviewLikeRepository { void deleteBy(long memberId, long reviewId); void save(ReviewLike like); + + Map existsByMemberIdAndReviewIds(Long memberId, List reviewIds); } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewRepository.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewRepository.java index bf2de6dc..306a9b19 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewRepository.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewRepository.java @@ -3,7 +3,9 @@ import java.util.List; import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.domain.review.Review.ReviewType; import org.depromeet.spot.domain.review.Review.SortCriteria; +import org.depromeet.spot.domain.review.ReviewCount; import org.depromeet.spot.domain.review.ReviewYearMonth; import org.depromeet.spot.usecase.port.in.review.ReadReviewUsecase.LocationInfo; @@ -18,6 +20,8 @@ public interface ReviewRepository { long countByUserId(Long userId); + ReviewCount countAndSumLikesByUserId(Long id); + List findByStadiumIdAndBlockCode( Long stadiumId, String blockCode, @@ -35,9 +39,10 @@ List findAllByUserId( Integer month, String cursor, SortCriteria sortBy, - Integer size); + Integer size, + ReviewType reviewType); - List findReviewMonthsByMemberId(Long memberId); + List findReviewMonthsByMemberId(Long memberId, ReviewType reviewType); Long softDeleteByIdAndMemberId(Long reviewId, Long memberId); diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewScrapRepository.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewScrapRepository.java index 6adfa576..5cd5b7cd 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewScrapRepository.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/review/ReviewScrapRepository.java @@ -1,6 +1,7 @@ package org.depromeet.spot.usecase.port.out.review; import java.util.List; +import java.util.Map; import org.depromeet.spot.domain.review.Review; import org.depromeet.spot.domain.review.Review.SortCriteria; @@ -32,4 +33,6 @@ Long getTotalCount( void deleteBy(long memberId, long reviewId); void save(ReviewScrap like); + + Map existsByMemberIdAndReviewIds(Long memberId, List reviewIds); } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/ReadReviewService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/ReadReviewService.java index f183e309..520f2f60 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/ReadReviewService.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/ReadReviewService.java @@ -6,7 +6,9 @@ import org.depromeet.spot.domain.member.Member; import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.domain.review.Review.ReviewType; import org.depromeet.spot.domain.review.Review.SortCriteria; +import org.depromeet.spot.domain.review.ReviewCount; import org.depromeet.spot.domain.review.ReviewYearMonth; import org.depromeet.spot.domain.review.keyword.Keyword; import org.depromeet.spot.domain.review.keyword.ReviewKeyword; @@ -16,8 +18,12 @@ 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.ReviewImageRepository; +import org.depromeet.spot.usecase.port.out.review.ReviewLikeRepository; import org.depromeet.spot.usecase.port.out.review.ReviewRepository; +import org.depromeet.spot.usecase.port.out.review.ReviewScrapRepository; import org.depromeet.spot.usecase.port.out.team.BaseballTeamRepository; +import org.depromeet.spot.usecase.service.review.processor.PaginationProcessor; +import org.depromeet.spot.usecase.service.review.processor.ReadReviewProcessor; import org.depromeet.spot.usecase.service.util.MixpanelUtil; import org.depromeet.spot.usecase.service.util.MixpanelUtil.MixpanelEvent; import org.springframework.stereotype.Service; @@ -36,6 +42,10 @@ public class ReadReviewService implements ReadReviewUsecase { private final KeywordRepository keywordRepository; private final MemberRepository memberRepository; private final BaseballTeamRepository baseballTeamRepository; + private final ReviewLikeRepository reviewLikeRepository; + private final ReviewScrapRepository reviewScrapRepository; + private final ReadReviewProcessor readReviewProcessor; + private final PaginationProcessor paginationProcessor; private final MixpanelUtil mixpanelUtil; private static final int TOP_KEYWORDS_LIMIT = 5; @@ -43,6 +53,7 @@ public class ReadReviewService implements ReadReviewUsecase { @Override public BlockReviewListResult findReviewsByStadiumIdAndBlockCode( + Long memberId, Long stadiumId, String blockCode, Integer rowNumber, @@ -74,7 +85,10 @@ public BlockReviewListResult findReviewsByStadiumIdAndBlockCode( reviews = reviews.subList(0, size); } - String nextCursor = hasNext ? getCursor(reviews.get(reviews.size() - 1), sortBy) : null; + String nextCursor = + hasNext + ? paginationProcessor.getCursor(reviews.get(reviews.size() - 1), sortBy) + : null; // stadiumId랑 blockCode로 blockId를 조회 후 이걸 통해 topKeywords를 조회 List topKeywords = @@ -90,6 +104,9 @@ public BlockReviewListResult findReviewsByStadiumIdAndBlockCode( List reviewsWithKeywords = mapKeywordsToReviews(reviews); + // 유저의 리뷰 좋아요, 스크랩 여부 + readReviewProcessor.setLikedAndScrappedStatus(reviewsWithKeywords, memberId); + long totalElements = reviewRepository.countByStadiumIdAndBlockCode( stadiumId, blockCode, rowNumber, seatNumber, year, month); @@ -105,67 +122,67 @@ public BlockReviewListResult findReviewsByStadiumIdAndBlockCode( .build(); } + @Override + public MemberInfoOnMyReviewResult findMemberInfoOnMyReview(Long memberId) { + Member member = memberRepository.findById(memberId); + ReviewCount reviewCount = reviewRepository.countAndSumLikesByUserId(memberId); + + if (member.getTeamId() == null) { + return MemberInfoOnMyReviewResult.of(member, reviewCount); + } else { + BaseballTeam baseballTeam = baseballTeamRepository.findById(member.getTeamId()); + return MemberInfoOnMyReviewResult.of(member, reviewCount, baseballTeam.getName()); + } + } + @Override public MyReviewListResult findMyReviewsByUserId( - Long userId, + Long memberId, Integer year, Integer month, String cursor, SortCriteria sortBy, - Integer size) { + Integer size, + ReviewType reviewType) { + + if (reviewType == null) { + reviewType = ReviewType.VIEW; + } List reviews = - reviewRepository.findAllByUserId(userId, year, month, cursor, sortBy, size + 1); + reviewRepository.findAllByUserId( + memberId, year, month, cursor, sortBy, size + 1, reviewType); boolean hasNext = reviews.size() > size; if (hasNext) { reviews = reviews.subList(0, size); } - String nextCursor = hasNext ? getCursor(reviews.get(reviews.size() - 1), sortBy) : null; + String nextCursor = + hasNext + ? paginationProcessor.getCursor(reviews.get(reviews.size() - 1), sortBy) + : null; List reviewsWithKeywords = mapKeywordsToReviews(reviews); - Member member = memberRepository.findById(userId); - - MemberInfoOnMyReviewResult memberInfo; - if (member.getTeamId() == null) { - memberInfo = - MemberInfoOnMyReviewResult.of(member, reviewRepository.countByUserId(userId)); - - } else { - BaseballTeam baseballTeam = baseballTeamRepository.findById(member.getTeamId()); - - memberInfo = - MemberInfoOnMyReviewResult.of( - member, reviewRepository.countByUserId(userId), baseballTeam.getName()); + if (reviewType.equals(ReviewType.VIEW)) { + // 유저의 리뷰 좋아요, 스크랩 여부 + readReviewProcessor.setLikedAndScrappedStatus(reviewsWithKeywords, memberId); } return MyReviewListResult.builder() - .memberInfoOnMyReviewResult(memberInfo) .reviews(reviewsWithKeywords) .nextCursor(nextCursor) .hasNext(hasNext) .build(); } - public String getCursor(Review review, SortCriteria sortBy) { - switch (sortBy) { - case LIKES_COUNT: - return review.getLikesCount() - + "_" - + review.getDateTime().toString() - + "_" - + review.getId(); - case DATE_TIME: - default: - return review.getDateTime().toString() + "_" + review.getId(); - } - } - @Override - public List findReviewMonths(Long memberId) { - return reviewRepository.findReviewMonthsByMemberId(memberId); + public List findReviewMonths(Long memberId, ReviewType reviewType) { + if (reviewType == null) { + reviewType = ReviewType.VIEW; + } + return reviewRepository.findReviewMonthsByMemberId(memberId, reviewType); } @Override @@ -242,6 +259,8 @@ public Review mapKeywordsToSingleReview(Review review) { .images(review.getImages()) .keywords(mappedKeywords) .likesCount(review.getLikesCount()) + .scrapsCount(review.getScrapsCount()) + .reviewType(review.getReviewType()) .build(); mappedReview.setKeywordMap(keywordMap); @@ -287,6 +306,8 @@ public Review mapKeywordsToReview(Review review) { .images(review.getImages()) .keywords(mappedKeywords) // 리뷰 키워드 담당 .likesCount(review.getLikesCount()) + .scrapsCount(review.getScrapsCount()) + .reviewType(review.getReviewType()) .build(); // Keyword 정보를 Review 객체에 추가 @@ -295,4 +316,20 @@ public Review mapKeywordsToReview(Review review) { return mappedReview; } + + private void setLikedAndScrappedStatus(List reviews, Long memberId) { + List reviewIds = reviews.stream().map(Review::getId).collect(Collectors.toList()); + + Map likedMap = + reviewLikeRepository.existsByMemberIdAndReviewIds(memberId, reviewIds); + Map scrappedMap = + reviewScrapRepository.existsByMemberIdAndReviewIds(memberId, reviewIds); + + reviews.forEach( + review -> { + boolean isLiked = likedMap.getOrDefault(review.getId(), false); + boolean isScrapped = scrappedMap.getOrDefault(review.getId(), false); + review.setLikedAndScrapped(isLiked, isScrapped); + }); + } } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/PaginationProcessor.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/PaginationProcessor.java new file mode 100644 index 00000000..cb324843 --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/PaginationProcessor.java @@ -0,0 +1,9 @@ +package org.depromeet.spot.usecase.service.review.processor; + +import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.domain.review.Review.SortCriteria; + +public interface PaginationProcessor { + + String getCursor(Review review, SortCriteria sortBy); +} diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/PaginationProcessorImpl.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/PaginationProcessorImpl.java new file mode 100644 index 00000000..7907e6be --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/PaginationProcessorImpl.java @@ -0,0 +1,26 @@ +package org.depromeet.spot.usecase.service.review.processor; + +import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.domain.review.Review.SortCriteria; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +public class PaginationProcessorImpl implements PaginationProcessor { + + public String getCursor(Review review, SortCriteria sortBy) { + switch (sortBy) { + case LIKES_COUNT: + return review.getLikesCount() + + "_" + + review.getDateTime().toString() + + "_" + + review.getId(); + case DATE_TIME: + default: + return review.getDateTime().toString() + "_" + review.getId(); + } + } +} diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReadReviewProcessor.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReadReviewProcessor.java new file mode 100644 index 00000000..0ff738b3 --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReadReviewProcessor.java @@ -0,0 +1,10 @@ +package org.depromeet.spot.usecase.service.review.processor; + +import java.util.List; + +import org.depromeet.spot.domain.review.Review; + +public interface ReadReviewProcessor { + + void setLikedAndScrappedStatus(List reviews, Long memberId); +} diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReadReviewProcessorImpl.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReadReviewProcessorImpl.java new file mode 100644 index 00000000..94a5fc81 --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReadReviewProcessorImpl.java @@ -0,0 +1,36 @@ +package org.depromeet.spot.usecase.service.review.processor; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.usecase.port.out.review.ReviewLikeRepository; +import org.depromeet.spot.usecase.port.out.review.ReviewScrapRepository; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +public class ReadReviewProcessorImpl implements ReadReviewProcessor { + + private final ReviewLikeRepository reviewLikeRepository; + private final ReviewScrapRepository reviewScrapRepository; + + public void setLikedAndScrappedStatus(List reviews, Long memberId) { + List reviewIds = reviews.stream().map(Review::getId).collect(Collectors.toList()); + + Map likedMap = + reviewLikeRepository.existsByMemberIdAndReviewIds(memberId, reviewIds); + Map scrappedMap = + reviewScrapRepository.existsByMemberIdAndReviewIds(memberId, reviewIds); + + reviews.forEach( + review -> { + boolean isLiked = likedMap.getOrDefault(review.getId(), false); + boolean isScrapped = scrappedMap.getOrDefault(review.getId(), false); + review.setLikedAndScrapped(isLiked, isScrapped); + }); + } +} diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/scrap/ReviewScrapService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/scrap/ReviewScrapService.java index 6c9718fc..73a1ca0b 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/scrap/ReviewScrapService.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/scrap/ReviewScrapService.java @@ -10,6 +10,8 @@ import org.depromeet.spot.usecase.port.in.review.scrap.ReviewScrapUsecase; import org.depromeet.spot.usecase.port.out.review.ReviewScrapRepository; import org.depromeet.spot.usecase.service.review.ReadReviewService; +import org.depromeet.spot.usecase.service.review.processor.PaginationProcessor; +import org.depromeet.spot.usecase.service.review.processor.ReadReviewProcessor; import org.depromeet.spot.usecase.service.util.MixpanelUtil; import org.depromeet.spot.usecase.service.util.MixpanelUtil.MixpanelEvent; import org.springframework.stereotype.Service; @@ -26,6 +28,8 @@ public class ReviewScrapService implements ReviewScrapUsecase { private final UpdateReviewUsecase updateReviewUsecase; private final ReviewScrapRepository scrapRepository; private final ReadReviewService readReviewService; + private final ReadReviewProcessor readReviewProcessor; + private final PaginationProcessor paginationProcessor; private final MixpanelUtil mixpanelUtil; @Override @@ -50,12 +54,15 @@ public MyScrapListResult findMyScrappedReviews( String nextCursor = hasNext - ? readReviewService.getCursor( + ? paginationProcessor.getCursor( reviews.get(reviews.size() - 1), pageCommand.sortBy()) : null; List reviewsWithKeywords = readReviewService.mapKeywordsToReviews(reviews); + // 유저의 리뷰 좋아요, 스크랩 여부 + readReviewProcessor.setLikedAndScrappedStatus(reviewsWithKeywords, memberId); + Long totalScrapCount = scrapRepository.getTotalCount( memberId, diff --git a/usecase/src/test/java/org/depromeet/spot/usecase/service/fake/FakeReviewScrapRepository.java b/usecase/src/test/java/org/depromeet/spot/usecase/service/fake/FakeReviewScrapRepository.java index 6da0937f..21f29492 100644 --- a/usecase/src/test/java/org/depromeet/spot/usecase/service/fake/FakeReviewScrapRepository.java +++ b/usecase/src/test/java/org/depromeet/spot/usecase/service/fake/FakeReviewScrapRepository.java @@ -3,6 +3,7 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import org.depromeet.spot.domain.review.Review; @@ -90,6 +91,11 @@ public void save(ReviewScrap scrap) { scraps.add(scrap); } + @Override + public Map existsByMemberIdAndReviewIds(Long memberId, List reviewIds) { + return Map.of(); + } + public void addReview(Review review) { reviews.add(review); } diff --git a/usecase/src/test/java/org/depromeet/spot/usecase/service/review/ReviewScrapServiceTest.java b/usecase/src/test/java/org/depromeet/spot/usecase/service/review/ReviewScrapServiceTest.java index f6c5b7e4..458de70f 100644 --- a/usecase/src/test/java/org/depromeet/spot/usecase/service/review/ReviewScrapServiceTest.java +++ b/usecase/src/test/java/org/depromeet/spot/usecase/service/review/ReviewScrapServiceTest.java @@ -19,6 +19,8 @@ import org.depromeet.spot.usecase.port.in.review.scrap.ReviewScrapUsecase.MyScrapCommand; import org.depromeet.spot.usecase.port.in.review.scrap.ReviewScrapUsecase.MyScrapListResult; import org.depromeet.spot.usecase.service.fake.FakeReviewScrapRepository; +import org.depromeet.spot.usecase.service.review.processor.PaginationProcessor; +import org.depromeet.spot.usecase.service.review.processor.ReadReviewProcessor; import org.depromeet.spot.usecase.service.review.scrap.ReviewScrapService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -33,6 +35,8 @@ class ReviewScrapServiceTest { @Mock private ReadReviewUsecase readReviewUsecase; @Mock private UpdateReviewUsecase updateReviewUsecase; @Mock private ReadReviewService readReviewService; + @Mock private ReadReviewProcessor readReviewProcessor; + @Mock private PaginationProcessor paginationProcessor; @BeforeEach void init() { @@ -43,7 +47,9 @@ void init() { readReviewUsecase, updateReviewUsecase, fakeReviewScrapRepository, - readReviewService); + readReviewService, + readReviewProcessor, + paginationProcessor); } @Test