From c8eec6d91f1a9ae6c7658c366245982e0afe8c16 Mon Sep 17 00:00:00 2001 From: yunyoung1819 Date: Mon, 5 Sep 2022 15:36:36 +0900 Subject: [PATCH 1/2] =?UTF-8?q?:recycle:=20[refactor]=20=ED=83=91=EC=8A=B9?= =?UTF-8?q?=20=ED=95=98=EC=B0=A8=20API=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20(Recommendation=EC=9D=84=20WebtoonStatus=EB=A1=9C?= =?UTF-8?q?=20=EB=8F=84=EB=A9=94=EC=9D=B8=EB=AA=85=EC=9D=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=ED=95=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/sql/DDL.sql | 4 +- .../RecommendationDailyJob.java | 15 ----- .../WebtoonStatusBatchScheduler.java} | 8 +-- .../webtoonstatus/WebtoonStatusDailyJob.java | 15 +++++ .../facade/CharacterHistoryFacade.java | 2 +- .../java/kr/co/antoon/coin/AntCoinClient.java | 3 - .../coin/application/AntCoinService.java | 6 +- .../antoon/coin/domain/vo/RemittanceType.java | 4 +- .../kr/co/antoon/common/dto/SwaggerNote.java | 12 ++-- .../antoon/criteria/BasicAllocateScore.java | 6 +- .../criteria/ScoreAllocationCriteria.java | 10 +-- .../kr/co/antoon/error/dto/ErrorMessage.java | 2 +- .../AlreadyJoinedException.java | 2 +- .../AlreadyLeavedException.java | 2 +- .../antoon/graph/facade/GraphScoreFacade.java | 22 +++---- .../RecommendationCountService.java | 31 ---------- .../application/RecommendationService.java | 36 ----------- .../dto/response/RecommendationResponse.java | 34 ---------- .../facade/RecommendationFacade.java | 62 ------------------- .../RecommendationCountRepository.java | 12 ---- .../RecommendationRepository.java | 11 ---- .../RecommendationController.java | 44 ------------- .../WebtoonStatusCountService.java | 31 ++++++++++ .../application/WebtoonStatusService.java | 37 +++++++++++ .../webtoon/converter/WebtoonConverter.java | 48 ++++++++++++-- .../domain/WebtoonStatus.java} | 12 ++-- .../domain/WebtoonStatusCount.java} | 10 +-- .../domain/vo/WebtoonStatusType.java} | 6 +- .../kr/co/antoon/webtoon/dto/WebtoonDto.java | 6 +- .../webtoon/dto/query/WebtoonNativeDto.java | 6 +- .../dto/response/WebtoonStatusResponse.java | 34 ++++++++++ .../webtoon/facade/WebtoonStatusFacade.java | 62 +++++++++++++++++++ .../infrastructure/WebtoonRepository.java | 8 +-- .../WebtoonStatusCountRepository.java | 12 ++++ .../WebtoonStatusRepository.java | 11 ++++ .../presentation/WebtoonController.java | 22 +++++++ .../criteria/BasicAllocateScoreTest.java | 6 +- .../domain/RecommendationCountTest.java | 21 ------- .../domain/WebtoonStatusCountTest.java | 22 +++++++ .../presentation/WebtoonControllerTest.java} | 17 ++--- 40 files changed, 360 insertions(+), 354 deletions(-) delete mode 100644 src/main/java/kr/co/antoon/batch/recommendation/RecommendationDailyJob.java rename src/main/java/kr/co/antoon/batch/{recommendation/RecommendationBatchScheduler.java => webtoonstatus/WebtoonStatusBatchScheduler.java} (69%) create mode 100644 src/main/java/kr/co/antoon/batch/webtoonstatus/WebtoonStatusDailyJob.java rename src/main/java/kr/co/antoon/error/exception/{recommendation => webtoon}/AlreadyJoinedException.java (83%) rename src/main/java/kr/co/antoon/error/exception/{recommendation => webtoon}/AlreadyLeavedException.java (83%) delete mode 100644 src/main/java/kr/co/antoon/recommendation/application/RecommendationCountService.java delete mode 100644 src/main/java/kr/co/antoon/recommendation/application/RecommendationService.java delete mode 100644 src/main/java/kr/co/antoon/recommendation/dto/response/RecommendationResponse.java delete mode 100644 src/main/java/kr/co/antoon/recommendation/facade/RecommendationFacade.java delete mode 100644 src/main/java/kr/co/antoon/recommendation/infrastructure/RecommendationCountRepository.java delete mode 100644 src/main/java/kr/co/antoon/recommendation/infrastructure/RecommendationRepository.java delete mode 100644 src/main/java/kr/co/antoon/recommendation/presentation/RecommendationController.java create mode 100644 src/main/java/kr/co/antoon/webtoon/application/WebtoonStatusCountService.java create mode 100644 src/main/java/kr/co/antoon/webtoon/application/WebtoonStatusService.java rename src/main/java/kr/co/antoon/{recommendation/domain/Recommendation.java => webtoon/domain/WebtoonStatus.java} (70%) rename src/main/java/kr/co/antoon/{recommendation/domain/RecommendationCount.java => webtoon/domain/WebtoonStatusCount.java} (79%) rename src/main/java/kr/co/antoon/{recommendation/domain/vo/RecommendationStatus.java => webtoon/domain/vo/WebtoonStatusType.java} (72%) create mode 100644 src/main/java/kr/co/antoon/webtoon/dto/response/WebtoonStatusResponse.java create mode 100644 src/main/java/kr/co/antoon/webtoon/facade/WebtoonStatusFacade.java create mode 100644 src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonStatusCountRepository.java create mode 100644 src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonStatusRepository.java delete mode 100644 src/test/java/kr/co/antoon/recommendation/domain/RecommendationCountTest.java create mode 100644 src/test/java/kr/co/antoon/webtoon/domain/WebtoonStatusCountTest.java rename src/test/java/kr/co/antoon/{recommendation/presentation/RecommendationControllerTest.java => webtoon/presentation/WebtoonControllerTest.java} (83%) diff --git a/scripts/sql/DDL.sql b/scripts/sql/DDL.sql index 365298da..57b654a1 100644 --- a/scripts/sql/DDL.sql +++ b/scripts/sql/DDL.sql @@ -79,7 +79,7 @@ CREATE TABLE `graph_score_snapshot` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci -CREATE TABLE `recommendation` +CREATE TABLE `webtoon_status` ( `id` bigint NOT NULL AUTO_INCREMENT, `created_at` datetime DEFAULT NULL, @@ -90,7 +90,7 @@ CREATE TABLE `recommendation` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci -CREATE TABLE `recommendation_count` +CREATE TABLE `webtoon_status_count` ( `id` bigint NOT NULL AUTO_INCREMENT, `created_at` datetime DEFAULT NULL, diff --git a/src/main/java/kr/co/antoon/batch/recommendation/RecommendationDailyJob.java b/src/main/java/kr/co/antoon/batch/recommendation/RecommendationDailyJob.java deleted file mode 100644 index 29866f5d..00000000 --- a/src/main/java/kr/co/antoon/batch/recommendation/RecommendationDailyJob.java +++ /dev/null @@ -1,15 +0,0 @@ -package kr.co.antoon.batch.recommendation; - -import kr.co.antoon.recommendation.facade.RecommendationFacade; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class RecommendationDailyJob { - private final RecommendationFacade recommendationFacade; - - public void run() { - recommendationFacade.changeAllStatus(); - } -} diff --git a/src/main/java/kr/co/antoon/batch/recommendation/RecommendationBatchScheduler.java b/src/main/java/kr/co/antoon/batch/webtoonstatus/WebtoonStatusBatchScheduler.java similarity index 69% rename from src/main/java/kr/co/antoon/batch/recommendation/RecommendationBatchScheduler.java rename to src/main/java/kr/co/antoon/batch/webtoonstatus/WebtoonStatusBatchScheduler.java index 70ea23ef..c3727355 100644 --- a/src/main/java/kr/co/antoon/batch/recommendation/RecommendationBatchScheduler.java +++ b/src/main/java/kr/co/antoon/batch/webtoonstatus/WebtoonStatusBatchScheduler.java @@ -1,4 +1,4 @@ -package kr.co.antoon.batch.recommendation; +package kr.co.antoon.batch.webtoonstatus; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Profile; @@ -8,14 +8,14 @@ @Profile("batch") @Component @RequiredArgsConstructor -public class RecommendationBatchScheduler { - private final RecommendationDailyJob recommendationDailyJob; +public class WebtoonStatusBatchScheduler { + private final WebtoonStatusDailyJob webtoonStatusDailyJob; /** * 매일 낮 12시에 탑승중, 하차중 상태 초기화 **/ @Scheduled(cron = "0 0 12 * * ?") public void runDailyJobLeavedStatus() { - recommendationDailyJob.run(); + webtoonStatusDailyJob.run(); } } diff --git a/src/main/java/kr/co/antoon/batch/webtoonstatus/WebtoonStatusDailyJob.java b/src/main/java/kr/co/antoon/batch/webtoonstatus/WebtoonStatusDailyJob.java new file mode 100644 index 00000000..211b1e80 --- /dev/null +++ b/src/main/java/kr/co/antoon/batch/webtoonstatus/WebtoonStatusDailyJob.java @@ -0,0 +1,15 @@ +package kr.co.antoon.batch.webtoonstatus; + +import kr.co.antoon.webtoon.facade.WebtoonStatusFacade; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class WebtoonStatusDailyJob { + private final WebtoonStatusFacade webtoonStatusFacade; + + public void run() { + webtoonStatusFacade.changeAllStatus(); + } +} diff --git a/src/main/java/kr/co/antoon/character/facade/CharacterHistoryFacade.java b/src/main/java/kr/co/antoon/character/facade/CharacterHistoryFacade.java index d6208d04..16a62dc2 100644 --- a/src/main/java/kr/co/antoon/character/facade/CharacterHistoryFacade.java +++ b/src/main/java/kr/co/antoon/character/facade/CharacterHistoryFacade.java @@ -5,7 +5,7 @@ import kr.co.antoon.coin.AntCoinClient; import kr.co.antoon.coin.domain.vo.CoinRewardType; import kr.co.antoon.coin.domain.vo.RemittanceType; -import kr.co.antoon.error.exception.recommendation.AlreadyJoinedException; +import kr.co.antoon.error.exception.webtoon.AlreadyJoinedException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/kr/co/antoon/coin/AntCoinClient.java b/src/main/java/kr/co/antoon/coin/AntCoinClient.java index 63a46c57..3b4f6f11 100644 --- a/src/main/java/kr/co/antoon/coin/AntCoinClient.java +++ b/src/main/java/kr/co/antoon/coin/AntCoinClient.java @@ -3,10 +3,7 @@ import kr.co.antoon.coin.domain.AntCoinWallet; import kr.co.antoon.coin.domain.vo.RemittanceType; -import kr.co.antoon.coin.dto.CoinHistoryResponse; import kr.co.antoon.coin.dto.CoinHistoryResponseByDate; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; -import kr.co.antoon.recommendation.dto.response.RecommendationResponse; /** * @apiNote coin module diff --git a/src/main/java/kr/co/antoon/coin/application/AntCoinService.java b/src/main/java/kr/co/antoon/coin/application/AntCoinService.java index 1fd6de4a..cb2fa5e7 100644 --- a/src/main/java/kr/co/antoon/coin/application/AntCoinService.java +++ b/src/main/java/kr/co/antoon/coin/application/AntCoinService.java @@ -11,8 +11,8 @@ import kr.co.antoon.coin.domain.vo.RemittanceType; import kr.co.antoon.coin.dto.CoinHistoryResponse; import kr.co.antoon.coin.dto.CoinHistoryResponseByDate; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; -import kr.co.antoon.recommendation.dto.response.RecommendationResponse; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; +import kr.co.antoon.webtoon.dto.response.WebtoonStatusResponse; import kr.co.antoon.vote.application.CandidateService; import kr.co.antoon.webtoon.application.WebtoonService; import lombok.RequiredArgsConstructor; @@ -135,7 +135,7 @@ public void create(Long userId) { } @Transactional - public RecommendationResponse joinWebtoon(Long userId, Long webtoonId, RecommendationResponse response, RecommendationStatus status) { + public WebtoonStatusResponse joinWebtoon(Long userId, Long webtoonId, WebtoonStatusResponse response, WebtoonStatusType status) { if (antCoinHistoryService.checkTodayJoinWebtoon(userId, webtoonId)) { log.info("ALREADY_GET_COIN: 이미 탑승/하차를 통한 코인 지급이 완료되었습니다."); return response; diff --git a/src/main/java/kr/co/antoon/coin/domain/vo/RemittanceType.java b/src/main/java/kr/co/antoon/coin/domain/vo/RemittanceType.java index 4115887e..88567bb8 100644 --- a/src/main/java/kr/co/antoon/coin/domain/vo/RemittanceType.java +++ b/src/main/java/kr/co/antoon/coin/domain/vo/RemittanceType.java @@ -1,6 +1,6 @@ package kr.co.antoon.coin.domain.vo; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -16,7 +16,7 @@ public enum RemittanceType { private final String description; - public static RemittanceType joinOrLeave(RecommendationStatus status) { + public static RemittanceType joinOrLeave(WebtoonStatusType status) { if(status.toString().startsWith("JOIN")) { return JOINED_WEBTOON; } diff --git a/src/main/java/kr/co/antoon/common/dto/SwaggerNote.java b/src/main/java/kr/co/antoon/common/dto/SwaggerNote.java index 467f7f4c..2b860b71 100644 --- a/src/main/java/kr/co/antoon/common/dto/SwaggerNote.java +++ b/src/main/java/kr/co/antoon/common/dto/SwaggerNote.java @@ -3,7 +3,7 @@ public class SwaggerNote { public final static String DISCUSSION_CREATE_NOTE = """ 종목토론방에 댓글 달기 - POST /api/v1/webtoons/{webtoonId}/discussions + POST /api/v1/webtoons/{webtoonId}/discussions Request Body { @@ -26,7 +26,7 @@ public class SwaggerNote { public final static String DISCUSSION_READ_ONE_NOTE = """ 종목토론방에 댓글 단건 조회 - POST /api/v1/webtoons/discussions/discussionId + POST /api/v1/webtoons/discussions/discussionId Response Body { @@ -107,10 +107,10 @@ public class SwaggerNote { None """; - public final static String RECOMMENDATION = """ + public final static String WEBTOON_JOIN = """ 웹툰 상세페이지 > 탑승/하차 API status값 : JOIN, LEAVE - PATCH /api/v1/recommendations/{webtonId}?status={status} + PATCH /api/v1/webtoons/{webtonId}/join?status={status} Response Body { @@ -165,13 +165,13 @@ public class SwaggerNote { "name": "홍필" } ], - "recommendationCountId": 6, + "webtoonStatusCountId": 6, "joinCount": 1, "leaveCount": 1, "score": 648, "scoreGap": 0, "scoreGapPercent": 0.0, - "recommendationStatus": "LEAVED", + "webtoonStatus": "LEAVED", "ranking": 1, "characters": [ { diff --git a/src/main/java/kr/co/antoon/criteria/BasicAllocateScore.java b/src/main/java/kr/co/antoon/criteria/BasicAllocateScore.java index 486b58a3..e641f01e 100644 --- a/src/main/java/kr/co/antoon/criteria/BasicAllocateScore.java +++ b/src/main/java/kr/co/antoon/criteria/BasicAllocateScore.java @@ -21,7 +21,7 @@ public int discussionScore(long count) { } } - public int recommendationScore(int count) { + public int webtoonStatusScore(int count) { if (count > 10) { return 300; } else if (count > 8) { @@ -37,8 +37,8 @@ public int recommendationScore(int count) { } } - public int graphScore(int discussionScore, int recommendationScore, int webtoonScore) { - var graphScore = discussionScore + recommendationScore + webtoonScore; + public int graphScore(int discussionScore, int webtoonStatusScore, int webtoonScore) { + var graphScore = discussionScore + webtoonStatusScore + webtoonScore; return Math.max(graphScore, 250); } diff --git a/src/main/java/kr/co/antoon/criteria/ScoreAllocationCriteria.java b/src/main/java/kr/co/antoon/criteria/ScoreAllocationCriteria.java index 4e8c3e86..eae4ba38 100644 --- a/src/main/java/kr/co/antoon/criteria/ScoreAllocationCriteria.java +++ b/src/main/java/kr/co/antoon/criteria/ScoreAllocationCriteria.java @@ -19,17 +19,17 @@ public interface ScoreAllocationCriteria { int discussionScore(long count); /** - * @param count webtoon recommendation count - * @apiNote webtoon recommendation count to score + * @param count webtoon status count + * @apiNote webtoon status count to score * max score 300 **/ - int recommendationScore(int count); + int webtoonStatusScore(int count); /** * @param webtoonScore 50% 500 * @param discussionScore 20% 200 - * @param recommendationScore 30% 300 + * @param webtoonStatusScore 30% 300 * @apiNote graph score max 1000 **/ - int graphScore(int discussionScore, int recommendationScore, int webtoonScore); + int graphScore(int discussionScore, int webtoonStatusScore, int webtoonScore); } \ No newline at end of file diff --git a/src/main/java/kr/co/antoon/error/dto/ErrorMessage.java b/src/main/java/kr/co/antoon/error/dto/ErrorMessage.java index a20f7837..4737eeab 100644 --- a/src/main/java/kr/co/antoon/error/dto/ErrorMessage.java +++ b/src/main/java/kr/co/antoon/error/dto/ErrorMessage.java @@ -36,7 +36,7 @@ public enum ErrorMessage { NOT_EXISTS_DISCUSSION_ERROR(HttpStatus.NOT_FOUND, "존재하지 않는 댓글입니다."), /** - * Recommendation Error Message + * Webtoon Status Error Message **/ ALREADY_JOINED_ERROR(HttpStatus.BAD_REQUEST, "이미 탑승 중입니다."), ALREADY_LEAVED_ERROR(HttpStatus.CONFLICT, "이미 하차 중입니다"), diff --git a/src/main/java/kr/co/antoon/error/exception/recommendation/AlreadyJoinedException.java b/src/main/java/kr/co/antoon/error/exception/webtoon/AlreadyJoinedException.java similarity index 83% rename from src/main/java/kr/co/antoon/error/exception/recommendation/AlreadyJoinedException.java rename to src/main/java/kr/co/antoon/error/exception/webtoon/AlreadyJoinedException.java index ea0392ea..ecf1ac93 100644 --- a/src/main/java/kr/co/antoon/error/exception/recommendation/AlreadyJoinedException.java +++ b/src/main/java/kr/co/antoon/error/exception/webtoon/AlreadyJoinedException.java @@ -1,4 +1,4 @@ -package kr.co.antoon.error.exception.recommendation; +package kr.co.antoon.error.exception.webtoon; import kr.co.antoon.error.dto.ErrorMessage; import kr.co.antoon.error.exception.BusinessException; diff --git a/src/main/java/kr/co/antoon/error/exception/recommendation/AlreadyLeavedException.java b/src/main/java/kr/co/antoon/error/exception/webtoon/AlreadyLeavedException.java similarity index 83% rename from src/main/java/kr/co/antoon/error/exception/recommendation/AlreadyLeavedException.java rename to src/main/java/kr/co/antoon/error/exception/webtoon/AlreadyLeavedException.java index 1e41d5e5..0cd5d999 100644 --- a/src/main/java/kr/co/antoon/error/exception/recommendation/AlreadyLeavedException.java +++ b/src/main/java/kr/co/antoon/error/exception/webtoon/AlreadyLeavedException.java @@ -1,4 +1,4 @@ -package kr.co.antoon.error.exception.recommendation; +package kr.co.antoon.error.exception.webtoon; import kr.co.antoon.error.dto.ErrorMessage; import kr.co.antoon.error.exception.BusinessException; diff --git a/src/main/java/kr/co/antoon/graph/facade/GraphScoreFacade.java b/src/main/java/kr/co/antoon/graph/facade/GraphScoreFacade.java index 242d815e..feafa870 100644 --- a/src/main/java/kr/co/antoon/graph/facade/GraphScoreFacade.java +++ b/src/main/java/kr/co/antoon/graph/facade/GraphScoreFacade.java @@ -9,8 +9,8 @@ import kr.co.antoon.graph.application.TopRankService; import kr.co.antoon.graph.domain.GraphScoreSnapshot; import kr.co.antoon.graph.domain.vo.GraphStatus; -import kr.co.antoon.recommendation.application.RecommendationCountService; -import kr.co.antoon.recommendation.domain.RecommendationCount; +import kr.co.antoon.webtoon.application.WebtoonStatusCountService; +import kr.co.antoon.webtoon.domain.WebtoonStatusCount; import kr.co.antoon.webtoon.application.WebtoonService; import kr.co.antoon.webtoon.application.WebtoonSnapshotService; import lombok.RequiredArgsConstructor; @@ -31,7 +31,7 @@ public class GraphScoreFacade { private final DiscussionService discussionService; private final WebtoonService webtoonService; private final TopRankService topRankService; - private final RecommendationCountService recommendationCountService; + private final WebtoonStatusCountService webtoonStatusCountService; private final ScoreAllocationCriteria scoreAllocationCriteria; private final WebtoonRedisCacheService webtoonRedisCacheService; @@ -44,12 +44,12 @@ public class GraphScoreFacade { @Transactional public void snapshot() { var webtoons = webtoonService.findAll(); - var recommendationCounts = recommendationCountService.findAll() + var webtoonStatusCounts = webtoonStatusCountService.findAll() .parallelStream() .collect(Collectors.toMap( - RecommendationCount::getWebtoonId, - rc -> rc, - (rc1, rc2) -> rc1 + WebtoonStatusCount::getWebtoonId, + ws -> ws, + (ws1, ws2) -> ws1 ) ); var now = TimeUtil.now(); @@ -82,12 +82,12 @@ public void snapshot() { discussionScore = scoreAllocationCriteria.discussionScore(discussionScore); var count = 0; - if (recommendationCounts.containsKey(webtoonId)) { - count = recommendationCounts.get(webtoonId).count(); + if (webtoonStatusCounts.containsKey(webtoonId)) { + count = webtoonStatusCounts.get(webtoonId).count(); } - var recommendationScore = scoreAllocationCriteria.recommendationScore(count); + var webtoonStatusScore = scoreAllocationCriteria.webtoonStatusScore(count); - var graphScore = scoreAllocationCriteria.graphScore((int) discussionScore, recommendationScore, webtoonScore); + var graphScore = scoreAllocationCriteria.graphScore((int) discussionScore, webtoonStatusScore, webtoonScore); var graphScoreSnapshots = graphScoreSnapshotService.findTop1ByWebtoonIdOrderBySnapshotTimeDesc(webtoonId); diff --git a/src/main/java/kr/co/antoon/recommendation/application/RecommendationCountService.java b/src/main/java/kr/co/antoon/recommendation/application/RecommendationCountService.java deleted file mode 100644 index 35791b5a..00000000 --- a/src/main/java/kr/co/antoon/recommendation/application/RecommendationCountService.java +++ /dev/null @@ -1,31 +0,0 @@ -package kr.co.antoon.recommendation.application; - -import kr.co.antoon.recommendation.domain.RecommendationCount; -import kr.co.antoon.recommendation.infrastructure.RecommendationCountRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Optional; - -@Service -@RequiredArgsConstructor -public class RecommendationCountService { - private final RecommendationCountRepository recommendationCountRepository; - - @Transactional(readOnly = true) - public Optional findByWebtoonId(Long webtoonId) { - return recommendationCountRepository.findByWebtoonId(webtoonId); - } - - @Transactional - public RecommendationCount save(Long webtoonId) { - return recommendationCountRepository.save(new RecommendationCount(webtoonId)); - } - - @Transactional(readOnly = true) - public List findAll() { - return recommendationCountRepository.findAll(); - } -} diff --git a/src/main/java/kr/co/antoon/recommendation/application/RecommendationService.java b/src/main/java/kr/co/antoon/recommendation/application/RecommendationService.java deleted file mode 100644 index 57c8cb25..00000000 --- a/src/main/java/kr/co/antoon/recommendation/application/RecommendationService.java +++ /dev/null @@ -1,36 +0,0 @@ -package kr.co.antoon.recommendation.application; - -import kr.co.antoon.recommendation.domain.Recommendation; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; -import kr.co.antoon.recommendation.infrastructure.RecommendationRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class RecommendationService { - private final RecommendationRepository recommendationRepository; - - @Transactional(readOnly = true) - public boolean existsByUserIdAndWebtoonIdAndStatus(Long userId, Long webtoonId, RecommendationStatus status) { - return recommendationRepository.existsByUserIdAndWebtoonIdAndStatus(userId, webtoonId, status); - } - - @Transactional - public void save(Long userId, Long webtoonId, RecommendationStatus status) { - var recommendation = new Recommendation(userId, webtoonId, status); - - recommendationRepository.save(recommendation); - } - - @Transactional(readOnly = true) - public List findAllByStatus(RecommendationStatus status) { - return recommendationRepository.findAll() - .stream() - .filter(r -> r.getStatus().equals(status)) - .toList(); - } -} diff --git a/src/main/java/kr/co/antoon/recommendation/dto/response/RecommendationResponse.java b/src/main/java/kr/co/antoon/recommendation/dto/response/RecommendationResponse.java deleted file mode 100644 index 6736e750..00000000 --- a/src/main/java/kr/co/antoon/recommendation/dto/response/RecommendationResponse.java +++ /dev/null @@ -1,34 +0,0 @@ -package kr.co.antoon.recommendation.dto.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import kr.co.antoon.recommendation.domain.RecommendationCount; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; - -public record RecommendationResponse( - @Schema(description = "탑승 인원수") - int joinCount, - @Schema(description = "하차 인원수") - int leaveCount, - @Schema(description = "상하차 상태") - RecommendationStatus status, - @Schema(description = "코인 지급 여부", defaultValue = "false") - boolean getCoin -) { - public RecommendationResponse( - RecommendationCount recommendationCount, - RecommendationStatus status - ) { - this( - recommendationCount.getJoinCount(), - recommendationCount.getLeaveCount(), - status, - false - ); - } - - public RecommendationResponse update( - boolean getCoin - ) { - return new RecommendationResponse(joinCount, leaveCount, status, getCoin); - } -} diff --git a/src/main/java/kr/co/antoon/recommendation/facade/RecommendationFacade.java b/src/main/java/kr/co/antoon/recommendation/facade/RecommendationFacade.java deleted file mode 100644 index 441585db..00000000 --- a/src/main/java/kr/co/antoon/recommendation/facade/RecommendationFacade.java +++ /dev/null @@ -1,62 +0,0 @@ -package kr.co.antoon.recommendation.facade; - -import kr.co.antoon.error.exception.recommendation.AlreadyJoinedException; -import kr.co.antoon.error.exception.recommendation.AlreadyLeavedException; -import kr.co.antoon.recommendation.application.RecommendationCountService; -import kr.co.antoon.recommendation.application.RecommendationService; -import kr.co.antoon.recommendation.domain.RecommendationCount; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; -import kr.co.antoon.recommendation.dto.response.RecommendationResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -@Component -@RequiredArgsConstructor -public class RecommendationFacade { - private final RecommendationService recommendationService; - private final RecommendationCountService recommendationCountService; - - @Transactional - public RecommendationResponse saveOrUpdate(RecommendationStatus status, Long userId, Long webtoonId) { - statusCheck(userId, webtoonId); - RecommendationCount recommendationCount = recommendationCountService.findByWebtoonId(webtoonId) - .orElseGet(() -> recommendationCountService.save(webtoonId)); - recommendationCount.updateCount(status); - - status = RecommendationStatus.of(status); - recommendationService.save(webtoonId, userId, status); - - return new RecommendationResponse( - recommendationCount, - status - ); - } - - @Transactional(readOnly = true) - public void statusCheck(Long userId, Long webtoonId) { - if (recommendationService.existsByUserIdAndWebtoonIdAndStatus(userId, webtoonId, RecommendationStatus.LEAVED)) { - throw new AlreadyLeavedException(); - } - if (recommendationService.existsByUserIdAndWebtoonIdAndStatus(userId, webtoonId, RecommendationStatus.JOINED)) { - throw new AlreadyJoinedException(); - } - } - - @Transactional - public void changeAllStatus() { - recommendationService.findAllByStatus(RecommendationStatus.JOINED) - .forEach(recommendation -> { - recommendation.updateStatus(RecommendationStatus.NONE); - recommendationCountService.findByWebtoonId(recommendation.getWebtoonId()) - .ifPresent(rc -> rc.updateCount(RecommendationStatus.JOINED)); - }); - - recommendationService.findAllByStatus(RecommendationStatus.LEAVED) - .forEach(recommendation -> { - recommendation.updateStatus(RecommendationStatus.NONE); - recommendationCountService.findByWebtoonId(recommendation.getWebtoonId()) - .ifPresent(rc -> rc.updateCount(RecommendationStatus.LEAVED)); - }); - } -} diff --git a/src/main/java/kr/co/antoon/recommendation/infrastructure/RecommendationCountRepository.java b/src/main/java/kr/co/antoon/recommendation/infrastructure/RecommendationCountRepository.java deleted file mode 100644 index abc0054f..00000000 --- a/src/main/java/kr/co/antoon/recommendation/infrastructure/RecommendationCountRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package kr.co.antoon.recommendation.infrastructure; - -import kr.co.antoon.recommendation.domain.RecommendationCount; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -@Repository -public interface RecommendationCountRepository extends JpaRepository { - Optional findByWebtoonId(Long webtoonId); -} diff --git a/src/main/java/kr/co/antoon/recommendation/infrastructure/RecommendationRepository.java b/src/main/java/kr/co/antoon/recommendation/infrastructure/RecommendationRepository.java deleted file mode 100644 index 0be0bb9b..00000000 --- a/src/main/java/kr/co/antoon/recommendation/infrastructure/RecommendationRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package kr.co.antoon.recommendation.infrastructure; - -import kr.co.antoon.recommendation.domain.Recommendation; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface RecommendationRepository extends JpaRepository { - Boolean existsByUserIdAndWebtoonIdAndStatus(long userId, long webtoonId, RecommendationStatus status); -} diff --git a/src/main/java/kr/co/antoon/recommendation/presentation/RecommendationController.java b/src/main/java/kr/co/antoon/recommendation/presentation/RecommendationController.java deleted file mode 100644 index 02c13de5..00000000 --- a/src/main/java/kr/co/antoon/recommendation/presentation/RecommendationController.java +++ /dev/null @@ -1,44 +0,0 @@ -package kr.co.antoon.recommendation.presentation; - -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import kr.co.antoon.coin.AntCoinClient; -import kr.co.antoon.coin.application.AntCoinService; -import kr.co.antoon.common.dto.ResponseDto; -import kr.co.antoon.common.dto.SwaggerNote; -import kr.co.antoon.oauth.config.AuthUser; -import kr.co.antoon.oauth.dto.AuthInfo; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; -import kr.co.antoon.recommendation.dto.response.RecommendationResponse; -import kr.co.antoon.recommendation.facade.RecommendationFacade; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import static kr.co.antoon.common.util.CommonUtil.APPLICATION_JSON_UTF_8; - -@Api(tags = "탑승/하차 API") -@RestController -@RequestMapping(value = "/api/v1/recommendations", produces = APPLICATION_JSON_UTF_8) -@RequiredArgsConstructor -public class RecommendationController { - private final RecommendationFacade recommendationFacade; - private final AntCoinService antCoinService; - - @ApiOperation(value = "탑승/하차", notes = SwaggerNote.RECOMMENDATION) - @PatchMapping("/{webtoonId}") - public ResponseEntity createLeaveStatus( - @PathVariable Long webtoonId, - @AuthUser AuthInfo info, - @RequestParam("status") RecommendationStatus status - ) { - // TODO 해당 로직 처리는 여기서 하는게 이상해보이네요 response가 두번 사용되는 것도... - var response = recommendationFacade.saveOrUpdate(status, info.userId(), webtoonId); - response = antCoinService.joinWebtoon(info.userId(), webtoonId, response, status); - return ResponseDto.ok(response); - } -} diff --git a/src/main/java/kr/co/antoon/webtoon/application/WebtoonStatusCountService.java b/src/main/java/kr/co/antoon/webtoon/application/WebtoonStatusCountService.java new file mode 100644 index 00000000..ee78a77b --- /dev/null +++ b/src/main/java/kr/co/antoon/webtoon/application/WebtoonStatusCountService.java @@ -0,0 +1,31 @@ +package kr.co.antoon.webtoon.application; + +import kr.co.antoon.webtoon.domain.WebtoonStatusCount; +import kr.co.antoon.webtoon.infrastructure.WebtoonStatusCountRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class WebtoonStatusCountService { + private final WebtoonStatusCountRepository webtoonStatusCountRepository; + + @Transactional(readOnly = true) + public Optional findByWebtoonId(Long webtoonId) { + return webtoonStatusCountRepository.findByWebtoonId(webtoonId); + } + + @Transactional + public WebtoonStatusCount save(Long webtoonId) { + return webtoonStatusCountRepository.save(new WebtoonStatusCount(webtoonId)); + } + + @Transactional(readOnly = true) + public List findAll() { + return webtoonStatusCountRepository.findAll(); + } +} diff --git a/src/main/java/kr/co/antoon/webtoon/application/WebtoonStatusService.java b/src/main/java/kr/co/antoon/webtoon/application/WebtoonStatusService.java new file mode 100644 index 00000000..cb2a9880 --- /dev/null +++ b/src/main/java/kr/co/antoon/webtoon/application/WebtoonStatusService.java @@ -0,0 +1,37 @@ +package kr.co.antoon.webtoon.application; + +import kr.co.antoon.webtoon.domain.WebtoonStatus; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; +import kr.co.antoon.webtoon.infrastructure.WebtoonStatusRepository; +import kr.co.antoon.webtoon.converter.WebtoonConverter; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class WebtoonStatusService { + private final WebtoonStatusRepository webtoonStatusRepository; + + @Transactional(readOnly = true) + public boolean existsByUserIdAndWebtoonIdAndStatus(Long userId, Long webtoonId, WebtoonStatusType status) { + return webtoonStatusRepository.existsByUserIdAndWebtoonIdAndStatus(userId, webtoonId, status); + } + + @Transactional + public void save(Long userId, Long webtoonId, WebtoonStatusType status) { + var webtoonStatus = new WebtoonStatus(userId, webtoonId, status); + + webtoonStatusRepository.save(webtoonStatus); + } + + @Transactional(readOnly = true) + public List findAllByStatus(WebtoonStatusType status) { + return webtoonStatusRepository.findAll() + .stream() + .filter(ws -> ws.getStatus().equals(status)) + .toList(); + } +} diff --git a/src/main/java/kr/co/antoon/webtoon/converter/WebtoonConverter.java b/src/main/java/kr/co/antoon/webtoon/converter/WebtoonConverter.java index 0ec9dc03..a0e6202b 100644 --- a/src/main/java/kr/co/antoon/webtoon/converter/WebtoonConverter.java +++ b/src/main/java/kr/co/antoon/webtoon/converter/WebtoonConverter.java @@ -1,11 +1,22 @@ package kr.co.antoon.webtoon.converter; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; +import kr.co.antoon.common.domain.BaseEntity; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; import kr.co.antoon.webtoon.domain.Webtoon; import kr.co.antoon.webtoon.domain.vo.Platform; import kr.co.antoon.webtoon.dto.WebtoonDto; import kr.co.antoon.webtoon.dto.query.WebtoonNativeDto; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -58,21 +69,21 @@ public static WebtoonDto toWebtoonDto(List webtoon) { genres, days, writers, - webtoon.get(0).getRecommendationCountId(), + webtoon.get(0).getWebtoonStatusCountId(), webtoon.get(0).getJoinCount(), webtoon.get(0).getLeaveCount(), webtoon.get(0).getGraphScore(), webtoon.get(0).getScoreGap(), getDifferencePercentage(webtoon.get(0).getGraphScore(), webtoon.get(0).getScoreGap()), - status(webtoon.get(0).getRecommendationStatus()), + status(webtoon.get(0).getWebtoonStatus()), webtoon.get(0).getRanking(), characters ); } - private static RecommendationStatus status(RecommendationStatus status) { + private static WebtoonStatusType status(WebtoonStatusType status) { if (status == null) { - return RecommendationStatus.NONE; + return WebtoonStatusType.NONE; } return status; } @@ -86,4 +97,31 @@ public static Webtoon toWebtoon(WebtoonCrawlingDetail crawlingWebtton, Platform .platform(platform) .build(); } + + @Getter + @Entity + @NoArgsConstructor(access = AccessLevel.PROTECTED) + public static class WebtoonStatus extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private Long webtoonId; + + private Long userId; + + @Enumerated(EnumType.STRING) + private WebtoonStatusType status; + + @Builder + public WebtoonStatus(Long webtoonId, Long userId, WebtoonStatusType status) { + this.webtoonId = webtoonId; + this.userId = userId; + this.status = status; + } + + public void updateStatus(WebtoonStatusType status) { + this.status = status; + } + } } diff --git a/src/main/java/kr/co/antoon/recommendation/domain/Recommendation.java b/src/main/java/kr/co/antoon/webtoon/domain/WebtoonStatus.java similarity index 70% rename from src/main/java/kr/co/antoon/recommendation/domain/Recommendation.java rename to src/main/java/kr/co/antoon/webtoon/domain/WebtoonStatus.java index 68b52575..1c1fcd05 100644 --- a/src/main/java/kr/co/antoon/recommendation/domain/Recommendation.java +++ b/src/main/java/kr/co/antoon/webtoon/domain/WebtoonStatus.java @@ -1,7 +1,7 @@ -package kr.co.antoon.recommendation.domain; +package kr.co.antoon.webtoon.domain; import kr.co.antoon.common.domain.BaseEntity; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -18,7 +18,7 @@ @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Recommendation extends BaseEntity { +public class WebtoonStatus extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -28,16 +28,16 @@ public class Recommendation extends BaseEntity { private Long userId; @Enumerated(EnumType.STRING) - private RecommendationStatus status; + private WebtoonStatusType status; @Builder - public Recommendation(Long webtoonId, Long userId, RecommendationStatus status) { + public WebtoonStatus(Long webtoonId, Long userId, WebtoonStatusType status) { this.webtoonId = webtoonId; this.userId = userId; this.status = status; } - public void updateStatus(RecommendationStatus status) { + public void updateStatus(WebtoonStatusType status) { this.status = status; } } diff --git a/src/main/java/kr/co/antoon/recommendation/domain/RecommendationCount.java b/src/main/java/kr/co/antoon/webtoon/domain/WebtoonStatusCount.java similarity index 79% rename from src/main/java/kr/co/antoon/recommendation/domain/RecommendationCount.java rename to src/main/java/kr/co/antoon/webtoon/domain/WebtoonStatusCount.java index 94364ed3..9656d556 100644 --- a/src/main/java/kr/co/antoon/recommendation/domain/RecommendationCount.java +++ b/src/main/java/kr/co/antoon/webtoon/domain/WebtoonStatusCount.java @@ -1,7 +1,7 @@ -package kr.co.antoon.recommendation.domain; +package kr.co.antoon.webtoon.domain; import kr.co.antoon.common.domain.BaseEntity; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -18,7 +18,7 @@ @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Table(indexes = @Index(name = "i_webtoon_id", columnList = "webtoonId", unique = true)) -public class RecommendationCount extends BaseEntity { +public class WebtoonStatusCount extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -30,7 +30,7 @@ public class RecommendationCount extends BaseEntity { private int leaveCount; @Builder - public RecommendationCount(Long webtoonId) { + public WebtoonStatusCount(Long webtoonId) { this.webtoonId = webtoonId; this.joinCount = 0; this.leaveCount = 0; @@ -40,7 +40,7 @@ public int count() { return joinCount - leaveCount; } - public void updateCount(RecommendationStatus status) { + public void updateCount(WebtoonStatusType status) { switch (status) { case JOIN -> joinCount += 1; case LEAVE -> leaveCount += 1; diff --git a/src/main/java/kr/co/antoon/recommendation/domain/vo/RecommendationStatus.java b/src/main/java/kr/co/antoon/webtoon/domain/vo/WebtoonStatusType.java similarity index 72% rename from src/main/java/kr/co/antoon/recommendation/domain/vo/RecommendationStatus.java rename to src/main/java/kr/co/antoon/webtoon/domain/vo/WebtoonStatusType.java index efe3a371..d70d41f2 100644 --- a/src/main/java/kr/co/antoon/recommendation/domain/vo/RecommendationStatus.java +++ b/src/main/java/kr/co/antoon/webtoon/domain/vo/WebtoonStatusType.java @@ -1,11 +1,11 @@ -package kr.co.antoon.recommendation.domain.vo; +package kr.co.antoon.webtoon.domain.vo; import lombok.Getter; import lombok.RequiredArgsConstructor; @Getter @RequiredArgsConstructor -public enum RecommendationStatus { +public enum WebtoonStatusType { JOIN("탑승"), JOINED("탑승중"), LEAVE("하차"), @@ -15,7 +15,7 @@ public enum RecommendationStatus { private final String description; - public static RecommendationStatus of(RecommendationStatus status) { + public static WebtoonStatusType of(WebtoonStatusType status) { return switch (status) { case JOIN -> JOINED; case LEAVE -> LEAVED; diff --git a/src/main/java/kr/co/antoon/webtoon/dto/WebtoonDto.java b/src/main/java/kr/co/antoon/webtoon/dto/WebtoonDto.java index 9fbfa9ee..ef844130 100644 --- a/src/main/java/kr/co/antoon/webtoon/dto/WebtoonDto.java +++ b/src/main/java/kr/co/antoon/webtoon/dto/WebtoonDto.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.swagger.v3.oas.annotations.media.Schema; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; import kr.co.antoon.webtoon.domain.vo.ActiveStatus; import kr.co.antoon.webtoon.domain.vo.GenreCategory; import kr.co.antoon.webtoon.domain.vo.Platform; @@ -24,13 +24,13 @@ public record WebtoonDto( Set genres, Set publishDays, Set writers, - Long recommendationCountId, + Long webtoonStatusCountId, Integer joinCount, Integer leaveCount, int score, int scoreGap, double scoreGapPercent, - RecommendationStatus recommendationStatus, + WebtoonStatusType webtoonStatusType, Integer ranking, Set characters ) { diff --git a/src/main/java/kr/co/antoon/webtoon/dto/query/WebtoonNativeDto.java b/src/main/java/kr/co/antoon/webtoon/dto/query/WebtoonNativeDto.java index 7e8fbf99..4c90ed2b 100644 --- a/src/main/java/kr/co/antoon/webtoon/dto/query/WebtoonNativeDto.java +++ b/src/main/java/kr/co/antoon/webtoon/dto/query/WebtoonNativeDto.java @@ -1,6 +1,6 @@ package kr.co.antoon.webtoon.dto.query; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; import kr.co.antoon.webtoon.domain.vo.ActiveStatus; import kr.co.antoon.webtoon.domain.vo.GenreCategory; import kr.co.antoon.webtoon.domain.vo.Platform; @@ -32,7 +32,7 @@ public interface WebtoonNativeDto { String getName(); - Long getRecommendationCountId(); + Long getWebtoonStatusCountId(); Integer getJoinCount(); @@ -42,7 +42,7 @@ public interface WebtoonNativeDto { int getScoreGap(); - RecommendationStatus getRecommendationStatus(); + WebtoonStatusType getWebtoonStatus(); Integer getRanking(); diff --git a/src/main/java/kr/co/antoon/webtoon/dto/response/WebtoonStatusResponse.java b/src/main/java/kr/co/antoon/webtoon/dto/response/WebtoonStatusResponse.java new file mode 100644 index 00000000..52cb81c5 --- /dev/null +++ b/src/main/java/kr/co/antoon/webtoon/dto/response/WebtoonStatusResponse.java @@ -0,0 +1,34 @@ +package kr.co.antoon.webtoon.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.co.antoon.webtoon.domain.WebtoonStatusCount; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; + +public record WebtoonStatusResponse( + @Schema(description = "탑승 인원수") + int joinCount, + @Schema(description = "하차 인원수") + int leaveCount, + @Schema(description = "상하차 상태") + WebtoonStatusType status, + @Schema(description = "코인 지급 여부", defaultValue = "false") + boolean getCoin +) { + public WebtoonStatusResponse( + WebtoonStatusCount webtoonStatusCount, + WebtoonStatusType status + ) { + this( + webtoonStatusCount.getJoinCount(), + webtoonStatusCount.getLeaveCount(), + status, + false + ); + } + + public WebtoonStatusResponse update( + boolean getCoin + ) { + return new WebtoonStatusResponse(joinCount, leaveCount, status, getCoin); + } +} diff --git a/src/main/java/kr/co/antoon/webtoon/facade/WebtoonStatusFacade.java b/src/main/java/kr/co/antoon/webtoon/facade/WebtoonStatusFacade.java new file mode 100644 index 00000000..a270b08d --- /dev/null +++ b/src/main/java/kr/co/antoon/webtoon/facade/WebtoonStatusFacade.java @@ -0,0 +1,62 @@ +package kr.co.antoon.webtoon.facade; + +import kr.co.antoon.error.exception.webtoon.AlreadyJoinedException; +import kr.co.antoon.error.exception.webtoon.AlreadyLeavedException; +import kr.co.antoon.webtoon.application.WebtoonStatusCountService; +import kr.co.antoon.webtoon.application.WebtoonStatusService; +import kr.co.antoon.webtoon.domain.WebtoonStatusCount; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; +import kr.co.antoon.webtoon.dto.response.WebtoonStatusResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class WebtoonStatusFacade { + private final WebtoonStatusService webtoonStatusService; + private final WebtoonStatusCountService webtoonStatusCountService; + + @Transactional + public WebtoonStatusResponse saveOrUpdate(WebtoonStatusType status, Long userId, Long webtoonId) { + statusCheck(userId, webtoonId); + WebtoonStatusCount webtoonStatusCount = webtoonStatusCountService.findByWebtoonId(webtoonId) + .orElseGet(() -> webtoonStatusCountService.save(webtoonId)); + webtoonStatusCount.updateCount(status); + + status = WebtoonStatusType.of(status); + webtoonStatusService.save(webtoonId, userId, status); + + return new WebtoonStatusResponse( + webtoonStatusCount, + status + ); + } + + @Transactional(readOnly = true) + public void statusCheck(Long userId, Long webtoonId) { + if (webtoonStatusService.existsByUserIdAndWebtoonIdAndStatus(userId, webtoonId, WebtoonStatusType.LEAVED)) { + throw new AlreadyLeavedException(); + } + if (webtoonStatusService.existsByUserIdAndWebtoonIdAndStatus(userId, webtoonId, WebtoonStatusType.JOINED)) { + throw new AlreadyJoinedException(); + } + } + + @Transactional + public void changeAllStatus() { + webtoonStatusService.findAllByStatus(WebtoonStatusType.JOINED) + .forEach(webtoonStatus -> { + webtoonStatus.updateStatus(WebtoonStatusType.NONE); + webtoonStatusCountService.findByWebtoonId(webtoonStatus.getWebtoonId()) + .ifPresent(ws -> ws.updateCount(WebtoonStatusType.JOINED)); + }); + + webtoonStatusService.findAllByStatus(WebtoonStatusType.LEAVED) + .forEach(webtoonStatus -> { + webtoonStatus.updateStatus(WebtoonStatusType.NONE); + webtoonStatusCountService.findByWebtoonId(webtoonStatus.getWebtoonId()) + .ifPresent(ws -> ws.updateCount(WebtoonStatusType.LEAVED)); + }); + } +} diff --git a/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonRepository.java b/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonRepository.java index 5b06e696..cde9649f 100644 --- a/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonRepository.java +++ b/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonRepository.java @@ -34,9 +34,9 @@ public interface WebtoonRepository extends JpaRepository, JpaSpec wg.id as webtoonGenreId, wg.genre_category as genreCategory, wpd.id as webtoonPublishDayId, wpd.day, ww.id as webtoonWriterId, ww.name, - rc.id as recommendationCountId, rc.join_count as joinCount, rc.leave_count as leaveCount, + wsc.id as webtoonStatusCountId, wsc.join_count as joinCount, wsc.leave_count as leaveCount, gss.graph_score as graphScore, gss.score_gap as scoreGap, - r.status as recommendationStatus, + ws.status as webtoonStatus, tr.ranking as ranking, c.id as characterId, c.name as characterName, @@ -47,8 +47,8 @@ public interface WebtoonRepository extends JpaRepository, JpaSpec left join webtoon_writer ww on w.id = ww.webtoon_id left join graph_score_snapshot gss on w.id = gss.webtoon_id left join top_rank tr on w.id = tr.webtoon_id - left join recommendation_count rc on w.id = rc.webtoon_id - left join recommendation r on w.id = r.webtoon_id + left join webtoon_status_count wsc on w.id = wsc.webtoon_id + left join webtoon_status ws on w.id = ws.webtoon_id left join ( select c.id as id, c.webtoon_id as webtoon_id, c.name as name, ci.image_url as image_url from characters c diff --git a/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonStatusCountRepository.java b/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonStatusCountRepository.java new file mode 100644 index 00000000..8eec6b10 --- /dev/null +++ b/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonStatusCountRepository.java @@ -0,0 +1,12 @@ +package kr.co.antoon.webtoon.infrastructure; + +import kr.co.antoon.webtoon.domain.WebtoonStatusCount; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface WebtoonStatusCountRepository extends JpaRepository { + Optional findByWebtoonId(Long webtoonId); +} diff --git a/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonStatusRepository.java b/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonStatusRepository.java new file mode 100644 index 00000000..42caf0cb --- /dev/null +++ b/src/main/java/kr/co/antoon/webtoon/infrastructure/WebtoonStatusRepository.java @@ -0,0 +1,11 @@ +package kr.co.antoon.webtoon.infrastructure; + +import kr.co.antoon.webtoon.domain.WebtoonStatus; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface WebtoonStatusRepository extends JpaRepository { + Boolean existsByUserIdAndWebtoonIdAndStatus(long userId, long webtoonId, WebtoonStatusType status); +} diff --git a/src/main/java/kr/co/antoon/webtoon/presentation/WebtoonController.java b/src/main/java/kr/co/antoon/webtoon/presentation/WebtoonController.java index 6466e888..d624d00c 100644 --- a/src/main/java/kr/co/antoon/webtoon/presentation/WebtoonController.java +++ b/src/main/java/kr/co/antoon/webtoon/presentation/WebtoonController.java @@ -2,8 +2,14 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import kr.co.antoon.coin.application.AntCoinService; import kr.co.antoon.common.dto.ResponseDto; import kr.co.antoon.common.dto.SwaggerNote; +import kr.co.antoon.oauth.config.AuthUser; +import kr.co.antoon.oauth.dto.AuthInfo; +import kr.co.antoon.webtoon.domain.vo.WebtoonStatusType; +import kr.co.antoon.webtoon.dto.response.WebtoonStatusResponse; +import kr.co.antoon.webtoon.facade.WebtoonStatusFacade; import kr.co.antoon.webtoon.application.WebtoonService; import kr.co.antoon.webtoon.dto.request.WebtoonSearchRequest; import kr.co.antoon.webtoon.facade.WebtoonFacade; @@ -12,6 +18,7 @@ import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -27,7 +34,9 @@ @RequestMapping(value = "/api/v1/webtoons", produces = APPLICATION_JSON_UTF_8) public class WebtoonController { private final WebtoonFacade webtoonFacade; + private final WebtoonStatusFacade webtoonStatusFacade; private final WebtoonService webtoonService; + private final AntCoinService antCoinService; @ApiOperation(value = "웹툰 상세 조회 API", notes = SwaggerNote.WEBTOON_READ_DETAIL) @GetMapping(value = "/{webtoonId}") @@ -93,5 +102,18 @@ public ResponseEntity search(@RequestBody WebtoonSearchRequest request) { var response = webtoonFacade.search(request); return ResponseDto.ok(response); } + + @ApiOperation(value = "웹툰 탑승/하차", notes = SwaggerNote.WEBTOON_JOIN) + @PatchMapping("/{webtoonId}/join") + public ResponseEntity createWebtoonStatus( + @PathVariable Long webtoonId, + @AuthUser AuthInfo info, + @RequestParam("status") WebtoonStatusType status + ) { + // TODO 해당 로직 처리는 여기서 하는게 이상해보이네요 response가 두번 사용되는 것도... + var response = webtoonStatusFacade.saveOrUpdate(status, info.userId(), webtoonId); + response = antCoinService.joinWebtoon(info.userId(), webtoonId, response, status); + return ResponseDto.ok(response); + } } diff --git a/src/test/java/kr/co/antoon/criteria/BasicAllocateScoreTest.java b/src/test/java/kr/co/antoon/criteria/BasicAllocateScoreTest.java index fe220d91..92bbec6a 100644 --- a/src/test/java/kr/co/antoon/criteria/BasicAllocateScoreTest.java +++ b/src/test/java/kr/co/antoon/criteria/BasicAllocateScoreTest.java @@ -67,7 +67,7 @@ class BasicAllocateScoreTest { "1" }) void 추천_점수_합은_300점을_초과할_수_없음(String score) { - int actual = basicAllocateScore.recommendationScore(Integer.parseInt(score)); + int actual = basicAllocateScore.webtoonStatusScore(Integer.parseInt(score)); int expected = 300; @@ -81,8 +81,8 @@ class BasicAllocateScoreTest { "0, 100, 100", "0, 0, 0" }) - void 그래프_점수는_최소_250점을_넘는다(int discussionScore, int recommendationScore, int webtoonScore) { - int actual = basicAllocateScore.graphScore(discussionScore, recommendationScore, webtoonScore); + void 그래프_점수는_최소_250점을_넘는다(int discussionScore, int webtoonStatusScore, int webtoonScore) { + int actual = basicAllocateScore.graphScore(discussionScore, webtoonStatusScore, webtoonScore); assertTrue((actual >= 250)); } diff --git a/src/test/java/kr/co/antoon/recommendation/domain/RecommendationCountTest.java b/src/test/java/kr/co/antoon/recommendation/domain/RecommendationCountTest.java deleted file mode 100644 index 743ddcd1..00000000 --- a/src/test/java/kr/co/antoon/recommendation/domain/RecommendationCountTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package kr.co.antoon.recommendation.domain; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class RecommendationCountTest { - private RecommendationCount recommendationCount; - - @BeforeEach - void setup() { - recommendationCount = new RecommendationCount(); - } - - @Test - void 카운트처리() { - int actual = recommendationCount.count(); - assertEquals(0, actual); - } -} \ No newline at end of file diff --git a/src/test/java/kr/co/antoon/webtoon/domain/WebtoonStatusCountTest.java b/src/test/java/kr/co/antoon/webtoon/domain/WebtoonStatusCountTest.java new file mode 100644 index 00000000..b3a40448 --- /dev/null +++ b/src/test/java/kr/co/antoon/webtoon/domain/WebtoonStatusCountTest.java @@ -0,0 +1,22 @@ +package kr.co.antoon.webtoon.domain; + +import kr.co.antoon.webtoon.domain.WebtoonStatusCount; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class WebtoonStatusCountTest { + private WebtoonStatusCount webtoonStatusCount; + + @BeforeEach + void setup() { + webtoonStatusCount = new WebtoonStatusCount(); + } + + @Test + void 카운트처리() { + int actual = webtoonStatusCount.count(); + assertEquals(0, actual); + } +} \ No newline at end of file diff --git a/src/test/java/kr/co/antoon/recommendation/presentation/RecommendationControllerTest.java b/src/test/java/kr/co/antoon/webtoon/presentation/WebtoonControllerTest.java similarity index 83% rename from src/test/java/kr/co/antoon/recommendation/presentation/RecommendationControllerTest.java rename to src/test/java/kr/co/antoon/webtoon/presentation/WebtoonControllerTest.java index 6db85e45..89d51950 100644 --- a/src/test/java/kr/co/antoon/recommendation/presentation/RecommendationControllerTest.java +++ b/src/test/java/kr/co/antoon/webtoon/presentation/WebtoonControllerTest.java @@ -1,36 +1,27 @@ -package kr.co.antoon.recommendation.presentation; +package kr.co.antoon.webtoon.presentation; -import kr.co.antoon.error.exception.BusinessException; -import kr.co.antoon.recommendation.domain.Recommendation; -import kr.co.antoon.recommendation.domain.vo.RecommendationStatus; -import kr.co.antoon.recommendation.infrastructure.RecommendationRepository; -import kr.co.antoon.webtoon.domain.Webtoon; -import kr.co.antoon.webtoon.domain.vo.Platform; +import kr.co.antoon.webtoon.infrastructure.WebtoonStatusRepository; import kr.co.antoon.webtoon.infrastructure.WebtoonRepository; import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @Slf4j @SpringBootTest @AutoConfigureMockMvc -public class RecommendationControllerTest { +public class WebtoonControllerTest { @Autowired private MockMvc mockMvc; @Autowired - private RecommendationRepository recommendationRepository; + private WebtoonStatusRepository webtoonStatusRepository; @Autowired private WebtoonRepository webtoonRepository; From 9a2404141a5a8af87a83cfdb062adcba74bad044 Mon Sep 17 00:00:00 2001 From: yunyoung1819 Date: Mon, 5 Sep 2022 17:49:10 +0900 Subject: [PATCH 2/2] =?UTF-8?q?:recycle:=20[refactor]=20TODO=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=A0=81=ED=9E=8C=20=EB=B6=80=EB=B6=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/co/antoon/webtoon/facade/WebtoonStatusFacade.java | 9 +++++---- .../antoon/webtoon/presentation/WebtoonController.java | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/kr/co/antoon/webtoon/facade/WebtoonStatusFacade.java b/src/main/java/kr/co/antoon/webtoon/facade/WebtoonStatusFacade.java index a270b08d..e8db2ee5 100644 --- a/src/main/java/kr/co/antoon/webtoon/facade/WebtoonStatusFacade.java +++ b/src/main/java/kr/co/antoon/webtoon/facade/WebtoonStatusFacade.java @@ -1,5 +1,6 @@ package kr.co.antoon.webtoon.facade; +import kr.co.antoon.coin.application.AntCoinService; import kr.co.antoon.error.exception.webtoon.AlreadyJoinedException; import kr.co.antoon.error.exception.webtoon.AlreadyLeavedException; import kr.co.antoon.webtoon.application.WebtoonStatusCountService; @@ -16,21 +17,21 @@ public class WebtoonStatusFacade { private final WebtoonStatusService webtoonStatusService; private final WebtoonStatusCountService webtoonStatusCountService; + private final AntCoinService antCoinService; @Transactional public WebtoonStatusResponse saveOrUpdate(WebtoonStatusType status, Long userId, Long webtoonId) { statusCheck(userId, webtoonId); + WebtoonStatusCount webtoonStatusCount = webtoonStatusCountService.findByWebtoonId(webtoonId) .orElseGet(() -> webtoonStatusCountService.save(webtoonId)); webtoonStatusCount.updateCount(status); status = WebtoonStatusType.of(status); webtoonStatusService.save(webtoonId, userId, status); + WebtoonStatusResponse response = new WebtoonStatusResponse(webtoonStatusCount, status); - return new WebtoonStatusResponse( - webtoonStatusCount, - status - ); + return antCoinService.joinWebtoon(userId, webtoonId, response, status); } @Transactional(readOnly = true) diff --git a/src/main/java/kr/co/antoon/webtoon/presentation/WebtoonController.java b/src/main/java/kr/co/antoon/webtoon/presentation/WebtoonController.java index d624d00c..7b7e89a3 100644 --- a/src/main/java/kr/co/antoon/webtoon/presentation/WebtoonController.java +++ b/src/main/java/kr/co/antoon/webtoon/presentation/WebtoonController.java @@ -36,7 +36,7 @@ public class WebtoonController { private final WebtoonFacade webtoonFacade; private final WebtoonStatusFacade webtoonStatusFacade; private final WebtoonService webtoonService; - private final AntCoinService antCoinService; + @ApiOperation(value = "웹툰 상세 조회 API", notes = SwaggerNote.WEBTOON_READ_DETAIL) @GetMapping(value = "/{webtoonId}") @@ -110,9 +110,8 @@ public ResponseEntity createWebtoonStatus( @AuthUser AuthInfo info, @RequestParam("status") WebtoonStatusType status ) { - // TODO 해당 로직 처리는 여기서 하는게 이상해보이네요 response가 두번 사용되는 것도... + var response = webtoonStatusFacade.saveOrUpdate(status, info.userId(), webtoonId); - response = antCoinService.joinWebtoon(info.userId(), webtoonId, response, status); return ResponseDto.ok(response); } }