diff --git a/src/main/java/com/magamochi/model/specification/MangaSpecification.java b/src/main/java/com/magamochi/catalog/model/specification/MangaSpecification.java similarity index 98% rename from src/main/java/com/magamochi/model/specification/MangaSpecification.java rename to src/main/java/com/magamochi/catalog/model/specification/MangaSpecification.java index 8ad2c7c..d865a53 100644 --- a/src/main/java/com/magamochi/model/specification/MangaSpecification.java +++ b/src/main/java/com/magamochi/catalog/model/specification/MangaSpecification.java @@ -1,4 +1,4 @@ -package com.magamochi.model.specification; +package com.magamochi.catalog.model.specification; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; diff --git a/src/main/java/com/magamochi/catalog/service/MangaService.java b/src/main/java/com/magamochi/catalog/service/MangaService.java index e30f240..c4e1a9d 100644 --- a/src/main/java/com/magamochi/catalog/service/MangaService.java +++ b/src/main/java/com/magamochi/catalog/service/MangaService.java @@ -7,8 +7,8 @@ import com.magamochi.catalog.model.dto.MangaListDTO; import com.magamochi.catalog.model.dto.MangaListFilterDTO; import com.magamochi.catalog.model.entity.Manga; import com.magamochi.catalog.model.repository.MangaRepository; +import com.magamochi.catalog.model.specification.MangaSpecification; import com.magamochi.common.exception.NotFoundException; -import com.magamochi.model.specification.MangaSpecification; import com.magamochi.user.service.UserService; import com.magamochi.userinteraction.model.repository.UserFavoriteMangaRepository; import com.magamochi.userinteraction.model.repository.UserMangaFollowRepository; diff --git a/src/main/java/com/magamochi/common/config/RabbitConfig.java b/src/main/java/com/magamochi/common/config/RabbitConfig.java index e933b64..5f3e057 100644 --- a/src/main/java/com/magamochi/common/config/RabbitConfig.java +++ b/src/main/java/com/magamochi/common/config/RabbitConfig.java @@ -52,6 +52,9 @@ public class RabbitConfig { @Value("${queues.manga-content-download}") private String mangaContentDownloadQueue; + @Value("${queues.manga-follow-update-chapter}") + private String mangaFollowUpdateChapterQueue; + @Bean public TopicExchange imageUpdatesExchange() { return new TopicExchange(imageUpdatesTopic); @@ -220,11 +223,6 @@ public class RabbitConfig { return QueueBuilder.durable(mangaContentDownloadQueue + ".dlq").quorum().build(); } - // TODO: remove unused queues - - @Value("${rabbit-mq.queues.manga-follow-update-chapter}") - private String mangaFollowUpdateChapterQueue; - @Bean public Queue mangaFollowUpdateChapterQueue() { return QueueBuilder.durable(mangaFollowUpdateChapterQueue) diff --git a/src/main/java/com/magamochi/content/service/ContentIngestService.java b/src/main/java/com/magamochi/content/service/ContentIngestService.java index 3855a21..b1b0dc2 100644 --- a/src/main/java/com/magamochi/content/service/ContentIngestService.java +++ b/src/main/java/com/magamochi/content/service/ContentIngestService.java @@ -14,6 +14,7 @@ import com.magamochi.content.model.entity.MangaContentImage; import com.magamochi.content.model.repository.MangaContentImageRepository; import com.magamochi.content.model.repository.MangaContentRepository; import com.magamochi.image.service.ImageService; +import com.magamochi.userinteraction.service.UserMangaFollowService; import jakarta.validation.constraints.NotBlank; import java.util.UUID; import lombok.RequiredArgsConstructor; @@ -28,6 +29,7 @@ public class ContentIngestService { private final ContentService contentService; private final MangaContentProviderService mangaContentProviderService; private final LanguageService languageService; + private final UserMangaFollowService userMangaFollowService; private final MangaContentRepository mangaContentRepository; private final MangaContentImageRepository mangaContentImageRepository; @@ -66,6 +68,8 @@ public class ContentIngestService { .language(language) .build()); + userMangaFollowService.notifyNewMangaContent(mangaContent); + log.info( "Ingested Manga Content ({}) for provider {}: {}", title, diff --git a/src/main/java/com/magamochi/controller/ManagementController.java b/src/main/java/com/magamochi/controller/ManagementController.java index 46f428c..c6cdb35 100644 --- a/src/main/java/com/magamochi/controller/ManagementController.java +++ b/src/main/java/com/magamochi/controller/ManagementController.java @@ -3,8 +3,8 @@ package com.magamochi.controller; import com.magamochi.client.NtfyClient; import com.magamochi.common.model.dto.DefaultResponseDTO; import com.magamochi.image.task.ImageCleanupTask; -import com.magamochi.task.MangaFollowUpdateTask; import com.magamochi.user.repository.UserRepository; +import com.magamochi.userinteraction.task.MangaFollowUpdateTask; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/com/magamochi/service/OldMangaService.java b/src/main/java/com/magamochi/service/OldMangaService.java deleted file mode 100644 index 9d0e607..0000000 --- a/src/main/java/com/magamochi/service/OldMangaService.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.magamochi.service; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.springframework.stereotype.Service; - -@Log4j2 -@Service -@RequiredArgsConstructor -public class OldMangaService { - // public void fetchFollowedMangaChapters(Long mangaProviderId) { - // var mangaProvider = - // mangaContentProviderRepository - // .findById(mangaProviderId) - // .orElseThrow( - // () -> new NotFoundException("Manga Provider not found for ID: " + - // mangaProviderId)); - // - // var currentAvailableChapterCount = - // mangaChapterRepository.findByMangaContentProviderId(mangaProviderId).size(); - // - // fetchMangaChapters(mangaProviderId); - // mangaChapterRepository.flush(); - // - // var availableChapterCount = - // mangaChapterRepository.findByMangaContentProviderId(mangaProviderId).size(); - // - // if (availableChapterCount <= currentAvailableChapterCount) { - // return; - // } - // - // log.info("New chapters found for Manga Provider {}", mangaProviderId); - // - // var userMangaFollows = userMangaFollowRepository.findByManga(mangaProvider.getManga()); - // userMangaFollows.forEach( - // umf -> - // ntfyClient.notify( - // new NtfyClient.Request( - // "mangamochi-" + umf.getUser().getId().toString(), - // umf.getManga().getTitle(), - // "New chapter available on " + - // mangaProvider.getContentProvider().getName()))); - // } - -} diff --git a/src/main/java/com/magamochi/model/dto/UpdateMangaFollowChapterListCommand.java b/src/main/java/com/magamochi/userinteraction/queue/command/UpdateMangaFollowChapterListCommand.java similarity index 58% rename from src/main/java/com/magamochi/model/dto/UpdateMangaFollowChapterListCommand.java rename to src/main/java/com/magamochi/userinteraction/queue/command/UpdateMangaFollowChapterListCommand.java index 442ae9f..f47711c 100644 --- a/src/main/java/com/magamochi/model/dto/UpdateMangaFollowChapterListCommand.java +++ b/src/main/java/com/magamochi/userinteraction/queue/command/UpdateMangaFollowChapterListCommand.java @@ -1,3 +1,3 @@ -package com.magamochi.model.dto; +package com.magamochi.userinteraction.queue.command; public record UpdateMangaFollowChapterListCommand(Long mangaProviderId) {} diff --git a/src/main/java/com/magamochi/queue/UpdateMangaFollowChapterListConsumer.java b/src/main/java/com/magamochi/userinteraction/queue/consumer/UpdateMangaFollowChapterListConsumer.java similarity index 61% rename from src/main/java/com/magamochi/queue/UpdateMangaFollowChapterListConsumer.java rename to src/main/java/com/magamochi/userinteraction/queue/consumer/UpdateMangaFollowChapterListConsumer.java index 75efa22..cda3e7a 100644 --- a/src/main/java/com/magamochi/queue/UpdateMangaFollowChapterListConsumer.java +++ b/src/main/java/com/magamochi/userinteraction/queue/consumer/UpdateMangaFollowChapterListConsumer.java @@ -1,7 +1,7 @@ -package com.magamochi.queue; +package com.magamochi.userinteraction.queue.consumer; -import com.magamochi.model.dto.UpdateMangaFollowChapterListCommand; -import com.magamochi.service.OldMangaService; +import com.magamochi.userinteraction.queue.command.UpdateMangaFollowChapterListCommand; +import com.magamochi.userinteraction.service.UserMangaFollowService; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.amqp.rabbit.annotation.RabbitListener; @@ -11,11 +11,11 @@ import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class UpdateMangaFollowChapterListConsumer { - private final OldMangaService oldMangaService; + private final UserMangaFollowService userMangaFollowService; @RabbitListener(queues = "${rabbit-mq.queues.manga-follow-update-chapter}") public void receiveMangaFollowUpdateChapterCommand(UpdateMangaFollowChapterListCommand command) { log.info("Received update followed manga chapter list command: {}", command); - // oldMangaService.fetchFollowedMangaChapters(command.mangaProviderId()); + userMangaFollowService.checkForMangaUpdates(command.mangaProviderId()); } } diff --git a/src/main/java/com/magamochi/queue/UpdateMangaFollowChapterListProducer.java b/src/main/java/com/magamochi/userinteraction/queue/producer/UpdateMangaFollowChapterListProducer.java similarity index 84% rename from src/main/java/com/magamochi/queue/UpdateMangaFollowChapterListProducer.java rename to src/main/java/com/magamochi/userinteraction/queue/producer/UpdateMangaFollowChapterListProducer.java index 124d3a5..9329c58 100644 --- a/src/main/java/com/magamochi/queue/UpdateMangaFollowChapterListProducer.java +++ b/src/main/java/com/magamochi/userinteraction/queue/producer/UpdateMangaFollowChapterListProducer.java @@ -1,6 +1,6 @@ -package com.magamochi.queue; +package com.magamochi.userinteraction.queue.producer; -import com.magamochi.model.dto.UpdateMangaFollowChapterListCommand; +import com.magamochi.userinteraction.queue.command.UpdateMangaFollowChapterListCommand; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.amqp.rabbit.core.RabbitTemplate; diff --git a/src/main/java/com/magamochi/userinteraction/service/UserMangaFollowService.java b/src/main/java/com/magamochi/userinteraction/service/UserMangaFollowService.java index f01a744..b802a3f 100644 --- a/src/main/java/com/magamochi/userinteraction/service/UserMangaFollowService.java +++ b/src/main/java/com/magamochi/userinteraction/service/UserMangaFollowService.java @@ -2,7 +2,10 @@ package com.magamochi.userinteraction.service; import com.magamochi.catalog.model.entity.Manga; import com.magamochi.catalog.model.repository.MangaRepository; +import com.magamochi.client.NtfyClient; import com.magamochi.common.exception.NotFoundException; +import com.magamochi.content.model.entity.MangaContent; +import com.magamochi.ingestion.service.IngestionService; import com.magamochi.user.service.UserService; import com.magamochi.userinteraction.model.entity.UserMangaFollow; import com.magamochi.userinteraction.model.repository.UserMangaFollowRepository; @@ -14,10 +17,13 @@ import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor public class UserMangaFollowService { private final UserService userService; + private final IngestionService ingestionService; private final MangaRepository mangaRepository; private final UserMangaFollowRepository userMangaFollowRepository; + private final NtfyClient ntfyClient; + @Transactional public void follow(Long mangaId) { var user = userService.getLoggedUserThrowIfNotFound(); @@ -50,4 +56,21 @@ public class UserMangaFollowService { .findById(mangaId) .orElseThrow(() -> new NotFoundException("Manga not found for ID: " + mangaId)); } + + public void checkForMangaUpdates(Long contentProviderId) { + ingestionService.fetchMangaContentProviderContentList(contentProviderId); + } + + public void notifyNewMangaContent(MangaContent mangaContent) { + var userMangaFollows = + userMangaFollowRepository.findByManga(mangaContent.getMangaContentProvider().getManga()); + userMangaFollows.forEach( + umf -> + ntfyClient.notify( + new NtfyClient.Request( + "mangamochi-" + umf.getUser().getId().toString(), + umf.getManga().getTitle(), + "New content available on " + + mangaContent.getMangaContentProvider().getContentProvider().getName()))); + } } diff --git a/src/main/java/com/magamochi/task/MangaFollowUpdateTask.java b/src/main/java/com/magamochi/userinteraction/task/MangaFollowUpdateTask.java similarity index 82% rename from src/main/java/com/magamochi/task/MangaFollowUpdateTask.java rename to src/main/java/com/magamochi/userinteraction/task/MangaFollowUpdateTask.java index a2ec682..8a36596 100644 --- a/src/main/java/com/magamochi/task/MangaFollowUpdateTask.java +++ b/src/main/java/com/magamochi/userinteraction/task/MangaFollowUpdateTask.java @@ -1,12 +1,13 @@ -package com.magamochi.task; +package com.magamochi.userinteraction.task; import com.magamochi.catalog.model.entity.Manga; import com.magamochi.catalog.model.repository.MangaRepository; -import com.magamochi.model.dto.UpdateMangaFollowChapterListCommand; -import com.magamochi.queue.UpdateMangaFollowChapterListProducer; +import com.magamochi.userinteraction.queue.command.UpdateMangaFollowChapterListCommand; +import com.magamochi.userinteraction.queue.producer.UpdateMangaFollowChapterListProducer; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -21,7 +22,7 @@ public class MangaFollowUpdateTask { private final UpdateMangaFollowChapterListProducer producer; - // @Scheduled(cron = "${manga-follow.cron-expression}") + @Scheduled(cron = "${manga-follow.cron-expression}") @Transactional public void updateMangaFollow() { if (!updateEnabled) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a5204dd..bc40419 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -82,14 +82,11 @@ queues: manga-cover-update: ${MANGA_COVER_UDPATE_QUEUE:mangamochi.manga.cover.update} file-import: ${FILE_IMPORT_QUEUE:mangamochi.file.import} manga-content-download: ${MANGA_CONTENT_DOWNLOAD_QUEUE:mangamochi.manga.content.download} + manga-follow-update-chapter: ${MANGA_FOLLOW_UPDATE_CHAPTER_QUEUE:mangamochi.follow.update} routing-key: image-update: ${IMAGE_UPDATE_ROUTING_KEY:mangamochi.image.update} -rabbit-mq: - queues: - manga-follow-update-chapter: ${MANGA_FOLLOW_UPDATE_CHAPTER_QUEUE:mangaFollowUpdateChapterQueue} - image-service: clean-up-enabled: ${IMAGE_SERVICE_CLEAN_UP_ENABLED:false} cron-expression: "@weekly"