diff --git a/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/api/content/repository/ContentRepository.java b/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/api/content/repository/ContentRepository.java index 86ab5f6..574f33f 100644 --- a/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/api/content/repository/ContentRepository.java +++ b/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/api/content/repository/ContentRepository.java @@ -47,4 +47,7 @@ default Content findContentByIdOrThrow(Long contentId) { } List findContentByMember(Member member); + + @Query("SELECT c FROM Content c WHERE c.createdAt BETWEEN :startTime AND :endTime ORDER BY c.createdAt ASC") + List findAllContentsBetweenDatesOrderedByAsc(LocalDateTime startTime, LocalDateTime endTime); } \ No newline at end of file diff --git a/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/api/member/repository/MemberRepository.java b/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/api/member/repository/MemberRepository.java index 31bd8a8..6867566 100644 --- a/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/api/member/repository/MemberRepository.java +++ b/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/api/member/repository/MemberRepository.java @@ -9,6 +9,7 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.util.List; import java.util.Optional; public interface MemberRepository extends JpaRepository { @@ -39,4 +40,7 @@ default Member findByRefreshTokenOrThrow(String refreshToken) { void deleteMemberScheduledForDeletion(LocalDateTime currentDate); Member findMemberBySocialId(String socialId); + + @Query("SELECT m FROM Member m WHERE m.isDeleted = false") + List findAllActiveMembers(); } \ No newline at end of file diff --git a/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/common/crontab/PopularContentScheduler.java b/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/common/crontab/PopularContentScheduler.java new file mode 100644 index 0000000..1c5a71e --- /dev/null +++ b/DontBeServer/src/main/java/com/dontbe/www/DontBeServer/common/crontab/PopularContentScheduler.java @@ -0,0 +1,81 @@ +package com.dontbe.www.DontBeServer.common.crontab; + +import com.dontbe.www.DontBeServer.api.comment.repository.CommentRepository; +import com.dontbe.www.DontBeServer.api.content.domain.Content; +import com.dontbe.www.DontBeServer.api.content.repository.ContentLikedRepository; +import com.dontbe.www.DontBeServer.api.content.repository.ContentRepository; +import com.dontbe.www.DontBeServer.api.member.domain.Member; +import com.dontbe.www.DontBeServer.api.member.repository.MemberRepository; +import com.dontbe.www.DontBeServer.api.notification.domain.Notification; +import com.dontbe.www.DontBeServer.api.notification.repository.NotificationRepository; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.AbstractMap; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +@Service +public class PopularContentScheduler { + private final ContentRepository contentRepository; + private final ContentLikedRepository contentLikedRepository; + private final CommentRepository commentRepository; + private final NotificationRepository notificationRepository; + private final MemberRepository memberRepository; + + public PopularContentScheduler(ContentRepository contentRepository, ContentLikedRepository contentLikedRepository, + CommentRepository commentRepository, NotificationRepository notificationRepository, MemberRepository memberRepository){ + this.contentRepository = contentRepository; + this.contentLikedRepository = contentLikedRepository; + this.commentRepository = commentRepository; + this.notificationRepository = notificationRepository; + this.memberRepository = memberRepository; + } + + @Scheduled(cron = "0 0 4 * * ?") + @Transactional + public void popularContentNotification() { + LocalDateTime startOfYesterday = LocalDateTime.now().minusDays(1).toLocalDate().atStartOfDay(); + LocalDateTime endOfYesterday = startOfYesterday.plusDays(1).minusSeconds(1); + + List contents = contentRepository.findAllContentsBetweenDatesOrderedByAsc(startOfYesterday, endOfYesterday); + + Content topContent = contents.stream() + .map(c -> new AbstractMap.SimpleEntry<>(c, contentLikedRepository.countByContent(c) + commentRepository.countByContent(c) * 1.6)) + .filter(e -> e.getValue() >= 5) + .max(Comparator.comparingDouble(Map.Entry::getValue)) + .map(Map.Entry::getKey) + .orElse(null); + + if (topContent != null) { + Member topContentWriter = topContent.getMember(); + + Notification popularWriterNotification = Notification.builder() + .notificationTargetMember(topContentWriter) + .notificationTriggerMemberId(-1L) + .notificationTriggerType("popularWriter") + .notificationTriggerId(topContent.getId()) + .isNotificationChecked(false) + .notificationText("") + .build(); + Notification savedPopularWriterNotification = notificationRepository.save(popularWriterNotification); + + List activeMembers = memberRepository.findAllActiveMembers(); + + for (Member activeMember : activeMembers) { + Notification popularContentNotification = Notification.builder() + .notificationTargetMember(activeMember) + .notificationTriggerMemberId(-1L) + .notificationTriggerType("popularContent") + .notificationTriggerId(topContent.getId()) + .isNotificationChecked(false) + .notificationText(topContent.getContentText()) + .build(); + Notification savedPopularContentNotification = notificationRepository.save(popularContentNotification); + } + } + } +}