diff --git a/module-application/src/main/java/com/devtoon/jtoon/webtoon/application/WebtoonApplicationService.java b/module-application/src/main/java/com/devtoon/jtoon/webtoon/application/WebtoonApplicationService.java index 375af78c..054c041e 100644 --- a/module-application/src/main/java/com/devtoon/jtoon/webtoon/application/WebtoonApplicationService.java +++ b/module-application/src/main/java/com/devtoon/jtoon/webtoon/application/WebtoonApplicationService.java @@ -24,6 +24,7 @@ import com.devtoon.jtoon.webtoon.response.EpisodesRes; import com.devtoon.jtoon.webtoon.response.WebtoonInfoRes; import com.devtoon.jtoon.webtoon.response.WebtoonItemRes; +import com.devtoon.jtoon.webtoon.service.EpisodeDomainService; import com.devtoon.jtoon.webtoon.service.WebtoonDomainService; import lombok.RequiredArgsConstructor; @@ -33,18 +34,15 @@ public class WebtoonApplicationService { private final WebtoonDomainService webtoonDomainService; + private final EpisodeDomainService episodeDomainService; private final S3Service s3Service; @Transactional public void createWebtoon(MultipartFile thumbnailImage, CreateWebtoonReq request) { Member member = MemberThreadLocal.getMember(); webtoonDomainService.validateDuplicateTitle(request.title()); - String thumbnailUrl = s3Service.upload(UploadImageReq.builder() - .imageType(WEBTOON_THUMBNAIL) - .webtoonTitle(request.title()) - .fileName(FileName.forWebtoon()) - .image(thumbnailImage) - .build() + String thumbnailUrl = s3Service.upload( + UploadImageReq.of(WEBTOON_THUMBNAIL, request.title(), FileName.forWebtoon(), thumbnailImage) ); webtoonDomainService.createWebtoon(member, thumbnailUrl, request); } @@ -59,21 +57,13 @@ public void createEpisode( Member member = MemberThreadLocal.getMember(); Webtoon webtoon = webtoonDomainService.getWebtoonById(webtoonId); webtoon.validateAuthor(member.getId()); - String mainUrl = s3Service.upload(UploadImageReq.builder() - .imageType(EPISODE_MAIN) - .webtoonTitle(webtoon.getTitle()) - .fileName(FileName.forEpisode(request.no())) - .image(mainImage) - .build() + String mainUrl = s3Service.upload( + UploadImageReq.of(EPISODE_MAIN, webtoon.getTitle(), FileName.forEpisode(request.no()), mainImage) ); - String thumbnailUrl = s3Service.upload(UploadImageReq.builder() - .imageType(EPISODE_THUMBNAIL) - .webtoonTitle(webtoon.getTitle()) - .fileName(FileName.forEpisode(request.no())) - .image(thumbnailImage) - .build() + String thumbnailUrl = s3Service.upload( + UploadImageReq.of(EPISODE_THUMBNAIL, webtoon.getTitle(), FileName.forEpisode(request.no()), thumbnailImage) ); - webtoonDomainService.createEpisode(webtoon, mainUrl, thumbnailUrl, request); + episodeDomainService.createEpisode(webtoon, mainUrl, thumbnailUrl, request); } public Map> getWebtoons(GetWebtoonsReq request) { @@ -85,16 +75,16 @@ public WebtoonInfoRes getWebtoon(Long webtoonId) { } public List getEpisodes(Long webtoonId, CustomPageRequest request) { - return webtoonDomainService.getEpisodes(webtoonId, request); + return episodeDomainService.getEpisodes(webtoonId, request); } public EpisodeRes getEpisode(Long episodeId) { - return webtoonDomainService.getEpisode(episodeId); + return episodeDomainService.getEpisode(episodeId); } @Transactional public void purchaseEpisode(Long episodeId) { Member member = MemberThreadLocal.getMember(); - webtoonDomainService.purchaseEpisode(member, episodeId); + episodeDomainService.purchaseEpisode(member, episodeId); } } diff --git a/module-domain-s3/src/main/java/com/devtoon/jtoon/request/UploadImageReq.java b/module-domain-s3/src/main/java/com/devtoon/jtoon/request/UploadImageReq.java index 6ec8175e..04c54613 100644 --- a/module-domain-s3/src/main/java/com/devtoon/jtoon/request/UploadImageReq.java +++ b/module-domain-s3/src/main/java/com/devtoon/jtoon/request/UploadImageReq.java @@ -15,6 +15,15 @@ public record UploadImageReq( MultipartFile image ) { + public static UploadImageReq of(ImageType imageType, String webtoonTitle, FileName fileName, MultipartFile image) { + return UploadImageReq.builder() + .imageType(imageType) + .webtoonTitle(webtoonTitle) + .fileName(fileName) + .image(image) + .build(); + } + public String toKey() { return imageType.getPath(webtoonTitle, fileName.getValue()); } diff --git a/module-domain/src/main/java/com/devtoon/jtoon/webtoon/service/EpisodeDomainService.java b/module-domain/src/main/java/com/devtoon/jtoon/webtoon/service/EpisodeDomainService.java new file mode 100644 index 00000000..38e9100d --- /dev/null +++ b/module-domain/src/main/java/com/devtoon/jtoon/webtoon/service/EpisodeDomainService.java @@ -0,0 +1,76 @@ +package com.devtoon.jtoon.webtoon.service; + +import static com.devtoon.jtoon.error.model.ErrorStatus.*; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.devtoon.jtoon.error.exception.NotFoundException; +import com.devtoon.jtoon.global.util.CustomPageRequest; +import com.devtoon.jtoon.member.entity.Member; +import com.devtoon.jtoon.member.entity.MemberCookie; +import com.devtoon.jtoon.payment.repository.MemberCookieRepository; +import com.devtoon.jtoon.webtoon.entity.Episode; +import com.devtoon.jtoon.webtoon.entity.PurchasedEpisode; +import com.devtoon.jtoon.webtoon.entity.Webtoon; +import com.devtoon.jtoon.webtoon.repository.EpisodeRepository; +import com.devtoon.jtoon.webtoon.repository.EpisodeSearchRepository; +import com.devtoon.jtoon.webtoon.repository.PurchasedEpisodeRepository; +import com.devtoon.jtoon.webtoon.request.CreateEpisodeReq; +import com.devtoon.jtoon.webtoon.response.EpisodeRes; +import com.devtoon.jtoon.webtoon.response.EpisodesRes; + +import lombok.RequiredArgsConstructor; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class EpisodeDomainService { + + private final EpisodeRepository episodeRepository; + private final EpisodeSearchRepository episodeSearchRepository; + private final PurchasedEpisodeRepository purchasedEpisodeRepository; + private final MemberCookieRepository memberCookieRepository; + + @Transactional + public void createEpisode(Webtoon webtoon, String mainUrl, String thumbnailUrl, CreateEpisodeReq request) { + Episode episode = request.toEntity(webtoon, mainUrl, thumbnailUrl); + episodeRepository.save(episode); + } + + public List getEpisodes(Long webtoonId, CustomPageRequest request) { + return episodeSearchRepository.getEpisodes(webtoonId, request) + .stream() + .map(EpisodesRes::from) + .toList(); + } + + public EpisodeRes getEpisode(Long episodeId) { + Episode episode = getEpisodeById(episodeId); + return EpisodeRes.from(episode); + } + + @Transactional + public void purchaseEpisode(Member member, Long episodeId) { + Episode episode = getEpisodeById(episodeId); + MemberCookie memberCookie = getMemberCookieById(member.getId()); + memberCookie.decreaseCookieCount(episode.getCookieCount()); + purchasedEpisodeRepository.save(PurchasedEpisode.builder() + .member(member) + .episode(episode) + .build() + ); + } + + private Episode getEpisodeById(Long episodeId) { + return episodeRepository.findById(episodeId) + .orElseThrow(() -> new NotFoundException(EPISODE_NOT_FOUND)); + } + + private MemberCookie getMemberCookieById(Long memberId) { + return memberCookieRepository.findById(memberId) + .orElseThrow(() -> new NotFoundException(MEMBER_COOKIE_NOT_FOUND)); + } +} diff --git a/module-domain/src/main/java/com/devtoon/jtoon/webtoon/service/WebtoonDomainService.java b/module-domain/src/main/java/com/devtoon/jtoon/webtoon/service/WebtoonDomainService.java index 098ea6b6..803dd3d2 100644 --- a/module-domain/src/main/java/com/devtoon/jtoon/webtoon/service/WebtoonDomainService.java +++ b/module-domain/src/main/java/com/devtoon/jtoon/webtoon/service/WebtoonDomainService.java @@ -11,28 +11,19 @@ import com.devtoon.jtoon.error.exception.DuplicatedException; import com.devtoon.jtoon.error.exception.NotFoundException; -import com.devtoon.jtoon.global.util.CustomPageRequest; import com.devtoon.jtoon.member.entity.Member; import com.devtoon.jtoon.member.entity.MemberCookie; import com.devtoon.jtoon.payment.repository.MemberCookieRepository; import com.devtoon.jtoon.webtoon.entity.DayOfWeekWebtoon; -import com.devtoon.jtoon.webtoon.entity.Episode; import com.devtoon.jtoon.webtoon.entity.GenreWebtoon; -import com.devtoon.jtoon.webtoon.entity.PurchasedEpisode; import com.devtoon.jtoon.webtoon.entity.Webtoon; import com.devtoon.jtoon.webtoon.entity.enums.DayOfWeek; import com.devtoon.jtoon.webtoon.repository.DayOfWeekWebtoonRepository; -import com.devtoon.jtoon.webtoon.repository.EpisodeRepository; -import com.devtoon.jtoon.webtoon.repository.EpisodeSearchRepository; import com.devtoon.jtoon.webtoon.repository.GenreWebtoonRepository; -import com.devtoon.jtoon.webtoon.repository.PurchasedEpisodeRepository; import com.devtoon.jtoon.webtoon.repository.WebtoonRepository; import com.devtoon.jtoon.webtoon.repository.WebtoonSearchRepository; -import com.devtoon.jtoon.webtoon.request.CreateEpisodeReq; import com.devtoon.jtoon.webtoon.request.CreateWebtoonReq; import com.devtoon.jtoon.webtoon.request.GetWebtoonsReq; -import com.devtoon.jtoon.webtoon.response.EpisodeRes; -import com.devtoon.jtoon.webtoon.response.EpisodesRes; import com.devtoon.jtoon.webtoon.response.GenreRes; import com.devtoon.jtoon.webtoon.response.WebtoonInfoRes; import com.devtoon.jtoon.webtoon.response.WebtoonItemRes; @@ -48,10 +39,6 @@ public class WebtoonDomainService { private final WebtoonSearchRepository webtoonSearchRepository; private final DayOfWeekWebtoonRepository dayOfWeekWebtoonRepository; private final GenreWebtoonRepository genreWebtoonRepository; - private final EpisodeRepository episodeRepository; - private final EpisodeSearchRepository episodeSearchRepository; - private final PurchasedEpisodeRepository purchasedEpisodeRepository; - private final MemberCookieRepository memberCookieRepository; @Transactional public void createWebtoon(Member member, String thumbnailUrl, CreateWebtoonReq request) { @@ -63,12 +50,6 @@ public void createWebtoon(Member member, String thumbnailUrl, CreateWebtoonReq r genreWebtoonRepository.saveAll(genreWebtoons); } - @Transactional - public void createEpisode(Webtoon webtoon, String mainUrl, String thumbnailUrl, CreateEpisodeReq request) { - Episode episode = request.toEntity(webtoon, mainUrl, thumbnailUrl); - episodeRepository.save(episode); - } - public Map> getWebtoons(GetWebtoonsReq request) { return webtoonSearchRepository.findWebtoons(request.day(), request.keyword()) .stream() @@ -86,30 +67,6 @@ public WebtoonInfoRes getWebtoon(Long webtoonId) { return WebtoonInfoRes.of(webtoon, dayOfWeeks, genres); } - public List getEpisodes(Long webtoonId, CustomPageRequest request) { - return episodeSearchRepository.getEpisodes(webtoonId, request) - .stream() - .map(EpisodesRes::from) - .toList(); - } - - public EpisodeRes getEpisode(Long episodeId) { - Episode episode = getEpisodeById(episodeId); - return EpisodeRes.from(episode); - } - - @Transactional - public void purchaseEpisode(Member member, Long episodeId) { - Episode episode = getEpisodeById(episodeId); - MemberCookie memberCookie = getMemberCookieById(member.getId()); - memberCookie.decreaseCookieCount(episode.getCookieCount()); - purchasedEpisodeRepository.save(PurchasedEpisode.builder() - .member(member) - .episode(episode) - .build() - ); - } - public void validateDuplicateTitle(String title) { if (webtoonRepository.existsByTitle(title)) { throw new DuplicatedException(WEBTOON_TITLE_DUPLICATED); @@ -121,16 +78,6 @@ public Webtoon getWebtoonById(Long webtoonId) { .orElseThrow(() -> new NotFoundException(WEBTOON_NOT_FOUND)); } - private Episode getEpisodeById(Long episodeId) { - return episodeRepository.findById(episodeId) - .orElseThrow(() -> new NotFoundException(EPISODE_NOT_FOUND)); - } - - private MemberCookie getMemberCookieById(Long memberId) { - return memberCookieRepository.findById(memberId) - .orElseThrow(() -> new NotFoundException(MEMBER_COOKIE_NOT_FOUND)); - } - private List getDayOfWeeks(Long webtoonId) { return dayOfWeekWebtoonRepository.findById(webtoonId) .stream()