From 0032e032fea47774f9e2ae327d8cc9122b152f1b Mon Sep 17 00:00:00 2001 From: Rodrigo Verdiani Date: Sat, 28 Feb 2026 10:42:36 -0300 Subject: [PATCH] refactor(providers): replace provider status string with boolean for simplicity --- .woodpecker/.pipeline.yaml | 71 ------------------- .../mangamochi/model/dto/MangaDTO.java | 5 +- .../mangamochi/model/dto/ProviderListDTO.java | 7 +- .../mangamochi/model/entity/Provider.java | 6 +- .../model/enumeration/ProviderStatus.java | 6 -- .../repository/MangaProviderRepository.java | 3 + .../mangamochi/service/MangaListService.java | 54 +++++++------- .../ProviderManualMangaImportService.java | 3 +- .../mangamochi/service/ProviderService.java | 3 +- .../task/MangaFollowUpdateTask.java | 4 +- .../db/migration/V0021__PROVIDERS_ACTIVE.sql | 20 ++++++ 11 files changed, 63 insertions(+), 119 deletions(-) delete mode 100644 .woodpecker/.pipeline.yaml delete mode 100644 src/main/java/com/magamochi/mangamochi/model/enumeration/ProviderStatus.java create mode 100644 src/main/resources/db/migration/V0021__PROVIDERS_ACTIVE.sql diff --git a/.woodpecker/.pipeline.yaml b/.woodpecker/.pipeline.yaml deleted file mode 100644 index afaeaa8..0000000 --- a/.woodpecker/.pipeline.yaml +++ /dev/null @@ -1,71 +0,0 @@ -# .pipeline.yml -# ----------------- -# Build, publish, and deploy Java Spring Boot app - -when: - event: [ push, pull_request ] - -steps: - - name: test - image: maven:3.9.11-eclipse-temurin-25 - commands: - - echo "๐Ÿงช Building and testing Spring Boot app...." - - mvn -B clean verify - when: - - event: pull_request - branch: [main, develop] - - event: push - branch: [ main, develop ] - - - name: publish-image - depends_on: [ test ] - image: woodpeckerci/plugin-docker-buildx - settings: - platforms: linux/amd64 - repo: git.badger-pirarucu.ts.net/mangamochi/backend - registry: git.badger-pirarucu.ts.net - dockerfile: Dockerfile - context: . - username: - from_secret: DOCKER_USER - password: - from_secret: DOCKER_PASSWORD - tags: - - latest - - ${CI_COMMIT_SHA} - when: - event: [ push ] - branch: [ main ] - - - name: deploy - depends_on: [ publish-image ] - image: alpine:3.20 - environment: - DEPLOY_USER: rov - DEPLOY_HOST: mangamochi.badger-pirarucu.ts.net - DEPLOY_PORT: 22 - IMAGE: git.badger-pirarucu.ts.net/mangamochi/backend:${CI_COMMIT_SHA} - DEPLOY_SSH_KEY: - from_secret: DEPLOY_SSH_KEY - commands: - - echo "๐Ÿš€ Deploying to $DEPLOY_HOST..." - - apk add --no-cache openssh-client docker-cli - - mkdir -p ~/.ssh - - echo "$DEPLOY_SSH_KEY" > ~/.ssh/id_rsa - - chmod 600 ~/.ssh/id_rsa - - ssh-keyscan -p $DEPLOY_PORT $DEPLOY_HOST >> ~/.ssh/known_hosts - - > - ssh -p $DEPLOY_PORT $DEPLOY_USER@$DEPLOY_HOST " - docker pull $IMAGE && - docker stop mangamochi-backend 2>/dev/null || true && - docker rm mangamochi-backend 2>/dev/null || true && - docker run -d --name mangamochi-backend \ - --restart always \ - --network host \ - --env-file /home/rov/mangamochi/.env \ - -p 8080:8080 \ - $IMAGE - " - when: - event: [ push ] - branch: [ main ] diff --git a/src/main/java/com/magamochi/mangamochi/model/dto/MangaDTO.java b/src/main/java/com/magamochi/mangamochi/model/dto/MangaDTO.java index 454a8e7..4a6629f 100644 --- a/src/main/java/com/magamochi/mangamochi/model/dto/MangaDTO.java +++ b/src/main/java/com/magamochi/mangamochi/model/dto/MangaDTO.java @@ -6,7 +6,6 @@ import com.magamochi.mangamochi.model.entity.Manga; import com.magamochi.mangamochi.model.entity.MangaAlternativeTitle; import com.magamochi.mangamochi.model.entity.MangaChapter; import com.magamochi.mangamochi.model.entity.MangaProvider; -import com.magamochi.mangamochi.model.enumeration.ProviderStatus; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import java.time.OffsetDateTime; @@ -54,7 +53,7 @@ public record MangaDTO( public record MangaProviderDTO( @NotNull long id, @NotBlank String providerName, - @NotNull ProviderStatus providerStatus, + boolean active, @NotNull Integer chaptersAvailable, @NotNull Integer chaptersDownloaded, @NotNull Boolean supportsChapterFetch) { @@ -66,7 +65,7 @@ public record MangaDTO( return new MangaProviderDTO( mangaProvider.getId(), mangaProvider.getProvider().getName(), - mangaProvider.getProvider().getStatus(), + mangaProvider.getProvider().isActive(), chaptersAvailable, chaptersDownloaded, mangaProvider.getProvider().getSupportsChapterFetch()); diff --git a/src/main/java/com/magamochi/mangamochi/model/dto/ProviderListDTO.java b/src/main/java/com/magamochi/mangamochi/model/dto/ProviderListDTO.java index 6cb226f..159792a 100644 --- a/src/main/java/com/magamochi/mangamochi/model/dto/ProviderListDTO.java +++ b/src/main/java/com/magamochi/mangamochi/model/dto/ProviderListDTO.java @@ -2,6 +2,7 @@ package com.magamochi.mangamochi.model.dto; import com.magamochi.mangamochi.model.entity.*; import jakarta.validation.constraints.NotNull; +import java.time.Instant; import java.util.List; public record ProviderListDTO(@NotNull List providers) { @@ -9,9 +10,11 @@ public record ProviderListDTO(@NotNull List providers) { return new ProviderListDTO(providers.stream().map(ProviderDTO::from).toList()); } - record ProviderDTO(@NotNull Long id, @NotNull String name) { + record ProviderDTO( + @NotNull Long id, @NotNull String name, boolean active, Instant listLastUpdatedAt) { public static ProviderDTO from(Provider provider) { - return new ProviderDTO(provider.getId(), provider.getName()); + return new ProviderDTO( + provider.getId(), provider.getName(), provider.isActive(), provider.getListUpdatedAt()); } } } diff --git a/src/main/java/com/magamochi/mangamochi/model/entity/Provider.java b/src/main/java/com/magamochi/mangamochi/model/entity/Provider.java index bbea2ac..78438d8 100644 --- a/src/main/java/com/magamochi/mangamochi/model/entity/Provider.java +++ b/src/main/java/com/magamochi/mangamochi/model/entity/Provider.java @@ -1,6 +1,5 @@ package com.magamochi.mangamochi.model.entity; -import com.magamochi.mangamochi.model.enumeration.ProviderStatus; import jakarta.persistence.*; import java.time.Instant; import java.util.List; @@ -22,8 +21,7 @@ public class Provider { private String name; - @Enumerated(EnumType.STRING) - private ProviderStatus status; + private boolean active; @CreationTimestamp private Instant createdAt; @@ -35,4 +33,6 @@ public class Provider { @Builder.Default private Boolean supportsChapterFetch = true; @Builder.Default private Boolean manualImport = false; + + private Instant listUpdatedAt; } diff --git a/src/main/java/com/magamochi/mangamochi/model/enumeration/ProviderStatus.java b/src/main/java/com/magamochi/mangamochi/model/enumeration/ProviderStatus.java deleted file mode 100644 index cb09460..0000000 --- a/src/main/java/com/magamochi/mangamochi/model/enumeration/ProviderStatus.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.magamochi.mangamochi.model.enumeration; - -public enum ProviderStatus { - ACTIVE, - INACTIVE -} diff --git a/src/main/java/com/magamochi/mangamochi/model/repository/MangaProviderRepository.java b/src/main/java/com/magamochi/mangamochi/model/repository/MangaProviderRepository.java index 814d6d5..81ddb0c 100644 --- a/src/main/java/com/magamochi/mangamochi/model/repository/MangaProviderRepository.java +++ b/src/main/java/com/magamochi/mangamochi/model/repository/MangaProviderRepository.java @@ -3,6 +3,7 @@ package com.magamochi.mangamochi.model.repository; import com.magamochi.mangamochi.model.entity.Manga; import com.magamochi.mangamochi.model.entity.MangaProvider; import com.magamochi.mangamochi.model.entity.Provider; +import jakarta.validation.constraints.NotBlank; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; @@ -11,4 +12,6 @@ public interface MangaProviderRepository extends JpaRepository findByMangaTitleIgnoreCaseAndProvider( String mangaTitle, Provider provider); + + boolean existsByMangaTitleIgnoreCaseAndProvider(@NotBlank String title, Provider provider); } diff --git a/src/main/java/com/magamochi/mangamochi/service/MangaListService.java b/src/main/java/com/magamochi/mangamochi/service/MangaListService.java index add1f16..b3ef1bf 100644 --- a/src/main/java/com/magamochi/mangamochi/service/MangaListService.java +++ b/src/main/java/com/magamochi/mangamochi/service/MangaListService.java @@ -2,12 +2,16 @@ package com.magamochi.mangamochi.service; import static java.util.Objects.isNull; +import com.magamochi.mangamochi.model.dto.ContentProviderMangaInfoResponseDTO; import com.magamochi.mangamochi.model.entity.MangaProvider; +import com.magamochi.mangamochi.model.entity.Provider; import com.magamochi.mangamochi.model.repository.MangaProviderRepository; import com.magamochi.mangamochi.service.providers.PagedContentProviderFactory; +import java.time.Instant; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Log4j2 @Service @@ -16,43 +20,39 @@ public class MangaListService { private final ProviderService providerService; private final MangaCreationService mangaCreationService; private final PagedContentProviderFactory pagedContentProviderFactory; - private final MangaProviderRepository mangaProviderRepository; + @Transactional public void updateMangaList(String contentProviderName, Integer page) { var contentProvider = pagedContentProviderFactory.getPagedContentProvider(contentProviderName); var provider = providerService.getOrCreateProvider(contentProviderName); - var mangas = contentProvider.getMangasFromPage(page); - mangas.forEach( - mangaResponse -> { - var mangaProvider = - mangaProviderRepository.findByMangaTitleIgnoreCaseAndProvider( - mangaResponse.title(), provider); + mangas.forEach(mangaResponse -> processManga(mangaResponse, provider)); - if (mangaProvider.isPresent()) { - return; - } + provider.setListUpdatedAt(Instant.now()); + } - var manga = - mangaCreationService.getOrCreateManga( - mangaResponse.title(), mangaResponse.url(), provider); + private void processManga(ContentProviderMangaInfoResponseDTO mangaResponse, Provider provider) { + if (mangaProviderRepository.existsByMangaTitleIgnoreCaseAndProvider( + mangaResponse.title(), provider)) { + return; + } - if (isNull(manga)) { - return; - } + var manga = + mangaCreationService.getOrCreateManga(mangaResponse.title(), mangaResponse.url(), provider); - if (!mangaProviderRepository.existsByMangaAndProviderAndUrlIgnoreCase( - manga, provider, mangaResponse.url())) { - mangaProviderRepository.save( - MangaProvider.builder() - .manga(manga) - .mangaTitle(mangaResponse.title()) - .provider(provider) - .url(mangaResponse.url()) - .build()); - } - }); + if (isNull(manga)) { + log.warn("Failed to create manga: {}", mangaResponse.title()); + return; + } + + mangaProviderRepository.save( + MangaProvider.builder() + .manga(manga) + .mangaTitle(mangaResponse.title()) + .provider(provider) + .url(mangaResponse.url()) + .build()); } } diff --git a/src/main/java/com/magamochi/mangamochi/service/ProviderManualMangaImportService.java b/src/main/java/com/magamochi/mangamochi/service/ProviderManualMangaImportService.java index db9413f..322dd0b 100644 --- a/src/main/java/com/magamochi/mangamochi/service/ProviderManualMangaImportService.java +++ b/src/main/java/com/magamochi/mangamochi/service/ProviderManualMangaImportService.java @@ -7,7 +7,6 @@ import com.magamochi.mangamochi.exception.NotFoundException; import com.magamochi.mangamochi.model.dto.ImportMangaResponseDTO; import com.magamochi.mangamochi.model.dto.ImportRequestDTO; import com.magamochi.mangamochi.model.entity.*; -import com.magamochi.mangamochi.model.enumeration.ProviderStatus; import com.magamochi.mangamochi.model.repository.*; import com.magamochi.mangamochi.service.providers.ManualImportContentProviderFactory; import lombok.RequiredArgsConstructor; @@ -63,7 +62,7 @@ public class ProviderManualMangaImportService { .findById(providerId) .orElseThrow(() -> new NotFoundException("Provider not found")); - if (!provider.getStatus().equals(ProviderStatus.ACTIVE)) { + if (!provider.isActive()) { throw new IllegalStateException("Provider is not active"); } diff --git a/src/main/java/com/magamochi/mangamochi/service/ProviderService.java b/src/main/java/com/magamochi/mangamochi/service/ProviderService.java index 88581c2..ce51e4e 100644 --- a/src/main/java/com/magamochi/mangamochi/service/ProviderService.java +++ b/src/main/java/com/magamochi/mangamochi/service/ProviderService.java @@ -4,7 +4,6 @@ import static java.util.Objects.nonNull; import com.magamochi.mangamochi.model.dto.ProviderListDTO; import com.magamochi.mangamochi.model.entity.Provider; -import com.magamochi.mangamochi.model.enumeration.ProviderStatus; import com.magamochi.mangamochi.model.repository.ProviderRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -36,7 +35,7 @@ public class ProviderService { providerRepository.save( Provider.builder() .name(providerName) - .status(ProviderStatus.ACTIVE) + .active(true) .supportsChapterFetch(supportsChapterFetch) .build())); } diff --git a/src/main/java/com/magamochi/mangamochi/task/MangaFollowUpdateTask.java b/src/main/java/com/magamochi/mangamochi/task/MangaFollowUpdateTask.java index 8e67714..52f7ed3 100644 --- a/src/main/java/com/magamochi/mangamochi/task/MangaFollowUpdateTask.java +++ b/src/main/java/com/magamochi/mangamochi/task/MangaFollowUpdateTask.java @@ -2,7 +2,6 @@ package com.magamochi.mangamochi.task; import com.magamochi.mangamochi.model.dto.UpdateMangaFollowChapterListCommand; import com.magamochi.mangamochi.model.entity.Manga; -import com.magamochi.mangamochi.model.enumeration.ProviderStatus; import com.magamochi.mangamochi.model.repository.MangaRepository; import com.magamochi.mangamochi.queue.UpdateMangaFollowChapterListProducer; import lombok.RequiredArgsConstructor; @@ -46,8 +45,7 @@ public class MangaFollowUpdateTask { var mangaProviders = manga.getMangaProviders(); mangaProviders.stream() - .filter( - mangaProvider -> mangaProvider.getProvider().getStatus().equals(ProviderStatus.ACTIVE)) + .filter(mangaProvider -> mangaProvider.getProvider().isActive()) .forEach( mangaProvider -> producer.sendUpdateMangaFollowChapterListCommand( diff --git a/src/main/resources/db/migration/V0021__PROVIDERS_ACTIVE.sql b/src/main/resources/db/migration/V0021__PROVIDERS_ACTIVE.sql new file mode 100644 index 0000000..621e8dd --- /dev/null +++ b/src/main/resources/db/migration/V0021__PROVIDERS_ACTIVE.sql @@ -0,0 +1,20 @@ +ALTER TABLE providers + ADD COLUMN IF NOT EXISTS list_updated_at TIMESTAMP; + +DO +$$ + BEGIN + IF EXISTS (SELECT 1 + FROM information_schema.columns + WHERE table_name = 'providers' + AND column_name = 'status') THEN + ALTER TABLE providers + ALTER COLUMN status TYPE boolean + USING (status = 'ACTIVE'); + + ALTER TABLE providers + RENAME COLUMN status TO active; + + END IF; + END +$$; \ No newline at end of file