diff --git a/src/main/java/org/websoso/WSSServer/application/FeedFindApplication.java b/src/main/java/org/websoso/WSSServer/application/FeedFindApplication.java new file mode 100644 index 00000000..1f9abf1d --- /dev/null +++ b/src/main/java/org/websoso/WSSServer/application/FeedFindApplication.java @@ -0,0 +1,203 @@ +package org.websoso.WSSServer.application; + +import static org.websoso.WSSServer.exception.error.CustomAvatarError.AVATAR_NOT_FOUND; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Slice; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.websoso.WSSServer.domain.Avatar; +import org.websoso.WSSServer.domain.Genre; +import org.websoso.WSSServer.domain.GenrePreference; +import org.websoso.WSSServer.domain.common.FeedGetOption; +import org.websoso.WSSServer.dto.feed.FeedGetResponse; +import org.websoso.WSSServer.dto.feed.FeedInfo; +import org.websoso.WSSServer.dto.feed.FeedsGetResponse; +import org.websoso.WSSServer.dto.feed.InterestFeedGetResponse; +import org.websoso.WSSServer.dto.feed.InterestFeedsGetResponse; +import org.websoso.WSSServer.dto.popularFeed.PopularFeedGetResponse; +import org.websoso.WSSServer.dto.popularFeed.PopularFeedsGetResponse; +import org.websoso.WSSServer.dto.user.UserBasicInfo; +import org.websoso.WSSServer.exception.exception.CustomAvatarException; +import org.websoso.WSSServer.feed.domain.Feed; +import org.websoso.WSSServer.feed.domain.FeedImage; +import org.websoso.WSSServer.feed.domain.PopularFeed; +import org.websoso.WSSServer.feed.repository.LikeRepository; +import org.websoso.WSSServer.feed.service.FeedServiceImpl; +import org.websoso.WSSServer.library.domain.UserNovel; +import org.websoso.WSSServer.library.repository.UserNovelRepository; +import org.websoso.WSSServer.novel.domain.Novel; +import org.websoso.WSSServer.novel.service.NovelServiceImpl; +import org.websoso.WSSServer.repository.AvatarRepository; +import org.websoso.WSSServer.repository.GenrePreferenceRepository; +import org.websoso.WSSServer.user.domain.User; + +@Service +@RequiredArgsConstructor +public class FeedFindApplication { + + private final FeedServiceImpl feedServiceImpl; + private final NovelServiceImpl novelServiceImpl; + + private static final String DEFAULT_CATEGORY = "all"; + private static final int DEFAULT_PAGE_NUMBER = 0; + + //ToDo : 의존성 제거 필요 부분 + private final AvatarRepository avatarRepository; + private final LikeRepository likeRepository; + private final GenrePreferenceRepository genrePreferenceRepository; + private final UserNovelRepository userNovelRepository; + + @Transactional(readOnly = true) + public FeedGetResponse getFeedById(User user, Long feedId) { + Feed feed = feedServiceImpl.getFeedOrException(feedId); + UserBasicInfo feedUserBasicInfo = getUserBasicInfo(feed.getUser()); + Novel novel = getLinkedNovelOrNull(feed.getNovelId()); + Boolean isLiked = isUserLikedFeed(user, feed); + List relevantCategories = feed.getFeedCategories().stream() + .map(feedCategory -> feedCategory.getCategory().getCategoryName().getLabel()) + .collect(Collectors.toList()); + Boolean isMyFeed = isUserFeedOwner(feed.getUser(), user); + + return FeedGetResponse.of(feed, feedUserBasicInfo, novel, isLiked, relevantCategories, isMyFeed); + } + + private UserBasicInfo getUserBasicInfo(User user) { + return user.getUserBasicInfo( + avatarRepository.findById(user.getAvatarId()).orElseThrow(() -> + new CustomAvatarException(AVATAR_NOT_FOUND, "avatar with the given id was not found")) + .getAvatarImage()); + } + + private Novel getLinkedNovelOrNull(Long linkedNovelId) { + if (linkedNovelId == null) { + return null; + } + return novelServiceImpl.getNovelOrException(linkedNovelId); + } + + private Boolean isUserLikedFeed(User user, Feed feed) { + return likeRepository.existsByUserIdAndFeed(user.getUserId(), feed); + } + + private Boolean isUserFeedOwner(User createdUser, User user) { + return createdUser.equals(user); + } + + @Transactional(readOnly = true) + public FeedsGetResponse getFeeds(User user, String category, Long lastFeedId, int size, + FeedGetOption feedGetOption) { + Long userIdOrNull = Optional.ofNullable(user).map(User::getUserId).orElse(null); + + List genres = getPreferenceGenres(user); + + Slice feeds = findFeedsByCategoryLabel(getChosenCategoryOrDefault(category), lastFeedId, userIdOrNull, + PageRequest.of(DEFAULT_PAGE_NUMBER, size), feedGetOption, genres); + + List feedGetResponses = feeds.getContent().stream().filter(feed -> feed.isVisibleTo(userIdOrNull)) + .map(feed -> createFeedInfo(feed, user)).toList(); + + return FeedsGetResponse.of(getChosenCategoryOrDefault(category), feeds.hasNext(), feedGetResponses); + } + + private List getPreferenceGenres(User user) { + if (user == null) { + return null; + } + return genrePreferenceRepository.findByUser(user).stream().map(GenrePreference::getGenre).toList(); + } + + private static String getChosenCategoryOrDefault(String category) { + return Optional.ofNullable(category).orElse(DEFAULT_CATEGORY); + } + + private Slice findFeedsByCategoryLabel(String category, Long lastFeedId, Long userId, PageRequest pageRequest, + FeedGetOption feedGetOption, List genres) { + return feedServiceImpl.findFeedsByCategoryLabel(category, lastFeedId, userId, pageRequest, feedGetOption, + genres); + } + + private FeedInfo createFeedInfo(Feed feed, User user) { + UserBasicInfo userBasicInfo = getUserBasicInfo(feed.getUser()); + Novel novel = getLinkedNovelOrNull(feed.getNovelId()); + Boolean isLiked = user != null && isUserLikedFeed(user, feed); + List relevantCategories = feed.getFeedCategories().stream() + .map(feedCategory -> feedCategory.getCategory().getCategoryName().getLabel()) + .collect(Collectors.toList()); + Boolean isMyFeed = user != null && isUserFeedOwner(feed.getUser(), user); + Integer imageCount = feedServiceImpl.countByFeedId(feed.getFeedId()); + Optional thumbnailImage = feedServiceImpl.findThumbnailFeedImageByFeedId(feed.getFeedId()); + String thumbnailUrl = thumbnailImage.map(FeedImage::getUrl).orElse(null); + + return FeedInfo.of(feed, userBasicInfo, novel, isLiked, relevantCategories, isMyFeed, thumbnailUrl, imageCount, + user); + } + + @Transactional(readOnly = true) + public PopularFeedsGetResponse getPopularFeeds(User user) { + Long currentUserId = Optional.ofNullable(user).map(User::getUserId).orElse(null); + + List popularFeeds = Optional.ofNullable(user).map(u -> findPopularFeedsWithUser(u.getUserId())) + .orElseGet(this::findPopularFeedsWithoutUser); + + List popularFeedGetResponses = mapToPopularFeedGetResponseList(popularFeeds, + currentUserId); + + return new PopularFeedsGetResponse(popularFeedGetResponses); + } + + private List findPopularFeedsWithUser(Long userId) { + return feedServiceImpl.findPopularFeedsWithUser(userId); + } + + private List findPopularFeedsWithoutUser() { + return feedServiceImpl.findPopularFeedsWithoutUser(); + } + + private static List mapToPopularFeedGetResponseList(List popularFeeds, + Long currentUserId) { + return popularFeeds.stream().filter(pf -> pf.getFeed().isVisibleTo(currentUserId)) + .map(PopularFeedGetResponse::of).toList(); + } + + @Transactional(readOnly = true) + public InterestFeedsGetResponse getInterestFeeds(User user) { + List interestNovels = userNovelRepository.findByUserAndIsInterestTrue(user).stream() + .map(UserNovel::getNovel).toList(); + + if (interestNovels.isEmpty()) { + return InterestFeedsGetResponse.of(Collections.emptyList(), "NO_INTEREST_NOVELS"); + } + + Map novelMap = interestNovels.stream() + .collect(Collectors.toMap(Novel::getNovelId, novel -> novel)); + List interestNovelIds = new ArrayList<>(novelMap.keySet()); + + List interestFeeds = feedServiceImpl.findInterestFeeds(interestNovelIds); + + if (interestFeeds.isEmpty()) { + return InterestFeedsGetResponse.of(Collections.emptyList(), "NO_ASSOCIATED_FEEDS"); + } + + Set avatarIds = interestFeeds.stream().map(feed -> feed.getUser().getAvatarId()) + .collect(Collectors.toSet()); + Map avatarMap = avatarRepository.findAllById(avatarIds).stream() + .collect(Collectors.toMap(Avatar::getAvatarId, avatar -> avatar)); + + List interestFeedGetResponses = interestFeeds.stream() + .filter(feed -> feed.isVisibleTo(user.getUserId())).map(feed -> { + Novel novel = novelMap.get(feed.getNovelId()); + Avatar avatar = avatarMap.get(feed.getUser().getAvatarId()); + return InterestFeedGetResponse.of(novel, feed.getUser(), feed, avatar); + }).toList(); + return InterestFeedsGetResponse.of(interestFeedGetResponses, ""); + } +} diff --git a/src/main/java/org/websoso/WSSServer/application/FeedManagementApplication.java b/src/main/java/org/websoso/WSSServer/application/FeedManagementApplication.java new file mode 100644 index 00000000..18d0ec50 --- /dev/null +++ b/src/main/java/org/websoso/WSSServer/application/FeedManagementApplication.java @@ -0,0 +1,9 @@ +package org.websoso.WSSServer.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class FeedManagementApplication { +} diff --git a/src/main/java/org/websoso/WSSServer/application/ReportApplication.java b/src/main/java/org/websoso/WSSServer/application/ReportApplication.java new file mode 100644 index 00000000..bcea077e --- /dev/null +++ b/src/main/java/org/websoso/WSSServer/application/ReportApplication.java @@ -0,0 +1,105 @@ +package org.websoso.WSSServer.application; + +import static org.websoso.WSSServer.domain.common.DiscordWebhookMessageType.REPORT; +import static org.websoso.WSSServer.domain.common.ReportedType.IMPERTINENCE; +import static org.websoso.WSSServer.domain.common.ReportedType.SPOILER; +import static org.websoso.WSSServer.exception.error.CustomCommentError.ALREADY_REPORTED_COMMENT; +import static org.websoso.WSSServer.exception.error.CustomFeedError.ALREADY_REPORTED_FEED; +import static org.websoso.WSSServer.exception.error.CustomFeedError.SELF_REPORT_NOT_ALLOWED; +import static org.websoso.WSSServer.exception.error.CustomUserError.USER_NOT_FOUND; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.websoso.WSSServer.domain.common.DiscordWebhookMessage; +import org.websoso.WSSServer.domain.common.ReportedType; +import org.websoso.WSSServer.exception.error.CustomCommentError; +import org.websoso.WSSServer.exception.exception.CustomCommentException; +import org.websoso.WSSServer.exception.exception.CustomFeedException; +import org.websoso.WSSServer.exception.exception.CustomUserException; +import org.websoso.WSSServer.feed.domain.Comment; +import org.websoso.WSSServer.feed.domain.Feed; +import org.websoso.WSSServer.feed.service.CommentServiceImpl; +import org.websoso.WSSServer.feed.service.FeedServiceImpl; +import org.websoso.WSSServer.feed.service.ReportServiceImpl; +import org.websoso.WSSServer.service.DiscordMessageClient; +import org.websoso.WSSServer.service.MessageFormatter; +import org.websoso.WSSServer.user.domain.User; +import org.websoso.WSSServer.user.repository.UserRepository; + +@Service +@RequiredArgsConstructor +public class ReportApplication { + + private final FeedServiceImpl feedServiceImpl; + private final CommentServiceImpl commentServiceImpl; + private final ReportServiceImpl reportServiceImpl; + private final DiscordMessageClient discordMessageClient; + + //ToDo : 의존성 제거 필요 부분 + private final UserRepository userRepository; + + @Transactional + public void reportComment(User user, Long feedId, Long commentId, ReportedType reportedType) { + Feed feed = feedServiceImpl.getFeedOrException(feedId); + Comment comment = commentServiceImpl.findComment(commentId); + comment.validateFeedAssociation(feed); + + User commentCreatedUser = userRepository.findById(comment.getUserId()) + .orElseThrow(() -> new CustomUserException(USER_NOT_FOUND, "user with the given id was not found")); + + if (commentCreatedUser.equals(user)) { + throw new CustomCommentException(CustomCommentError.SELF_REPORT_NOT_ALLOWED, "cannot report own comment"); + } + + if (reportServiceImpl.isExistsByCommentAndUserAndReportedType(comment, user, reportedType)) { + throw new CustomCommentException(ALREADY_REPORTED_COMMENT, "comment has already been reported by the user"); + } + + reportServiceImpl.saveReportedComment(comment, user, reportedType); + + int reportedCount = reportServiceImpl.countByCommentAndReportedType(comment, reportedType); + boolean shouldHide = reportedType.isExceedingLimit(reportedCount); + + if (shouldHide) { + if (reportedType.equals(SPOILER)) { + comment.spoiler(); + } else if (reportedType.equals(IMPERTINENCE)) { + comment.hideComment(); + } + } + + discordMessageClient.sendDiscordWebhookMessage(DiscordWebhookMessage.of( + MessageFormatter.formatCommentReportMessage(user, feed, comment, reportedType, commentCreatedUser, + reportedCount, shouldHide), REPORT)); + } + + @Transactional + public void reportFeed(User user, Long feedId, ReportedType reportedType) { + Feed feed = feedServiceImpl.getFeedOrException(feedId); + + if (isUserFeedOwner(feed.getUser(), user)) { + throw new CustomFeedException(SELF_REPORT_NOT_ALLOWED, "cannot report own feed"); + } + + if (reportServiceImpl.isExistsByFeedAndUserAndReportedType(feed, user, reportedType)) { + throw new CustomFeedException(ALREADY_REPORTED_FEED, "feed has already been reported by the user"); + } + + reportServiceImpl.saveReportedFeed(feed, user, reportedType); + + int reportedCount = reportServiceImpl.countByFeedAndReportedType(feed, reportedType); + boolean shouldHide = reportedType.isExceedingLimit(reportedCount); + + if (shouldHide) { + feed.hideFeed(); + } + + discordMessageClient.sendDiscordWebhookMessage(DiscordWebhookMessage.of( + MessageFormatter.formatFeedReportMessage(user, feed, reportedType, reportedCount, shouldHide), REPORT)); + } + + private Boolean isUserFeedOwner(User createdUser, User user) { + return createdUser.equals(user); + } +} diff --git a/src/main/java/org/websoso/WSSServer/feed/controller/CommentController.java b/src/main/java/org/websoso/WSSServer/feed/controller/CommentController.java index ab48456c..a8f2ad89 100644 --- a/src/main/java/org/websoso/WSSServer/feed/controller/CommentController.java +++ b/src/main/java/org/websoso/WSSServer/feed/controller/CommentController.java @@ -16,24 +16,26 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import org.websoso.WSSServer.user.domain.User; +import org.websoso.WSSServer.application.CommentFindApplication; +import org.websoso.WSSServer.application.CommentManagementApplication; import org.websoso.WSSServer.dto.comment.CommentCreateRequest; import org.websoso.WSSServer.dto.comment.CommentUpdateRequest; import org.websoso.WSSServer.dto.comment.CommentsGetResponse; -import org.websoso.WSSServer.feed.service.CommentService; +import org.websoso.WSSServer.user.domain.User; @RequestMapping("/feeds") @RestController @RequiredArgsConstructor public class CommentController { - private final CommentService commentService; + private final CommentFindApplication commentFindApplication; + private final CommentManagementApplication commentManagementApplication; @PostMapping("/{feedId}/comments") @PreAuthorize("isAuthenticated() and @feedAccessValidator.canAccess(#feedId, #user)") public ResponseEntity createComment(@AuthenticationPrincipal User user, @PathVariable("feedId") Long feedId, @Valid @RequestBody CommentCreateRequest request) { - commentService.createComment(user, feedId, request); + commentManagementApplication.createComment(user, feedId, request); return ResponseEntity.status(NO_CONTENT).build(); } @@ -43,7 +45,7 @@ public ResponseEntity getComments(@AuthenticationPrincipal @PathVariable("feedId") Long feedId) { return ResponseEntity .status(OK) - .body(commentService.getComments(user, feedId)); + .body(commentFindApplication.getComments(user, feedId)); } @PutMapping("/{feedId}/comments/{commentId}") @@ -53,7 +55,7 @@ public ResponseEntity updateComment(@AuthenticationPrincipal User user, @PathVariable("feedId") Long feedId, @PathVariable("commentId") Long commentId, @Valid @RequestBody CommentUpdateRequest request) { - commentService.updateComment(user, feedId, commentId, request); + commentManagementApplication.updateComment(user, feedId, commentId, request); return ResponseEntity .status(NO_CONTENT) .build(); @@ -65,7 +67,7 @@ public ResponseEntity updateComment(@AuthenticationPrincipal User user, public ResponseEntity deleteComment(@AuthenticationPrincipal User user, @PathVariable("feedId") Long feedId, @PathVariable("commentId") Long commentId) { - commentService.deleteComment(user, feedId, commentId); + commentManagementApplication.deleteComment(user, feedId, commentId); return ResponseEntity .status(NO_CONTENT) .build(); diff --git a/src/main/java/org/websoso/WSSServer/feed/controller/FeedController.java b/src/main/java/org/websoso/WSSServer/feed/controller/FeedController.java index 7fc762b5..9f7ca44e 100644 --- a/src/main/java/org/websoso/WSSServer/feed/controller/FeedController.java +++ b/src/main/java/org/websoso/WSSServer/feed/controller/FeedController.java @@ -19,7 +19,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; -import org.websoso.WSSServer.user.domain.User; +import org.websoso.WSSServer.application.FeedFindApplication; import org.websoso.WSSServer.domain.common.FeedGetOption; import org.websoso.WSSServer.dto.feed.FeedCreateRequest; import org.websoso.WSSServer.dto.feed.FeedCreateResponse; @@ -31,7 +31,7 @@ import org.websoso.WSSServer.dto.feed.InterestFeedsGetResponse; import org.websoso.WSSServer.dto.popularFeed.PopularFeedsGetResponse; import org.websoso.WSSServer.feed.service.FeedService; -import org.websoso.WSSServer.feed.service.PopularFeedService; +import org.websoso.WSSServer.user.domain.User; @RequestMapping("/feeds") @RestController @@ -39,7 +39,7 @@ public class FeedController { private final FeedService feedService; - private final PopularFeedService popularFeedService; + private final FeedFindApplication feedFindApplication; @PostMapping @PreAuthorize("isAuthenticated()") @@ -57,7 +57,7 @@ public ResponseEntity getFeed(@AuthenticationPrincipal User use @PathVariable("feedId") Long feedId) { return ResponseEntity .status(OK) - .body(feedService.getFeedById(user, feedId)); + .body(feedFindApplication.getFeedById(user, feedId)); } @GetMapping @@ -68,7 +68,7 @@ public ResponseEntity getFeeds(@AuthenticationPrincipal User u @RequestParam(value = "feedsOption", required = false) FeedGetOption feedGetOption) { return ResponseEntity .status(OK) - .body(feedService.getFeeds(user, category, lastFeedId, size, feedGetOption)); + .body(feedFindApplication.getFeeds(user, category, lastFeedId, size, feedGetOption)); } @PutMapping("/{feedId}") @@ -116,7 +116,7 @@ public ResponseEntity unLikeFeed(@AuthenticationPrincipal User user, public ResponseEntity getPopularFeeds(@AuthenticationPrincipal User user) { return ResponseEntity .status(OK) - .body(popularFeedService.getPopularFeeds(user)); + .body(feedFindApplication.getPopularFeeds(user)); } @GetMapping("/interest") @@ -124,7 +124,7 @@ public ResponseEntity getPopularFeeds(@AuthenticationPr public ResponseEntity getInterestFeeds(@AuthenticationPrincipal User user) { return ResponseEntity .status(OK) - .body(feedService.getInterestFeeds(user)); + .body(feedFindApplication.getInterestFeeds(user)); } } diff --git a/src/main/java/org/websoso/WSSServer/feed/controller/ReportController.java b/src/main/java/org/websoso/WSSServer/feed/controller/ReportController.java index 6ace6c9a..5810d0dd 100644 --- a/src/main/java/org/websoso/WSSServer/feed/controller/ReportController.java +++ b/src/main/java/org/websoso/WSSServer/feed/controller/ReportController.java @@ -12,21 +12,21 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.websoso.WSSServer.application.ReportApplication; import org.websoso.WSSServer.user.domain.User; -import org.websoso.WSSServer.feed.service.ReportService; @RequestMapping("/feeds") @RestController @RequiredArgsConstructor public class ReportController { - private final ReportService reportService; + private final ReportApplication reportApplication; @PostMapping("/{feedId}/spoiler") @PreAuthorize("isAuthenticated() and @feedAccessValidator.canAccess(#feedId, #user)") public ResponseEntity reportFeedSpoiler(@AuthenticationPrincipal User user, @PathVariable("feedId") Long feedId) { - reportService.reportFeed(user, feedId, SPOILER); + reportApplication.reportFeed(user, feedId, SPOILER); return ResponseEntity .status(CREATED) .build(); @@ -36,7 +36,7 @@ public ResponseEntity reportFeedSpoiler(@AuthenticationPrincipal User user @PreAuthorize("isAuthenticated() and @feedAccessValidator.canAccess(#feedId, #user)") public ResponseEntity reportedFeedImpertinence(@AuthenticationPrincipal User user, @PathVariable("feedId") Long feedId) { - reportService.reportFeed(user, feedId, IMPERTINENCE); + reportApplication.reportFeed(user, feedId, IMPERTINENCE); return ResponseEntity .status(CREATED) .build(); @@ -47,7 +47,7 @@ public ResponseEntity reportedFeedImpertinence(@AuthenticationPrincipal Us public ResponseEntity reportCommentSpoiler(@AuthenticationPrincipal User user, @PathVariable("feedId") Long feedId, @PathVariable("commentId") Long commentId) { - reportService.reportComment(user, feedId, commentId, SPOILER); + reportApplication.reportComment(user, feedId, commentId, SPOILER); return ResponseEntity .status(CREATED) .build(); @@ -58,7 +58,7 @@ public ResponseEntity reportCommentSpoiler(@AuthenticationPrincipal User u public ResponseEntity reportCommentImpertinence(@AuthenticationPrincipal User user, @PathVariable("feedId") Long feedId, @PathVariable("commentId") Long commentId) { - reportService.reportComment(user, feedId, commentId, IMPERTINENCE); + reportApplication.reportComment(user, feedId, commentId, IMPERTINENCE); return ResponseEntity .status(CREATED) .build(); diff --git a/src/main/java/org/websoso/WSSServer/feed/service/FeedServiceImpl.java b/src/main/java/org/websoso/WSSServer/feed/service/FeedServiceImpl.java index 53d7fe2a..2f0c6ca9 100644 --- a/src/main/java/org/websoso/WSSServer/feed/service/FeedServiceImpl.java +++ b/src/main/java/org/websoso/WSSServer/feed/service/FeedServiceImpl.java @@ -1,23 +1,99 @@ package org.websoso.WSSServer.feed.service; +import static org.websoso.WSSServer.exception.error.CustomCategoryError.INVALID_CATEGORY_FORMAT; import static org.websoso.WSSServer.exception.error.CustomFeedError.FEED_NOT_FOUND; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.websoso.WSSServer.domain.Genre; +import org.websoso.WSSServer.domain.common.CategoryName; +import org.websoso.WSSServer.domain.common.FeedGetOption; +import org.websoso.WSSServer.exception.exception.CustomCategoryException; import org.websoso.WSSServer.exception.exception.CustomFeedException; +import org.websoso.WSSServer.feed.domain.Category; import org.websoso.WSSServer.feed.domain.Feed; +import org.websoso.WSSServer.feed.domain.FeedImage; +import org.websoso.WSSServer.feed.domain.PopularFeed; +import org.websoso.WSSServer.feed.repository.CategoryRepository; +import org.websoso.WSSServer.feed.repository.FeedCategoryRepository; +import org.websoso.WSSServer.feed.repository.FeedImageCustomRepository; +import org.websoso.WSSServer.feed.repository.FeedImageRepository; import org.websoso.WSSServer.feed.repository.FeedRepository; +import org.websoso.WSSServer.feed.repository.PopularFeedRepository; @Service @RequiredArgsConstructor public class FeedServiceImpl { private final FeedRepository feedRepository; + private final FeedCategoryRepository feedCategoryRepository; + private final CategoryRepository categoryRepository; + private final FeedImageRepository feedImageRepository; + private final FeedImageCustomRepository feedImageCustomRepository; + private final PopularFeedRepository popularFeedRepository; + + private static final String DEFAULT_CATEGORY = "all"; @Transactional(readOnly = true) public Feed getFeedOrException(Long feedId) { return feedRepository.findById(feedId) .orElseThrow(() -> new CustomFeedException(FEED_NOT_FOUND, "feed with the given id was not found")); } + + @Transactional(readOnly = true) + public Slice findFeedsByCategoryLabel(String category, Long lastFeedId, Long userId, PageRequest pageRequest, + FeedGetOption feedGetOption, List genres) { + if (DEFAULT_CATEGORY.equals(category)) { + if (FeedGetOption.isAll(feedGetOption)) { + return feedRepository.findFeeds(lastFeedId, userId, pageRequest); + } else { + return feedRepository.findRecommendedFeeds(lastFeedId, userId, pageRequest, genres); + } + } else { + if (FeedGetOption.isAll(feedGetOption)) { + return feedCategoryRepository.findFeedsByCategory(findCategoryByName(category), lastFeedId, userId, + pageRequest); + } else { + return feedCategoryRepository.findRecommendedFeedsByCategoryLabel(findCategoryByName(category), + lastFeedId, userId, pageRequest, genres); + } + } + } + + // 이 부분 private으로 두는 게 맞을지 아니면 public으로 두는 게 나을지 고민 + private Category findCategoryByName(String categoryName) { + return categoryRepository.findByCategoryName(CategoryName.valueOf(categoryName)).orElseThrow( + () -> new CustomCategoryException(INVALID_CATEGORY_FORMAT, + "Category for the given feed was not found")); + } + + @Transactional(readOnly = true) + public Integer countByFeedId(Long feedId) { + return feedImageRepository.countByFeedId(feedId); + } + + @Transactional(readOnly = true) + public Optional findThumbnailFeedImageByFeedId(Long feedId) { + return feedImageCustomRepository.findThumbnailFeedImageByFeedId(feedId); + } + + @Transactional(readOnly = true) + public List findPopularFeedsWithUser(Long userId) { + return popularFeedRepository.findTodayPopularFeeds(userId); + } + + @Transactional(readOnly = true) + public List findPopularFeedsWithoutUser() { + return popularFeedRepository.findTop9ByOrderByPopularFeedIdDesc(); + } + + @Transactional(readOnly = true) + public List findInterestFeeds(List interestNovelIds) { + return feedRepository.findTop10ByNovelIdInOrderByFeedIdDesc(interestNovelIds); + } } diff --git a/src/main/java/org/websoso/WSSServer/feed/service/ReportServiceImpl.java b/src/main/java/org/websoso/WSSServer/feed/service/ReportServiceImpl.java new file mode 100644 index 00000000..0b30326f --- /dev/null +++ b/src/main/java/org/websoso/WSSServer/feed/service/ReportServiceImpl.java @@ -0,0 +1,51 @@ +package org.websoso.WSSServer.feed.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.websoso.WSSServer.domain.common.ReportedType; +import org.websoso.WSSServer.feed.domain.Comment; +import org.websoso.WSSServer.feed.domain.Feed; +import org.websoso.WSSServer.feed.domain.ReportedComment; +import org.websoso.WSSServer.feed.domain.ReportedFeed; +import org.websoso.WSSServer.feed.repository.ReportedCommentRepository; +import org.websoso.WSSServer.feed.repository.ReportedFeedRepository; +import org.websoso.WSSServer.user.domain.User; + +@Service +@RequiredArgsConstructor +public class ReportServiceImpl { + + private final ReportedCommentRepository reportedCommentRepository; + private final ReportedFeedRepository reportedFeedRepository; + + @Transactional(readOnly = true) + public Boolean isExistsByCommentAndUserAndReportedType(Comment comment, User user, ReportedType reportedType) { + return reportedCommentRepository.existsByCommentAndUserAndReportedType(comment, user, reportedType); + } + + @Transactional + public void saveReportedComment(Comment comment, User user, ReportedType reportedType) { + reportedCommentRepository.save(ReportedComment.create(comment, user, reportedType)); + } + + @Transactional(readOnly = true) + public int countByCommentAndReportedType(Comment comment, ReportedType reportedType) { + return reportedCommentRepository.countByCommentAndReportedType(comment, reportedType); + } + + @Transactional(readOnly = true) + public Boolean isExistsByFeedAndUserAndReportedType(Feed feed, User user, ReportedType reportedType) { + return reportedFeedRepository.existsByFeedAndUserAndReportedType(feed, user, reportedType); + } + + @Transactional + public void saveReportedFeed(Feed feed, User user, ReportedType reportedType) { + reportedFeedRepository.save(ReportedFeed.create(feed, user, reportedType)); + } + + @Transactional(readOnly = true) + public int countByFeedAndReportedType(Feed feed, ReportedType reportedType) { + return reportedFeedRepository.countByFeedAndReportedType(feed, reportedType); + } +}