From d65944619470a7a3ed072bf8e02738be6c0dae25 Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Fri, 13 Dec 2024 12:15:21 +0800 Subject: [PATCH] style: ktlint format --- .../komga/benchmark/rest/BrowseBenchmark.kt | 6 +- .../benchmark/rest/DashboardBenchmark.kt | 8 +- .../komga/benchmark/rest/UnsortedBenchmark.kt | 6 +- .../scheduler/LibraryScanScheduler.kt | 21 +- .../gotson/komga/application/tasks/Task.kt | 137 ++++-- .../komga/application/tasks/TaskEmitter.kt | 3 +- .../komga/application/tasks/TaskProcessor.kt | 3 +- .../gotson/komga/domain/model/BookMetadata.kt | 50 ++- .../org/gotson/komga/domain/model/BookPage.kt | 13 +- .../komga/domain/model/ContentRestrictions.kt | 4 +- .../gotson/komga/domain/model/DomainEvent.kt | 130 ++++-- .../gotson/komga/domain/model/Exceptions.kt | 43 +- .../komga/domain/model/HistoricalEvent.kt | 126 +++--- .../gotson/komga/domain/model/KomgaUser.kt | 9 +- .../org/gotson/komga/domain/model/Media.kt | 4 +- .../gotson/komga/domain/model/MediaType.kt | 7 +- .../komga/domain/model/PageHashKnown.kt | 3 +- .../komga/domain/model/SearchCondition.kt | 24 +- .../komga/domain/model/SearchContext.kt | 6 +- .../komga/domain/model/SearchOperator.kt | 72 +++- .../komga/domain/model/SeriesMetadata.kt | 70 ++- .../komga/domain/model/ThumbnailSize.kt | 4 +- .../komga/domain/service/BookAnalyzer.kt | 20 +- .../komga/domain/service/BookConverter.kt | 18 +- .../komga/domain/service/BookImporter.kt | 30 +- .../komga/domain/service/BookLifecycle.kt | 32 +- .../komga/domain/service/BookPageEditor.kt | 15 +- .../komga/domain/service/FileSystemScanner.kt | 22 +- .../domain/service/LibraryContentLifecycle.kt | 58 ++- .../komga/domain/service/PageHashLifecycle.kt | 6 +- .../komga/domain/service/ReadListLifecycle.kt | 3 +- .../service/SeriesCollectionLifecycle.kt | 3 +- .../komga/domain/service/SeriesLifecycle.kt | 38 +- .../domain/service/SeriesMetadataLifecycle.kt | 10 +- .../domain/service/SyncPointLifecycle.kt | 27 +- .../domain/service/ThumbnailLifecycle.kt | 14 +- .../domain/service/TransientBookLifecycle.kt | 10 +- .../cache/TransientBookCache.kt | 3 +- .../datasource/DataSourcesConfiguration.kt | 6 +- .../FlywaySecondaryMigrationInitializer.kt | 3 +- .../datasource/SqliteUdfDataSource.kt | 6 +- .../infrastructure/image/ImageConverter.kt | 22 +- .../komga/infrastructure/image/ImageType.kt | 5 +- .../infrastructure/jooq/BookSearchHelper.kt | 37 +- .../jooq/ContentRestrictionsSearchHelper.kt | 15 +- .../jooq/KomgaJooqConfiguration.kt | 23 +- .../komga/infrastructure/jooq/RequiredJoin.kt | 4 +- .../jooq/SearchOperatorUtils.kt | 18 +- .../infrastructure/jooq/SeriesSearchHelper.kt | 65 ++- .../infrastructure/jooq/UnpagedSorted.kt | 12 +- .../gotson/komga/infrastructure/jooq/Utils.kt | 33 +- .../jooq/main/AuthenticationActivityDao.kt | 15 +- .../infrastructure/jooq/main/BookCommonDao.kt | 47 +- .../komga/infrastructure/jooq/main/BookDao.kt | 163 ++++--- .../infrastructure/jooq/main/BookDtoDao.kt | 164 +++---- .../jooq/main/BookMetadataAggregationDao.kt | 84 ++-- .../jooq/main/BookMetadataDao.kt | 245 ++++++----- .../jooq/main/HistoricalEventDao.kt | 21 +- .../jooq/main/HistoricalEventDtoDao.kt | 3 +- .../infrastructure/jooq/main/KoboDtoDao.kt | 57 +-- .../infrastructure/jooq/main/KomgaUserDao.kt | 63 +-- .../infrastructure/jooq/main/LibraryDao.kt | 36 +- .../infrastructure/jooq/main/MediaDao.kt | 229 +++++----- .../infrastructure/jooq/main/PageHashDao.kt | 56 ++- .../infrastructure/jooq/main/ReadListDao.kt | 60 ++- .../jooq/main/ReadListRequestDao.kt | 35 +- .../jooq/main/ReadProgressDao.kt | 63 +-- .../jooq/main/ReadProgressDtoDao.kt | 85 ++-- .../jooq/main/ReferentialDao.kt | 254 ++++++----- .../jooq/main/SeriesCollectionDao.kt | 60 ++- .../infrastructure/jooq/main/SeriesDao.kt | 42 +- .../infrastructure/jooq/main/SeriesDtoDao.kt | 185 ++++---- .../jooq/main/SeriesMetadataDao.kt | 208 +++++---- .../jooq/main/ServerSettingsDao.kt | 6 +- .../infrastructure/jooq/main/SidecarDao.kt | 18 +- .../infrastructure/jooq/main/SyncPointDao.kt | 254 ++++++----- .../jooq/main/ThumbnailBookDao.kt | 37 +- .../jooq/main/ThumbnailReadListDao.kt | 28 +- .../jooq/main/ThumbnailSeriesCollectionDao.kt | 28 +- .../jooq/main/ThumbnailSeriesDao.kt | 31 +- .../infrastructure/jooq/tasks/TasksDao.kt | 65 +-- .../komga/infrastructure/kobo/KoboProxy.kt | 27 +- .../kobo/KomgaSyncTokenGenerator.kt | 3 +- .../mediacontainer/ContentDetector.kt | 6 +- .../mediacontainer/divina/Rar5Extractor.kt | 6 +- .../mediacontainer/divina/RarExtractor.kt | 3 +- .../mediacontainer/divina/ZipExtractor.kt | 6 +- .../mediacontainer/epub/Epub.kt | 4 +- .../mediacontainer/epub/Epub2Nav.kt | 5 +- .../mediacontainer/epub/Epub3Nav.kt | 4 +- .../mediacontainer/epub/EpubExtractor.kt | 37 +- .../infrastructure/mediacontainer/epub/Nav.kt | 3 +- .../infrastructure/mediacontainer/epub/Ncx.kt | 3 +- .../metadata/comicrack/ComicInfoProvider.kt | 9 +- .../metadata/comicrack/dto/AgeRating.kt | 5 +- .../metadata/comicrack/dto/Book.kt | 4 +- .../metadata/comicrack/dto/Manga.kt | 4 +- .../metadata/comicrack/dto/ReadingList.kt | 4 +- .../metadata/comicrack/dto/YesNo.kt | 4 +- .../metadata/epub/EpubMetadataProvider.kt | 31 +- .../localartwork/LocalArtworkProvider.kt | 15 +- .../metadata/mylar/MylarSeriesProvider.kt | 3 +- .../metadata/oneshot/OneShotSeriesProvider.kt | 3 +- .../search/LuceneConfiguration.kt | 9 +- .../infrastructure/search/LuceneEntity.kt | 6 +- .../infrastructure/search/LuceneHelper.kt | 20 +- .../search/MultiLingualNGramAnalyzer.kt | 6 +- .../search/SearchIndexLifecycle.kt | 3 +- .../security/CorsConfiguration.kt | 3 +- .../infrastructure/security/KomgaPrincipal.kt | 4 +- .../infrastructure/security/LoginListener.kt | 6 +- .../security/SecurityConfiguration.kt | 53 ++- .../UserAgentWebAuthenticationDetails.kt | 4 +- ...UserAgentWebAuthenticationDetailsSource.kt | 3 +- .../apikey/ApiKeyAuthenticationProvider.kt | 6 +- .../apikey/ApiKeyAuthenticationToken.kt | 6 +- .../security/apikey/ApiKeyGenerator.kt | 3 +- .../UriRegexApiKeyAuthenticationConverter.kt | 16 +- .../oauth2/GithubOAuth2UserService.kt | 23 +- .../security/session/SessionConfiguration.kt | 11 +- .../session/SmartHttpSessionIdResolver.kt | 3 +- .../swagger/SwaggerConfiguration.kt | 9 +- .../transaction/TransactionConfiguration.kt | 3 +- .../komga/infrastructure/util/ZipFileUtils.kt | 3 +- .../AuthorsHandlerMethodArgumentResolver.kt | 3 +- .../web/BracketParamsRequestWrapper.kt | 18 +- ...imitedPairHandlerMethodArgumentResolver.kt | 3 +- .../web/KoboMissingPortFilter.kt | 9 +- .../gotson/komga/infrastructure/web/Utils.kt | 9 +- .../infrastructure/web/WebMvcConfiguration.kt | 15 +- .../infrastructure/xml/NamespaceXmlFactory.kt | 18 +- .../interfaces/api/CommonBookController.kt | 205 ++++----- .../komga/interfaces/api/OpdsGenerator.kt | 36 +- .../org/gotson/komga/interfaces/api/Utils.kt | 6 +- .../komga/interfaces/api/WebPubGenerator.kt | 36 +- .../interfaces/api/kobo/KoboController.kt | 65 ++- .../api/kobo/dto/ReadingStateDto.kt | 12 +- .../interfaces/api/opds/v1/OpdsController.kt | 23 +- .../interfaces/api/opds/v1/dto/OpdsLink.kt | 77 ++-- .../interfaces/api/opds/v2/Opds2Controller.kt | 294 ++++++------- .../api/rest/AnnouncementController.kt | 12 +- .../interfaces/api/rest/BookController.kt | 100 +++-- .../interfaces/api/rest/ClaimController.kt | 21 +- .../api/rest/FileSystemController.kt | 3 +- .../interfaces/api/rest/LibraryController.kt | 85 ++-- .../interfaces/api/rest/PageHashController.kt | 21 +- .../interfaces/api/rest/ReadListController.kt | 96 +++-- .../api/rest/ReferentialController.kt | 6 +- .../api/rest/SeriesCollectionController.kt | 50 ++- .../interfaces/api/rest/SeriesController.kt | 267 ++++++------ .../interfaces/api/rest/TaskController.kt | 3 +- .../api/rest/TransientBooksController.kt | 6 +- .../interfaces/api/rest/UserController.kt | 6 +- .../komga/interfaces/api/rest/dto/BookDto.kt | 3 +- .../api/rest/dto/ReadProgressUpdateDto.kt | 7 +- .../interfaces/api/rest/dto/SeriesDto.kt | 3 +- .../scheduler/MetricsPublisherController.kt | 15 +- .../scheduler/PeriodicScannerController.kt | 6 +- .../komga/interfaces/sse/SseController.kt | 3 +- .../gotson/komga/language/LanguageUtils.kt | 39 +- .../src/test/kotlin/org/gotson/komga/Utils.kt | 3 +- .../DomainDrivenDesignRulesTest.kt | 13 +- .../architecture/NamingConventionTest.kt | 24 +- .../architecture/SlicesIsolationRulesTest.kt | 7 +- .../org/gotson/komga/domain/model/Utils.kt | 8 +- .../komga/domain/service/BookAnalyzerTest.kt | 8 +- .../domain/service/LibraryLifecycleTest.kt | 13 +- .../jooq/main/BookDtoDaoTest.kt | 187 ++++---- .../jooq/main/ReadListDaoTest.kt | 5 +- .../jooq/main/SeriesDtoDaoTest.kt | 343 ++++++++------- .../infrastructure/jooq/tasks/TasksDaoTest.kt | 3 +- .../mediacontainer/epub/NavTest.kt | 5 +- .../mediacontainer/epub/NcxTest.kt | 5 +- .../komga/interfaces/api/SessionTest.kt | 100 +++-- .../interfaces/api/kobo/KoboControllerTest.kt | 24 +- .../interfaces/api/opds/OpdsControllerTest.kt | 27 +- .../komga/interfaces/api/rest/ActuatorTest.kt | 21 +- .../api/rest/AnnouncementControllerTest.kt | 3 +- .../api/rest/BookControllerPageTest.kt | 8 +- .../interfaces/api/rest/BookControllerTest.kt | 341 +++++++++------ .../api/rest/ClaimControllerTest.kt | 16 +- .../api/rest/FileSystemControllerTest.kt | 24 +- .../api/rest/LibraryControllerTest.kt | 58 ++- .../api/rest/OAuth2ControllerTest.kt | 3 +- .../api/rest/ReadListControllerTest.kt | 402 +++++++++++------- .../rest/SeriesCollectionControllerTest.kt | 239 +++++++---- .../api/rest/SeriesControllerTest.kt | 213 ++++++---- .../api/rest/SettingsControllerTest.kt | 39 +- .../api/rest/UserControllerDemoTest.kt | 16 +- .../interfaces/api/rest/UserControllerTest.kt | 200 +++++---- .../mvc/ResourceNotFoundControllerTest.kt | 12 +- 191 files changed, 4823 insertions(+), 3466 deletions(-) diff --git a/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/BrowseBenchmark.kt b/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/BrowseBenchmark.kt index f54e3a51..6b2ede2f 100644 --- a/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/BrowseBenchmark.kt +++ b/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/BrowseBenchmark.kt @@ -24,8 +24,10 @@ class BrowseBenchmark : AbstractRestBenchmark() { // find series with most books biggestSeriesId = - seriesController.getAllSeries(principal, page = PageRequest.of(0, 1, Sort.by(Sort.Order.desc("booksCount")))) - .content.first() + seriesController + .getAllSeries(principal, page = PageRequest.of(0, 1, Sort.by(Sort.Order.desc("booksCount")))) + .content + .first() .id } diff --git a/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/DashboardBenchmark.kt b/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/DashboardBenchmark.kt index f3aa4c0d..c37296f2 100644 --- a/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/DashboardBenchmark.kt +++ b/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/DashboardBenchmark.kt @@ -47,8 +47,12 @@ class DashboardBenchmark : AbstractRestBenchmark() { } // retrieve most recent book release date - bookLatestReleaseDate = bookController.getAllBooks(principal, page = PageRequest.of(0, 1, Sort.by(Sort.Order.desc("metadata.releaseDate")))) - .content.firstOrNull()?.metadata?.releaseDate ?: LocalDate.now() + bookLatestReleaseDate = bookController + .getAllBooks(principal, page = PageRequest.of(0, 1, Sort.by(Sort.Order.desc("metadata.releaseDate")))) + .content + .firstOrNull() + ?.metadata + ?.releaseDate ?: LocalDate.now() } @Benchmark diff --git a/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/UnsortedBenchmark.kt b/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/UnsortedBenchmark.kt index a0558e43..400a7a5f 100644 --- a/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/UnsortedBenchmark.kt +++ b/komga/src/benchmark/kotlin/org/gotson/komga/benchmark/rest/UnsortedBenchmark.kt @@ -23,8 +23,10 @@ class UnsortedBenchmark : AbstractRestBenchmark() { // find series with most books biggestSeriesId = - seriesController.getAllSeries(principal, page = PageRequest.of(0, 1, Sort.by(Sort.Order.desc("booksCount")))) - .content.first() + seriesController + .getAllSeries(principal, page = PageRequest.of(0, 1, Sort.by(Sort.Order.desc("booksCount")))) + .content + .first() .id } diff --git a/komga/src/main/kotlin/org/gotson/komga/application/scheduler/LibraryScanScheduler.kt b/komga/src/main/kotlin/org/gotson/komga/application/scheduler/LibraryScanScheduler.kt index 5d251248..f002a1c6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/application/scheduler/LibraryScanScheduler.kt +++ b/komga/src/main/kotlin/org/gotson/komga/application/scheduler/LibraryScanScheduler.kt @@ -36,16 +36,17 @@ class LibraryScanScheduler( fun scheduleScan(library: Library) { registry.remove(library.id)?.cancel(false) if (library.scanInterval != DISABLED) { - registrar.scheduleFixedRateTask( - FixedRateTask( - { - logger.info { "Periodic scan for library: ${library.name}" } - taskEmitter.scanLibrary(library.id) - }, - library.scanInterval.toDuration(), - library.scanInterval.toDuration(), - ), - )?.let { registry[library.id] = it } + registrar + .scheduleFixedRateTask( + FixedRateTask( + { + logger.info { "Periodic scan for library: ${library.name}" } + taskEmitter.scanLibrary(library.id) + }, + library.scanInterval.toDuration(), + library.scanInterval.toDuration(), + ), + )?.let { registry[library.id] = it } } } diff --git a/komga/src/main/kotlin/org/gotson/komga/application/tasks/Task.kt b/komga/src/main/kotlin/org/gotson/komga/application/tasks/Task.kt index f3fedb3b..4db0b183 100644 --- a/komga/src/main/kotlin/org/gotson/komga/application/tasks/Task.kt +++ b/komga/src/main/kotlin/org/gotson/komga/application/tasks/Task.kt @@ -12,149 +12,232 @@ const val DEFAULT_PRIORITY = 4 const val LOW_PRIORITY = 2 const val LOWEST_PRIORITY = 0 -sealed class Task(val priority: Int = DEFAULT_PRIORITY, val groupId: String? = null) { +sealed class Task( + val priority: Int = DEFAULT_PRIORITY, + val groupId: String? = null, +) { abstract val uniqueId: String - class ScanLibrary(val libraryId: String, val scanDeep: Boolean, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class ScanLibrary( + val libraryId: String, + val scanDeep: Boolean, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "SCAN_LIBRARY_${libraryId}_DEEP_$scanDeep" override fun toString(): String = "ScanLibrary(libraryId='$libraryId', scanDeep='$scanDeep', priority='$priority')" } - class FindBooksToConvert(val libraryId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class FindBooksToConvert( + val libraryId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "FIND_BOOKS_TO_CONVERT_$libraryId" override fun toString(): String = "FindBooksToConvert(libraryId='$libraryId', priority='$priority')" } - class FindBooksWithMissingPageHash(val libraryId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class FindBooksWithMissingPageHash( + val libraryId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "FIND_BOOKS_WITH_MISSING_PAGE_HASH_$libraryId" override fun toString(): String = "FindBooksWithMissingPageHash(libraryId='$libraryId', priority='$priority')" } - class FindDuplicatePagesToDelete(val libraryId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class FindDuplicatePagesToDelete( + val libraryId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "FIND_DUPLICATE_PAGES_TO_DELETE_$libraryId" override fun toString(): String = "FindDuplicatePagesToDelete(libraryId='$libraryId', priority='$priority')" } - class EmptyTrash(val libraryId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class EmptyTrash( + val libraryId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "EMPTY_TRASH_$libraryId" override fun toString(): String = "EmptyTrash(libraryId='$libraryId', priority='$priority')" } - class AnalyzeBook(val bookId: String, priority: Int = DEFAULT_PRIORITY, groupId: String) : Task(priority, groupId) { + class AnalyzeBook( + val bookId: String, + priority: Int = DEFAULT_PRIORITY, + groupId: String, + ) : Task(priority, groupId) { override val uniqueId = "ANALYZE_BOOK_$bookId" override fun toString(): String = "AnalyzeBook(bookId='$bookId', priority='$priority')" } - class GenerateBookThumbnail(val bookId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class GenerateBookThumbnail( + val bookId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "GENERATE_BOOK_THUMBNAIL_$bookId" override fun toString(): String = "GenerateBookThumbnail(bookId='$bookId', priority='$priority')" } - class RefreshBookMetadata(val bookId: String, val capabilities: Set, priority: Int = DEFAULT_PRIORITY, groupId: String) : Task(priority, groupId) { + class RefreshBookMetadata( + val bookId: String, + val capabilities: Set, + priority: Int = DEFAULT_PRIORITY, + groupId: String, + ) : Task(priority, groupId) { override val uniqueId = "REFRESH_BOOK_METADATA_$bookId" override fun toString(): String = "RefreshBookMetadata(bookId='$bookId', capabilities=$capabilities, priority='$priority')" } - class HashBook(val bookId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class HashBook( + val bookId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "HASH_BOOK_$bookId" override fun toString(): String = "HashBook(bookId='$bookId', priority='$priority')" } - class HashBookPages(val bookId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class HashBookPages( + val bookId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "HASH_BOOK_PAGES_$bookId" override fun toString(): String = "HashBookPages(bookId='$bookId', priority='$priority')" } - class RefreshSeriesMetadata(val seriesId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority, seriesId) { + class RefreshSeriesMetadata( + val seriesId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority, seriesId) { override val uniqueId = "REFRESH_SERIES_METADATA_$seriesId" override fun toString(): String = "RefreshSeriesMetadata(seriesId='$seriesId', priority='$priority')" } - class AggregateSeriesMetadata(val seriesId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority, seriesId) { + class AggregateSeriesMetadata( + val seriesId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority, seriesId) { override val uniqueId = "AGGREGATE_SERIES_METADATA_$seriesId" override fun toString(): String = "AggregateSeriesMetadata(seriesId='$seriesId', priority='$priority')" } - class RefreshBookLocalArtwork(val bookId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class RefreshBookLocalArtwork( + val bookId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId: String = "REFRESH_BOOK_LOCAL_ARTWORK_$bookId" override fun toString(): String = "RefreshBookLocalArtwork(bookId='$bookId', priority='$priority')" } - class RefreshSeriesLocalArtwork(val seriesId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class RefreshSeriesLocalArtwork( + val seriesId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId: String = "REFRESH_SERIES_LOCAL_ARTWORK_$seriesId" override fun toString(): String = "RefreshSeriesLocalArtwork(seriesId=$seriesId, priority='$priority')" } - class ImportBook(val sourceFile: String, val seriesId: String, val copyMode: CopyMode, val destinationName: String?, val upgradeBookId: String?, priority: Int = DEFAULT_PRIORITY) : Task(priority, seriesId) { + class ImportBook( + val sourceFile: String, + val seriesId: String, + val copyMode: CopyMode, + val destinationName: String?, + val upgradeBookId: String?, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority, seriesId) { override val uniqueId: String = "IMPORT_BOOK_${seriesId}_$sourceFile" - override fun toString(): String = - "ImportBook(sourceFile='$sourceFile', seriesId='$seriesId', copyMode=$copyMode, destinationName=$destinationName, upgradeBookId=$upgradeBookId, priority='$priority')" + override fun toString(): String = "ImportBook(sourceFile='$sourceFile', seriesId='$seriesId', copyMode=$copyMode, destinationName=$destinationName, upgradeBookId=$upgradeBookId, priority='$priority')" } - class ConvertBook(val bookId: String, priority: Int = DEFAULT_PRIORITY, groupId: String) : Task(priority, groupId) { + class ConvertBook( + val bookId: String, + priority: Int = DEFAULT_PRIORITY, + groupId: String, + ) : Task(priority, groupId) { override val uniqueId: String = "CONVERT_BOOK_$bookId" override fun toString(): String = "ConvertBook(bookId='$bookId', priority='$priority')" } - class RepairExtension(val bookId: String, priority: Int = DEFAULT_PRIORITY, groupId: String) : Task(priority, groupId) { + class RepairExtension( + val bookId: String, + priority: Int = DEFAULT_PRIORITY, + groupId: String, + ) : Task(priority, groupId) { override val uniqueId: String = "REPAIR_EXTENSION_$bookId" override fun toString(): String = "RepairExtension(bookId='$bookId', priority='$priority')" } - class RemoveHashedPages(val bookId: String, val pages: Collection, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class RemoveHashedPages( + val bookId: String, + val pages: Collection, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId: String = "REMOVE_HASHED_PAGES_$bookId" override fun toString(): String = "RemoveHashedPages(bookId='$bookId', priority='$priority')" } - class RebuildIndex(val entities: Set?, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class RebuildIndex( + val entities: Set?, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "REBUILD_INDEX" override fun toString(): String = "RebuildIndex(priority='$priority',entities='${entities?.map { it.type }}')" } - class UpgradeIndex(priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class UpgradeIndex( + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "UPGRADE_INDEX" override fun toString(): String = "UpgradeIndex(priority='$priority')" } - class DeleteBook(val bookId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class DeleteBook( + val bookId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "DELETE_BOOK_$bookId" override fun toString(): String = "DeleteBook(bookId='$bookId', priority='$priority')" } - class DeleteSeries(val seriesId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class DeleteSeries( + val seriesId: String, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "DELETE_SERIES_$seriesId" override fun toString(): String = "DeleteSeries(seriesId='$seriesId', priority='$priority')" } - class FixThumbnailsWithoutMetadata(priority: Int = DEFAULT_PRIORITY) : Task(priority, "FixThumbnailsWithoutMetadata") { + class FixThumbnailsWithoutMetadata( + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority, "FixThumbnailsWithoutMetadata") { override val uniqueId = "FIX_THUMBNAILS_WITHOUT_METADATA_${LocalDateTime.now()}" override fun toString(): String = "FixThumbnailsWithoutMetadata(priority='$priority')" } - class FindBookThumbnailsToRegenerate(val forBiggerResultOnly: Boolean, priority: Int = DEFAULT_PRIORITY) : Task(priority) { + class FindBookThumbnailsToRegenerate( + val forBiggerResultOnly: Boolean, + priority: Int = DEFAULT_PRIORITY, + ) : Task(priority) { override val uniqueId = "FIND_BOOK_THUMBNAILS_TO_REGENERATE" override fun toString(): String = "FindBookThumbnailsToRegenerate(forBiggerResultOnly='$forBiggerResultOnly', priority='$priority')" diff --git a/komga/src/main/kotlin/org/gotson/komga/application/tasks/TaskEmitter.kt b/komga/src/main/kotlin/org/gotson/komga/application/tasks/TaskEmitter.kt index 531692e8..0505e9bc 100644 --- a/komga/src/main/kotlin/org/gotson/komga/application/tasks/TaskEmitter.kt +++ b/komga/src/main/kotlin/org/gotson/komga/application/tasks/TaskEmitter.kt @@ -54,8 +54,7 @@ class TaskEmitter( ), SearchContext.empty(), UnpagedSorted(Sort.by(Sort.Order.asc("seriesId"), Sort.Order.asc("number"))), - ) - .content + ).content .map { Task.AnalyzeBook(it.id, groupId = it.seriesId) } .let { submitTasks(it) } } diff --git a/komga/src/main/kotlin/org/gotson/komga/application/tasks/TaskProcessor.kt b/komga/src/main/kotlin/org/gotson/komga/application/tasks/TaskProcessor.kt index d6fe1506..113b2803 100644 --- a/komga/src/main/kotlin/org/gotson/komga/application/tasks/TaskProcessor.kt +++ b/komga/src/main/kotlin/org/gotson/komga/application/tasks/TaskProcessor.kt @@ -48,8 +48,9 @@ class TaskProcessor( executor.execute { takeAndProcess() } } else { // fan out while threads are available - while (tasksRepository.hasAvailable() && executor.activeCount < executor.corePoolSize) + while (tasksRepository.hasAvailable() && executor.activeCount < executor.corePoolSize) { executor.execute { takeAndProcess() } + } } } else { logger.debug { "Not processing tasks" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/BookMetadata.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/BookMetadata.kt index b773a215..07e84f00 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/BookMetadata.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/BookMetadata.kt @@ -54,31 +54,29 @@ class BookMetadata( bookId: String = this.bookId, createdDate: LocalDateTime = this.createdDate, lastModifiedDate: LocalDateTime = this.lastModifiedDate, - ) = - BookMetadata( - title = title, - summary = summary, - number = number, - numberSort = numberSort, - releaseDate = releaseDate, - authors = authors, - tags = tags, - isbn = isbn, - links = links, - titleLock = titleLock, - summaryLock = summaryLock, - numberLock = numberLock, - numberSortLock = numberSortLock, - releaseDateLock = releaseDateLock, - authorsLock = authorsLock, - tagsLock = tagsLock, - isbnLock = isbnLock, - linksLock = linksLock, - bookId = bookId, - createdDate = createdDate, - lastModifiedDate = lastModifiedDate, - ) + ) = BookMetadata( + title = title, + summary = summary, + number = number, + numberSort = numberSort, + releaseDate = releaseDate, + authors = authors, + tags = tags, + isbn = isbn, + links = links, + titleLock = titleLock, + summaryLock = summaryLock, + numberLock = numberLock, + numberSortLock = numberSortLock, + releaseDateLock = releaseDateLock, + authorsLock = authorsLock, + tagsLock = tagsLock, + isbnLock = isbnLock, + linksLock = linksLock, + bookId = bookId, + createdDate = createdDate, + lastModifiedDate = lastModifiedDate, + ) - override fun toString(): String = - "BookMetadata(numberSort=$numberSort, releaseDate=$releaseDate, authors=$authors, isbn='$isbn', links=$links, titleLock=$titleLock, summaryLock=$summaryLock, numberLock=$numberLock, numberSortLock=$numberSortLock, releaseDateLock=$releaseDateLock, authorsLock=$authorsLock, tagsLock=$tagsLock, isbnLock=$isbnLock, linksLock=$linksLock, bookId='$bookId', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate, title='$title', summary='$summary', number='$number', tags=$tags)" + override fun toString(): String = "BookMetadata(numberSort=$numberSort, releaseDate=$releaseDate, authors=$authors, isbn='$isbn', links=$links, titleLock=$titleLock, summaryLock=$summaryLock, numberLock=$numberLock, numberSortLock=$numberSortLock, releaseDateLock=$releaseDateLock, authorsLock=$authorsLock, tagsLock=$tagsLock, isbnLock=$isbnLock, linksLock=$linksLock, bookId='$bookId', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate, title='$title', summary='$summary', number='$number', tags=$tags)" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/BookPage.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/BookPage.kt index f05d2327..a7240365 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/BookPage.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/BookPage.kt @@ -26,11 +26,12 @@ open class BookPage( fun Collection.restoreHashFrom(restoreFrom: Collection): List = this.map { newPage -> - restoreFrom.find { - it.fileSize == newPage.fileSize && - it.mediaType == newPage.mediaType && - it.fileName == newPage.fileName && - it.fileHash.isNotBlank() - }?.let { newPage.copy(fileHash = it.fileHash) } + restoreFrom + .find { + it.fileSize == newPage.fileSize && + it.mediaType == newPage.mediaType && + it.fileName == newPage.fileName && + it.fileHash.isNotBlank() + }?.let { newPage.copy(fileHash = it.fileHash) } ?: newPage } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/ContentRestrictions.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/ContentRestrictions.kt index 3ff3c3a0..28479ccc 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/ContentRestrictions.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/ContentRestrictions.kt @@ -8,7 +8,9 @@ class ContentRestrictions( labelsExclude: Set = emptySet(), ) { val labelsAllow = - labelsAllow.lowerNotBlank().toSet() + labelsAllow + .lowerNotBlank() + .toSet() .minus(labelsExclude.lowerNotBlank().toSet()) val labelsExclude = labelsExclude.lowerNotBlank().toSet() diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/DomainEvent.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/DomainEvent.kt index 08a44fcc..47a28127 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/DomainEvent.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/DomainEvent.kt @@ -3,65 +3,133 @@ package org.gotson.komga.domain.model import java.net.URL sealed class DomainEvent { - data class LibraryAdded(val library: Library) : DomainEvent() + data class LibraryAdded( + val library: Library, + ) : DomainEvent() - data class LibraryUpdated(val library: Library) : DomainEvent() + data class LibraryUpdated( + val library: Library, + ) : DomainEvent() - data class LibraryDeleted(val library: Library) : DomainEvent() + data class LibraryDeleted( + val library: Library, + ) : DomainEvent() - data class LibraryScanned(val library: Library) : DomainEvent() + data class LibraryScanned( + val library: Library, + ) : DomainEvent() - data class SeriesAdded(val series: Series) : DomainEvent() + data class SeriesAdded( + val series: Series, + ) : DomainEvent() - data class SeriesUpdated(val series: Series) : DomainEvent() + data class SeriesUpdated( + val series: Series, + ) : DomainEvent() - data class SeriesDeleted(val series: Series) : DomainEvent() + data class SeriesDeleted( + val series: Series, + ) : DomainEvent() - data class BookAdded(val book: Book) : DomainEvent() + data class BookAdded( + val book: Book, + ) : DomainEvent() - data class BookUpdated(val book: Book) : DomainEvent() + data class BookUpdated( + val book: Book, + ) : DomainEvent() - data class BookDeleted(val book: Book) : DomainEvent() + data class BookDeleted( + val book: Book, + ) : DomainEvent() - data class BookImported(val book: Book?, val sourceFile: URL, val success: Boolean, val message: String? = null) : DomainEvent() + data class BookImported( + val book: Book?, + val sourceFile: URL, + val success: Boolean, + val message: String? = null, + ) : DomainEvent() - data class CollectionAdded(val collection: SeriesCollection) : DomainEvent() + data class CollectionAdded( + val collection: SeriesCollection, + ) : DomainEvent() - data class CollectionUpdated(val collection: SeriesCollection) : DomainEvent() + data class CollectionUpdated( + val collection: SeriesCollection, + ) : DomainEvent() - data class CollectionDeleted(val collection: SeriesCollection) : DomainEvent() + data class CollectionDeleted( + val collection: SeriesCollection, + ) : DomainEvent() - data class ReadListAdded(val readList: ReadList) : DomainEvent() + data class ReadListAdded( + val readList: ReadList, + ) : DomainEvent() - data class ReadListUpdated(val readList: ReadList) : DomainEvent() + data class ReadListUpdated( + val readList: ReadList, + ) : DomainEvent() - data class ReadListDeleted(val readList: ReadList) : DomainEvent() + data class ReadListDeleted( + val readList: ReadList, + ) : DomainEvent() - data class ReadProgressChanged(val progress: ReadProgress) : DomainEvent() + data class ReadProgressChanged( + val progress: ReadProgress, + ) : DomainEvent() - data class ReadProgressDeleted(val progress: ReadProgress) : DomainEvent() + data class ReadProgressDeleted( + val progress: ReadProgress, + ) : DomainEvent() - data class ReadProgressSeriesChanged(val seriesId: String, val userId: String) : DomainEvent() + data class ReadProgressSeriesChanged( + val seriesId: String, + val userId: String, + ) : DomainEvent() - data class ReadProgressSeriesDeleted(val seriesId: String, val userId: String) : DomainEvent() + data class ReadProgressSeriesDeleted( + val seriesId: String, + val userId: String, + ) : DomainEvent() - data class ThumbnailBookAdded(val thumbnail: ThumbnailBook) : DomainEvent() + data class ThumbnailBookAdded( + val thumbnail: ThumbnailBook, + ) : DomainEvent() - data class ThumbnailBookDeleted(val thumbnail: ThumbnailBook) : DomainEvent() + data class ThumbnailBookDeleted( + val thumbnail: ThumbnailBook, + ) : DomainEvent() - data class ThumbnailSeriesAdded(val thumbnail: ThumbnailSeries) : DomainEvent() + data class ThumbnailSeriesAdded( + val thumbnail: ThumbnailSeries, + ) : DomainEvent() - data class ThumbnailSeriesDeleted(val thumbnail: ThumbnailSeries) : DomainEvent() + data class ThumbnailSeriesDeleted( + val thumbnail: ThumbnailSeries, + ) : DomainEvent() - data class ThumbnailSeriesCollectionAdded(val thumbnail: ThumbnailSeriesCollection) : DomainEvent() + data class ThumbnailSeriesCollectionAdded( + val thumbnail: ThumbnailSeriesCollection, + ) : DomainEvent() - data class ThumbnailSeriesCollectionDeleted(val thumbnail: ThumbnailSeriesCollection) : DomainEvent() + data class ThumbnailSeriesCollectionDeleted( + val thumbnail: ThumbnailSeriesCollection, + ) : DomainEvent() - data class ThumbnailReadListAdded(val thumbnail: ThumbnailReadList) : DomainEvent() + data class ThumbnailReadListAdded( + val thumbnail: ThumbnailReadList, + ) : DomainEvent() - data class ThumbnailReadListDeleted(val thumbnail: ThumbnailReadList) : DomainEvent() + data class ThumbnailReadListDeleted( + val thumbnail: ThumbnailReadList, + ) : DomainEvent() - data class UserUpdated(val user: KomgaUser, val expireSession: Boolean) : DomainEvent() + data class UserUpdated( + val user: KomgaUser, + val expireSession: Boolean, + ) : DomainEvent() - data class UserDeleted(val user: KomgaUser) : DomainEvent() + data class UserDeleted( + val user: KomgaUser, + ) : DomainEvent() } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/Exceptions.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/Exceptions.kt index 7fa5e6e7..e7ecd48e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/Exceptions.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/Exceptions.kt @@ -18,20 +18,45 @@ class MediaNotReadyException : Exception() class NoThumbnailFoundException : Exception() -class MediaUnsupportedException(message: String, code: String = "") : CodedException(message, code) +class MediaUnsupportedException( + message: String, + code: String = "", +) : CodedException(message, code) -class ImageConversionException(message: String, code: String = "") : CodedException(message, code) +class ImageConversionException( + message: String, + code: String = "", +) : CodedException(message, code) -class DirectoryNotFoundException(message: String, code: String = "") : CodedException(message, code) +class DirectoryNotFoundException( + message: String, + code: String = "", +) : CodedException(message, code) -class DuplicateNameException(message: String, code: String = "") : CodedException(message, code) +class DuplicateNameException( + message: String, + code: String = "", +) : CodedException(message, code) -class PathContainedInPath(message: String, code: String = "") : CodedException(message, code) +class PathContainedInPath( + message: String, + code: String = "", +) : CodedException(message, code) -class UserEmailAlreadyExistsException(message: String, code: String = "") : CodedException(message, code) +class UserEmailAlreadyExistsException( + message: String, + code: String = "", +) : CodedException(message, code) -class BookConversionException(message: String) : Exception(message) +class BookConversionException( + message: String, +) : Exception(message) -class ComicRackListException(message: String, code: String = "") : CodedException(message, code) +class ComicRackListException( + message: String, + code: String = "", +) : CodedException(message, code) -class EntryNotFoundException(message: String) : Exception(message) +class EntryNotFoundException( + message: String, +) : Exception(message) diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/HistoricalEvent.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/HistoricalEvent.kt index de013495..097302d4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/HistoricalEvent.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/HistoricalEvent.kt @@ -12,64 +12,82 @@ sealed class HistoricalEvent( val timestamp: LocalDateTime = LocalDateTime.now(), val id: String = TsidCreator.getTsid256().toString(), ) { - class BookFileDeleted(book: Book, reason: String) : HistoricalEvent( - type = "BookFileDeleted", - bookId = book.id, - seriesId = book.seriesId, - properties = - mapOf( - "reason" to reason, - "name" to book.path.toString(), - ), - ) + class BookFileDeleted( + book: Book, + reason: String, + ) : HistoricalEvent( + type = "BookFileDeleted", + bookId = book.id, + seriesId = book.seriesId, + properties = + mapOf( + "reason" to reason, + "name" to book.path.toString(), + ), + ) - class SeriesFolderDeleted(seriesId: String, seriesPath: Path, reason: String) : HistoricalEvent( - type = "SeriesFolderDeleted", - seriesId = seriesId, - properties = - mapOf( - "reason" to reason, - "name" to seriesPath.toString(), - ), - ) { + class SeriesFolderDeleted( + seriesId: String, + seriesPath: Path, + reason: String, + ) : HistoricalEvent( + type = "SeriesFolderDeleted", + seriesId = seriesId, + properties = + mapOf( + "reason" to reason, + "name" to seriesPath.toString(), + ), + ) { constructor(series: Series, reason: String) : this(series.id, series.path, reason) } - class BookConverted(book: Book, previous: Book) : HistoricalEvent( - type = "BookConverted", - bookId = book.id, - seriesId = book.seriesId, - properties = - mapOf( - "name" to book.path.toString(), - "former file" to previous.path.toString(), - ), - ) + class BookConverted( + book: Book, + previous: Book, + ) : HistoricalEvent( + type = "BookConverted", + bookId = book.id, + seriesId = book.seriesId, + properties = + mapOf( + "name" to book.path.toString(), + "former file" to previous.path.toString(), + ), + ) - class BookImported(book: Book, series: Series, source: Path, upgrade: Boolean) : HistoricalEvent( - type = "BookImported", - bookId = book.id, - seriesId = series.id, - properties = - mapOf( - "name" to book.path.toString(), - "source" to source.toString(), - "upgrade" to if (upgrade) "Yes" else "No", - ), - ) + class BookImported( + book: Book, + series: Series, + source: Path, + upgrade: Boolean, + ) : HistoricalEvent( + type = "BookImported", + bookId = book.id, + seriesId = series.id, + properties = + mapOf( + "name" to book.path.toString(), + "source" to source.toString(), + "upgrade" to if (upgrade) "Yes" else "No", + ), + ) - class DuplicatePageDeleted(book: Book, page: BookPageNumbered) : HistoricalEvent( - type = "DuplicatePageDeleted", - bookId = book.id, - seriesId = book.seriesId, - properties = - mapOf( - "name" to book.path.toString(), - "page number" to page.pageNumber.toString(), - "page file name" to page.fileName, - "page file hash" to page.fileHash, - "page file size" to page.fileSize.toString(), - "page media type" to page.mediaType, - ), - ) + class DuplicatePageDeleted( + book: Book, + page: BookPageNumbered, + ) : HistoricalEvent( + type = "DuplicatePageDeleted", + bookId = book.id, + seriesId = book.seriesId, + properties = + mapOf( + "name" to book.path.toString(), + "page number" to page.pageNumber.toString(), + "page file name" to page.fileName, + "page file hash" to page.fileHash, + "page file size" to page.fileSize.toString(), + "page media type" to page.mediaType, + ), + ) } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/KomgaUser.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/KomgaUser.kt index d30f88ef..0bd780d7 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/KomgaUser.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/KomgaUser.kt @@ -62,11 +62,9 @@ data class KomgaUser( fun canAccessAllLibraries(): Boolean = sharedAllLibraries || roleAdmin - fun canAccessLibrary(libraryId: String): Boolean = - canAccessAllLibraries() || sharedLibrariesIds.any { it == libraryId } + fun canAccessLibrary(libraryId: String): Boolean = canAccessAllLibraries() || sharedLibrariesIds.any { it == libraryId } - fun canAccessLibrary(library: Library): Boolean = - canAccessAllLibraries() || sharedLibrariesIds.any { it == library.id } + fun canAccessLibrary(library: Library): Boolean = canAccessAllLibraries() || sharedLibrariesIds.any { it == library.id } fun isContentAllowed( ageRating: Int? = null, @@ -109,6 +107,5 @@ data class KomgaUser( return !ageDenied && !labelDenied } - override fun toString(): String = - "KomgaUser(email='$email', roleAdmin=$roleAdmin, roleFileDownload=$roleFileDownload, rolePageStreaming=$rolePageStreaming, roleKoboSync=$roleKoboSync, sharedLibrariesIds=$sharedLibrariesIds, sharedAllLibraries=$sharedAllLibraries, restrictions=$restrictions, id='$id', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate)" + override fun toString(): String = "KomgaUser(email='$email', roleAdmin=$roleAdmin, roleFileDownload=$roleFileDownload, rolePageStreaming=$rolePageStreaming, roleKoboSync=$roleKoboSync, sharedLibrariesIds=$sharedLibrariesIds, sharedAllLibraries=$sharedAllLibraries, restrictions=$restrictions, id='$id', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate)" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/Media.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/Media.kt index 26383090..6947a7c8 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/Media.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/Media.kt @@ -27,7 +27,5 @@ data class Media( OUTDATED, } - override fun toString(): String { - return "Media(status=$status, mediaType=$mediaType, comment=$comment, bookId='$bookId', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate)" - } + override fun toString(): String = "Media(status=$status, mediaType=$mediaType, comment=$comment, bookId='$bookId', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate)" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/MediaType.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/MediaType.kt index b676a9b6..84257542 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/MediaType.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/MediaType.kt @@ -1,6 +1,11 @@ package org.gotson.komga.domain.model -enum class MediaType(val type: String, val profile: MediaProfile, val fileExtension: String, val exportType: String = type) { +enum class MediaType( + val type: String, + val profile: MediaProfile, + val fileExtension: String, + val exportType: String = type, +) { ZIP("application/zip", MediaProfile.DIVINA, "cbz", "application/vnd.comicbook+zip"), RAR_GENERIC("application/x-rar-compressed", MediaProfile.DIVINA, "cbr", "application/vnd.comicbook-rar"), RAR_4("application/x-rar-compressed; version=4", MediaProfile.DIVINA, "cbr", "application/vnd.comicbook-rar"), diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/PageHashKnown.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/PageHashKnown.kt index 50b9d11c..b427524f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/PageHashKnown.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/PageHashKnown.kt @@ -10,7 +10,8 @@ class PageHashKnown( val matchCount: Int = 0, override val createdDate: LocalDateTime = LocalDateTime.now(), override val lastModifiedDate: LocalDateTime = createdDate, -) : Auditable, PageHash(hash, size) { +) : PageHash(hash, size), + Auditable { enum class Action { DELETE_AUTO, DELETE_MANUAL, diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchCondition.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchCondition.kt index 610753d6..15df714c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchCondition.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchCondition.kt @@ -42,7 +42,8 @@ class SearchCondition { data class LibraryId( @JsonProperty("libraryId") val operator: SearchOperator.Equality, - ) : Book, Series + ) : Book, + Series data class CollectionId( @JsonProperty("collectionId") @@ -62,7 +63,8 @@ class SearchCondition { data class Deleted( @JsonProperty("deleted") val operator: SearchOperator.Boolean, - ) : Book, Series + ) : Book, + Series data class Complete( @JsonProperty("complete") @@ -72,12 +74,14 @@ class SearchCondition { data class OneShot( @JsonProperty("oneShot") val operator: SearchOperator.Boolean, - ) : Book, Series + ) : Book, + Series data class Title( @JsonProperty("title") val operator: SearchOperator.StringOp, - ) : Book, Series + ) : Book, + Series data class TitleSort( @JsonProperty("titleSort") @@ -87,7 +91,8 @@ class SearchCondition { data class ReleaseDate( @JsonProperty("releaseDate") val operator: SearchOperator.Date, - ) : Book, Series + ) : Book, + Series data class NumberSort( @JsonProperty("numberSort") @@ -97,7 +102,8 @@ class SearchCondition { data class Tag( @JsonProperty("tag") val operator: SearchOperator.Equality, - ) : Book, Series + ) : Book, + Series data class SharingLabel( @JsonProperty("sharingLabel") @@ -127,7 +133,8 @@ class SearchCondition { data class ReadStatus( @JsonProperty("readStatus") val operator: SearchOperator.Equality, - ) : Book, Series + ) : Book, + Series data class MediaStatus( @JsonProperty("mediaStatus") @@ -147,7 +154,8 @@ class SearchCondition { data class Author( @JsonProperty("author") val operator: SearchOperator.Equality, - ) : Book, Series + ) : Book, + Series @JsonInclude(JsonInclude.Include.NON_NULL) data class AuthorMatch( diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchContext.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchContext.kt index 8d15047b..3ba01265 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchContext.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchContext.kt @@ -1,6 +1,10 @@ package org.gotson.komga.domain.model -class SearchContext private constructor(val userId: String?, val restrictions: ContentRestrictions, val libraryIds: Collection?) { +class SearchContext private constructor( + val userId: String?, + val restrictions: ContentRestrictions, + val libraryIds: Collection?, +) { constructor(user: KomgaUser?) : this(user?.id, user?.restrictions ?: ContentRestrictions(), user?.getAuthorizedLibraryIds(null)) companion object { diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchOperator.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchOperator.kt index 3f2644e8..4eae7ae5 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchOperator.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/SearchOperator.kt @@ -49,46 +49,82 @@ class SearchOperator { sealed interface Boolean @JsonTypeName("is") - data class Is(val value: T) : Equality, StringOp, Numeric, NumericNullable + data class Is( + val value: T, + ) : Equality, + StringOp, + Numeric, + NumericNullable @JsonTypeName("isNot") - data class IsNot(val value: T) : Equality, StringOp, Numeric, NumericNullable + data class IsNot( + val value: T, + ) : Equality, + StringOp, + Numeric, + NumericNullable @JsonTypeName("contains") - data class Contains(val value: String) : StringOp + data class Contains( + val value: String, + ) : StringOp @JsonTypeName("doesNotContain") - data class DoesNotContain(val value: String) : StringOp + data class DoesNotContain( + val value: String, + ) : StringOp @JsonTypeName("beginsWith") - data class BeginsWith(val value: String) : StringOp + data class BeginsWith( + val value: String, + ) : StringOp @JsonTypeName("doesNotBeginWith") - data class DoesNotBeginWith(val value: String) : StringOp + data class DoesNotBeginWith( + val value: String, + ) : StringOp @JsonTypeName("endsWith") - data class EndsWith(val value: String) : StringOp + data class EndsWith( + val value: String, + ) : StringOp @JsonTypeName("doesNotEndWith") - data class DoesNotEndWith(val value: String) : StringOp + data class DoesNotEndWith( + val value: String, + ) : StringOp @JsonTypeName("greaterThan") - data class GreaterThan(val value: T) : Numeric, NumericNullable + data class GreaterThan( + val value: T, + ) : Numeric, + NumericNullable @JsonTypeName("lessThan") - data class LessThan(val value: T) : Numeric, NumericNullable + data class LessThan( + val value: T, + ) : Numeric, + NumericNullable @JsonTypeName("before") - data class Before(val dateTime: ZonedDateTime) : Date + data class Before( + val dateTime: ZonedDateTime, + ) : Date @JsonTypeName("after") - data class After(val dateTime: ZonedDateTime) : Date + data class After( + val dateTime: ZonedDateTime, + ) : Date @JsonTypeName("isInTheLast") - data class IsInTheLast(val duration: Duration) : Date + data class IsInTheLast( + val duration: Duration, + ) : Date @JsonTypeName("isNotInTheLast") - data class IsNotInTheLast(val duration: Duration) : Date + data class IsNotInTheLast( + val duration: Duration, + ) : Date @JsonTypeName("isTrue") data object IsTrue : Boolean @@ -110,9 +146,7 @@ class SearchOperator { return true } - override fun hashCode(): Int { - return javaClass.hashCode() - } + override fun hashCode(): Int = javaClass.hashCode() } @JsonTypeName("isNotNull") @@ -123,8 +157,6 @@ class SearchOperator { return true } - override fun hashCode(): Int { - return javaClass.hashCode() - } + override fun hashCode(): Int = javaClass.hashCode() } } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/SeriesMetadata.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/SeriesMetadata.kt index 8e6972c0..91dbf299 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/SeriesMetadata.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/SeriesMetadata.kt @@ -77,40 +77,39 @@ class SeriesMetadata( seriesId: String = this.seriesId, createdDate: LocalDateTime = this.createdDate, lastModifiedDate: LocalDateTime = this.lastModifiedDate, - ) = - SeriesMetadata( - status = status, - title = title, - titleSort = titleSort, - summary = summary, - readingDirection = readingDirection, - publisher = publisher, - ageRating = ageRating, - language = language, - genres = genres, - tags = tags, - totalBookCount = totalBookCount, - sharingLabels = sharingLabels, - links = links, - alternateTitles = alternateTitles, - statusLock = statusLock, - titleLock = titleLock, - titleSortLock = titleSortLock, - summaryLock = summaryLock, - readingDirectionLock = readingDirectionLock, - publisherLock = publisherLock, - ageRatingLock = ageRatingLock, - languageLock = languageLock, - genresLock = genresLock, - tagsLock = tagsLock, - totalBookCountLock = totalBookCountLock, - sharingLabelsLock = sharingLabelsLock, - linksLock = linksLock, - alternateTitlesLock = alternateTitlesLock, - seriesId = seriesId, - createdDate = createdDate, - lastModifiedDate = lastModifiedDate, - ) + ) = SeriesMetadata( + status = status, + title = title, + titleSort = titleSort, + summary = summary, + readingDirection = readingDirection, + publisher = publisher, + ageRating = ageRating, + language = language, + genres = genres, + tags = tags, + totalBookCount = totalBookCount, + sharingLabels = sharingLabels, + links = links, + alternateTitles = alternateTitles, + statusLock = statusLock, + titleLock = titleLock, + titleSortLock = titleSortLock, + summaryLock = summaryLock, + readingDirectionLock = readingDirectionLock, + publisherLock = publisherLock, + ageRatingLock = ageRatingLock, + languageLock = languageLock, + genresLock = genresLock, + tagsLock = tagsLock, + totalBookCountLock = totalBookCountLock, + sharingLabelsLock = sharingLabelsLock, + linksLock = linksLock, + alternateTitlesLock = alternateTitlesLock, + seriesId = seriesId, + createdDate = createdDate, + lastModifiedDate = lastModifiedDate, + ) enum class Status { ENDED, @@ -126,6 +125,5 @@ class SeriesMetadata( WEBTOON, } - override fun toString(): String = - "SeriesMetadata(status=$status, readingDirection=$readingDirection, ageRating=$ageRating, totalBookCount=$totalBookCount, links=$links, alternateTitles=$alternateTitles, statusLock=$statusLock, titleLock=$titleLock, titleSortLock=$titleSortLock, summaryLock=$summaryLock, readingDirectionLock=$readingDirectionLock, publisherLock=$publisherLock, ageRatingLock=$ageRatingLock, languageLock=$languageLock, genresLock=$genresLock, tagsLock=$tagsLock, totalBookCountLock=$totalBookCountLock, sharingLabelsLock=$sharingLabelsLock, linksLock=$linksLock, alternateTitlesLock=$alternateTitlesLock, seriesId='$seriesId', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate, title='$title', titleSort='$titleSort', summary='$summary', publisher='$publisher', language='$language', tags=$tags, genres=$genres, sharingLabels=$sharingLabels)" + override fun toString(): String = "SeriesMetadata(status=$status, readingDirection=$readingDirection, ageRating=$ageRating, totalBookCount=$totalBookCount, links=$links, alternateTitles=$alternateTitles, statusLock=$statusLock, titleLock=$titleLock, titleSortLock=$titleSortLock, summaryLock=$summaryLock, readingDirectionLock=$readingDirectionLock, publisherLock=$publisherLock, ageRatingLock=$ageRatingLock, languageLock=$languageLock, genresLock=$genresLock, tagsLock=$tagsLock, totalBookCountLock=$totalBookCountLock, sharingLabelsLock=$sharingLabelsLock, linksLock=$linksLock, alternateTitlesLock=$alternateTitlesLock, seriesId='$seriesId', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate, title='$title', titleSort='$titleSort', summary='$summary', publisher='$publisher', language='$language', tags=$tags, genres=$genres, sharingLabels=$sharingLabels)" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/ThumbnailSize.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/ThumbnailSize.kt index 293ed376..e65c72de 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/ThumbnailSize.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/ThumbnailSize.kt @@ -1,6 +1,8 @@ package org.gotson.komga.domain.model -enum class ThumbnailSize(val maxEdge: Int) { +enum class ThumbnailSize( + val maxEdge: Int, +) { DEFAULT(300), MEDIUM(600), LARGE(900), diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookAnalyzer.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookAnalyzer.kt index 28fedfe4..10d14faf 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookAnalyzer.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookAnalyzer.kt @@ -206,12 +206,20 @@ class BookAnalyzer( fun getPoster(book: BookWithMedia): TypedBytes? = when (book.media.profile) { MediaProfile.DIVINA -> - divinaExtractors[book.media.mediaType]?.getEntryStream(book.book.path, book.media.pages.first().fileName)?.let { - TypedBytes( - it, - book.media.pages.first().mediaType, - ) - } + divinaExtractors[book.media.mediaType] + ?.getEntryStream( + book.book.path, + book.media.pages + .first() + .fileName, + )?.let { + TypedBytes( + it, + book.media.pages + .first() + .mediaType, + ) + } MediaProfile.PDF -> pdfExtractor.getPageContentAsImage(book.book.path, 1) MediaProfile.EPUB -> epubExtractor.getCover(book.book.path) diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookConverter.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookConverter.kt index 4dc08cbb..6e6155cc 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookConverter.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookConverter.kt @@ -60,7 +60,8 @@ class BookConverter( fun getConvertibleBooks(library: Library): Collection = if (library.convertToCbz) { - bookRepository.findAllByLibraryIdAndMediaTypes(library.id, convertibleTypes) + bookRepository + .findAllByLibraryIdAndMediaTypes(library.id, convertibleTypes) .also { logger.info { "Found ${it.size} books to convert" } } } else { logger.info { "CBZ conversion is not enabled, skipping" } @@ -100,7 +101,8 @@ class BookConverter( zipStream.setLevel(Deflater.NO_COMPRESSION) media - .pages.map { it.fileName } + .pages + .map { it.fileName } .union(media.files.map { it.fileName }) .forEach { entry -> zipStream.putArchiveEntry(ZipArchiveEntry(entry)) @@ -111,7 +113,8 @@ class BookConverter( // perform checks on new file val convertedBook = - fileSystemScanner.scanFile(destinationPath) + fileSystemScanner + .scanFile(destinationPath) ?.copy( id = book.id, seriesId = book.seriesId, @@ -129,11 +132,13 @@ class BookConverter( convertedMedia.mediaType != MediaType.ZIP.type -> throw BookConversionException("Converted file is not a zip file, aborting conversion") - !convertedMedia.pages.map { FilenameUtils.getName(it.fileName) to it.mediaType } + !convertedMedia.pages + .map { FilenameUtils.getName(it.fileName) to it.mediaType } .containsAll(media.pages.map { FilenameUtils.getName(it.fileName) to it.mediaType }) -> throw BookConversionException("Converted file does not contain all pages from existing file, aborting conversion") - !convertedMedia.files.map { FilenameUtils.getName(it.fileName) } + !convertedMedia.files + .map { FilenameUtils.getName(it.fileName) } .containsAll(media.files.map { FilenameUtils.getName(it.fileName) }) -> throw BookConversionException("Converted file does not contain all files from existing file, aborting conversion") } @@ -201,7 +206,8 @@ class BookConverter( book.path.moveTo(destinationPath) val repairedBook = - fileSystemScanner.scanFile(destinationPath) + fileSystemScanner + .scanFile(destinationPath) ?.copy( id = book.id, seriesId = book.seriesId, diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookImporter.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookImporter.kt index 51ba2c80..42ff75f9 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookImporter.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookImporter.kt @@ -89,9 +89,16 @@ class BookImporter( fileSystemScanner.scanBookSidecars(sourceFile).associateWith { series.path.resolve( if (destinationName != null) - it.url.toURI().toPath().name.replace(sourceFile.nameWithoutExtension, destinationName, true) + it.url + .toURI() + .toPath() + .name + .replace(sourceFile.nameWithoutExtension, destinationName, true) else - it.url.toURI().toPath().name, + it.url + .toURI() + .toPath() + .name, ) } @@ -166,13 +173,17 @@ class BookImporter( logger.warn(e) { "Filesystem does not support hardlinks, copying instead" } sourceFile.copyTo(destFile) sidecars.forEach { - it.key.url.toURI().toPath().copyTo(it.value, true) + it.key.url + .toURI() + .toPath() + .copyTo(it.value, true) } } } val importedBook = - fileSystemScanner.scanFile(destFile) + fileSystemScanner + .scanFile(destFile) ?.copy(libraryId = series.libraryId) ?: throw IllegalStateException("Newly imported book could not be scanned: $destFile").withCode("ERR_1022") @@ -200,16 +211,21 @@ class BookImporter( } // copy read progress - readProgressRepository.findAllByBookId(bookToUpgrade.id) + readProgressRepository + .findAllByBookId(bookToUpgrade.id) .map { it.copy(bookId = importedBook.id) } .forEach { readProgressRepository.save(it) } // replace upgraded book by imported book in read lists - readListRepository.findAllContainingBookId(bookToUpgrade.id, filterOnLibraryIds = null) + readListRepository + .findAllContainingBookId(bookToUpgrade.id, filterOnLibraryIds = null) .forEach { rl -> readListRepository.update( rl.copy( - bookIds = rl.bookIds.values.map { if (it == bookToUpgrade.id) importedBook.id else it }.toIndexedMap(), + bookIds = + rl.bookIds.values + .map { if (it == bookToUpgrade.id) importedBook.id else it } + .toIndexedMap(), ), ) } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt index ed91a597..052d40bf 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt @@ -82,7 +82,8 @@ class BookLifecycle( mediaRepository.findById(book.id).let { previous -> if (previous.status == Media.Status.OUTDATED && previous.pageCount != media.pageCount) { val adjustedProgress = - readProgressRepository.findAllByBookId(book.id) + readProgressRepository + .findAllByBookId(book.id) .map { it.copy(page = if (it.completed) media.pageCount else 1) } if (adjustedProgress.isNotEmpty()) { logger.info { "Number of pages differ, adjust read progress for book" } @@ -145,7 +146,8 @@ class BookLifecycle( ThumbnailBook.Type.SIDECAR -> { // delete existing thumbnail with the same url - thumbnailBookRepository.findAllByBookIdAndType(thumbnail.bookId, setOf(ThumbnailBook.Type.SIDECAR)) + thumbnailBookRepository + .findAllByBookIdAndType(thumbnail.bookId, setOf(ThumbnailBook.Type.SIDECAR)) .filter { it.url == thumbnail.url } .forEach { thumbnailBookRepository.delete(it.id) @@ -253,7 +255,8 @@ class BookLifecycle( private fun thumbnailsHouseKeeping(bookId: String) { logger.info { "House keeping thumbnails for book: $bookId" } val all = - thumbnailBookRepository.findAllByBookId(bookId) + thumbnailBookRepository + .findAllByBookId(bookId) .mapNotNull { if (!it.exists()) { logger.warn { "Thumbnail doesn't exist, removing entry" } @@ -278,13 +281,12 @@ class BookLifecycle( } } - fun findBookThumbnailsToRegenerate(forBiggerResultOnly: Boolean): Collection { - return if (forBiggerResultOnly) { + fun findBookThumbnailsToRegenerate(forBiggerResultOnly: Boolean): Collection = + if (forBiggerResultOnly) { thumbnailBookRepository.findAllBookIdsByThumbnailTypeAndDimensionSmallerThan(ThumbnailBook.Type.GENERATED, komgaSettingsProvider.thumbnailSize.maxEdge) } else { bookRepository.findAll(SearchCondition.Deleted(SearchOperator.IsFalse), SearchContext.empty(), Pageable.unpaged()).content.map { it.id } } - } @Throws( ImageConversionException::class, @@ -439,7 +441,12 @@ class BookLifecycle( newProgression: R2Progression, ) { readProgressRepository.findByBookIdAndUserIdOrNull(book.id, user.id)?.let { savedProgress -> - check(newProgression.modified.toLocalDateTime().toCurrentTimeZone().isAfter(savedProgress.readDate)) { "Progression is older than existing" } + check( + newProgression.modified + .toLocalDateTime() + .toCurrentTimeZone() + .isAfter(savedProgress.readDate), + ) { "Progression is older than existing" } } val media = mediaRepository.findById(book.id) @@ -465,7 +472,8 @@ class BookLifecycle( MediaProfile.EPUB -> { val href = newProgression.locator.href - .replaceAfter("#", "").removeSuffix("#") + .replaceAfter("#", "") + .removeSuffix("#") .let { UriUtils.decode(it, Charsets.UTF_8) } require(href in media.files.map { it.fileName }) { "Resource does not exist in book: $href" } requireNotNull(newProgression.locator.locations?.progression) { "location.progression is required" } @@ -519,7 +527,8 @@ class BookLifecycle( if (!book.path.isWritable()) return logger.info { "Cannot delete book file, path is not writable: ${book.path}" } val thumbnails = - thumbnailBookRepository.findAllByBookIdAndType(book.id, setOf(ThumbnailBook.Type.SIDECAR)) + thumbnailBookRepository + .findAllByBookIdAndType(book.id, setOf(ThumbnailBook.Type.SIDECAR)) .mapNotNull { it.url?.toURI()?.toPath() } .filter { it.exists() && it.isWritable() } @@ -531,7 +540,10 @@ class BookLifecycle( if (it.deleteIfExists()) logger.info { "Deleted file: $it" } } - if (book.path.parent.listDirectoryEntries().isEmpty()) + if (book.path.parent + .listDirectoryEntries() + .isEmpty() + ) if (book.path.parent.deleteIfExists()) { logger.info { "Deleted directory: ${book.path.parent}" } historicalEventRepository.insert(HistoricalEvent.SeriesFolderDeleted(book.seriesId, book.path.parent, "Folder was deleted because it was empty")) diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookPageEditor.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookPageEditor.kt index eaf275d8..a29c1edf 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookPageEditor.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookPageEditor.kt @@ -103,7 +103,8 @@ class BookPageEditor( zipStream.setMethod(ZipArchiveOutputStream.DEFLATED) zipStream.setLevel(Deflater.NO_COMPRESSION) - pagesToKeep.map { it.fileName } + pagesToKeep + .map { it.fileName } .union(media.files.map { it.fileName }) .forEach { entry -> zipStream.putArchiveEntry(ZipArchiveEntry(entry)) @@ -114,7 +115,8 @@ class BookPageEditor( // perform checks on new file val createdBook = - fileSystemScanner.scanFile(tempFile) + fileSystemScanner + .scanFile(tempFile) ?.copy( id = book.id, seriesId = book.seriesId, @@ -132,11 +134,13 @@ class BookPageEditor( createdMedia.mediaType != MediaType.ZIP.type -> throw BookConversionException("Created file is not a zip file, aborting page removal") - !createdMedia.pages.map { FilenameUtils.getName(it.fileName) to it.mediaType } + !createdMedia.pages + .map { FilenameUtils.getName(it.fileName) to it.mediaType } .containsAll(pagesToKeep.map { FilenameUtils.getName(it.fileName) to it.mediaType }) -> throw BookConversionException("Created file does not contain all pages to keep from existing file, aborting conversion") - !createdMedia.files.map { FilenameUtils.getName(it.fileName) } + !createdMedia.files + .map { FilenameUtils.getName(it.fileName) } .containsAll(media.files.map { FilenameUtils.getName(it.fileName) }) -> throw BookConversionException("Created file does not contain all files from existing file, aborting page removal") } @@ -148,7 +152,8 @@ class BookPageEditor( tempFile.moveTo(book.path, true) val newBook = - fileSystemScanner.scanFile(book.path) + fileSystemScanner + .scanFile(book.path) ?.copy( id = book.id, seriesId = book.seriesId, diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/FileSystemScanner.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/FileSystemScanner.kt index 8c586e0e..b91a4a99 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/FileSystemScanner.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/FileSystemScanner.kt @@ -121,12 +121,13 @@ class FileSystemScanner( } } - sidecarSeriesConsumers.firstOrNull { consumer -> - consumer.getSidecarSeriesFilenames().any { file.name.equals(it, ignoreCase = true) } - }?.let { - val sidecar = Sidecar(file.toUri().toURL(), file.parent.toUri().toURL(), attrs.getUpdatedTime(), it.getSidecarSeriesType(), Sidecar.Source.SERIES) - pathToSeriesSidecars.merge(file.parent, mutableListOf(sidecar)) { prev, one -> prev.union(one).toMutableList() } - } + sidecarSeriesConsumers + .firstOrNull { consumer -> + consumer.getSidecarSeriesFilenames().any { file.name.equals(it, ignoreCase = true) } + }?.let { + val sidecar = Sidecar(file.toUri().toURL(), file.parent.toUri().toURL(), attrs.getUpdatedTime(), it.getSidecarSeriesType(), Sidecar.Source.SERIES) + pathToSeriesSidecars.merge(file.parent, mutableListOf(sidecar)) { prev, one -> prev.union(one).toMutableList() } + } // book sidecars can't be exactly matched during a file visit // this prefilters files to reduce the candidates @@ -217,7 +218,8 @@ class FileSystemScanner( fun scanBookSidecars(path: Path): List { val bookBaseName = path.nameWithoutExtension val parent = path.parent - return parent.listDirectoryEntries() + return parent + .listDirectoryEntries() .filter { candidate -> sidecarBookPrefilter.any { it.matches(candidate.name) } } .mapNotNull { candidate -> sidecarBookConsumers.firstOrNull { it.isSidecarBookMatch(bookBaseName, candidate.name) }?.let { @@ -238,8 +240,6 @@ class FileSystemScanner( ) } -fun BasicFileAttributes.getUpdatedTime(): LocalDateTime = - maxOf(creationTime(), lastModifiedTime()).toLocalDateTime() +fun BasicFileAttributes.getUpdatedTime(): LocalDateTime = maxOf(creationTime(), lastModifiedTime()).toLocalDateTime() -fun FileTime.toLocalDateTime(): LocalDateTime = - LocalDateTime.ofInstant(this.toInstant(), ZoneId.systemDefault()) +fun FileTime.toLocalDateTime(): LocalDateTime = LocalDateTime.ofInstant(this.toInstant(), ZoneId.systemDefault()) diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycle.kt index ee5dd322..9315653c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycle.kt @@ -127,7 +127,11 @@ class LibraryContentLifecycle( if (books.isNotEmpty()) { logger.info { "Soft deleting books not on disk anymore: $books" } bookLifecycle.softDeleteMany(books) - books.map { it.seriesId }.distinct().mapNotNull { seriesRepository.findByIdOrNull(it) }.toMutableList() + books + .map { it.seriesId } + .distinct() + .mapNotNull { seriesRepository.findByIdOrNull(it) } + .toMutableList() } else { mutableListOf() } @@ -281,7 +285,9 @@ class LibraryContentLifecycle( val bookSizes = newBooks.map { it.fileSize } val deletedCandidates = - seriesRepository.findAll(SearchCondition.Deleted(SearchOperator.IsTrue), SearchContext.empty(), Pageable.unpaged()).content + seriesRepository + .findAll(SearchCondition.Deleted(SearchOperator.IsTrue), SearchContext.empty(), Pageable.unpaged()) + .content .mapNotNull { deletedCandidate -> val deletedBooks = bookRepository.findAllBySeriesId(deletedCandidate.id) val deletedBooksSizes = deletedBooks.map { it.fileSize } @@ -324,7 +330,8 @@ class LibraryContentLifecycle( } // replace deleted series by new series in collections - collectionRepository.findAllContainingSeriesId(match.first.id, filterOnLibraryIds = null) + collectionRepository + .findAllContainingSeriesId(match.first.id, filterOnLibraryIds = null) .forEach { col -> collectionRepository.update( col.copy( @@ -396,16 +403,21 @@ class LibraryContentLifecycle( } // copy read progress - readProgressRepository.findAllByBookId(match.id) + readProgressRepository + .findAllByBookId(match.id) .map { it.copy(bookId = bookToAdd.id) } .forEach { readProgressRepository.save(it) } // replace deleted book by new book in read lists - readListRepository.findAllContainingBookId(match.id, filterOnLibraryIds = null) + readListRepository + .findAllContainingBookId(match.id, filterOnLibraryIds = null) .forEach { rl -> readListRepository.update( rl.copy( - bookIds = rl.bookIds.values.map { if (it == match.id) bookToAdd.id else it }.toIndexedMap(), + bookIds = + rl.bookIds.values + .map { if (it == match.id) bookToAdd.id else it } + .toIndexedMap(), ), ) } @@ -422,25 +434,27 @@ class LibraryContentLifecycle( logger.info { "Empty trash for library: $library" } val seriesToDelete = - seriesRepository.findAll( - SearchCondition.AllOfSeries( - SearchCondition.LibraryId(SearchOperator.Is(library.id)), - SearchCondition.Deleted(SearchOperator.IsTrue), - ), - SearchContext.empty(), - Pageable.unpaged(), - ).content + seriesRepository + .findAll( + SearchCondition.AllOfSeries( + SearchCondition.LibraryId(SearchOperator.Is(library.id)), + SearchCondition.Deleted(SearchOperator.IsTrue), + ), + SearchContext.empty(), + Pageable.unpaged(), + ).content seriesLifecycle.deleteMany(seriesToDelete) val booksToDelete = - bookRepository.findAll( - SearchCondition.AllOfBook( - SearchCondition.LibraryId(SearchOperator.Is(library.id)), - SearchCondition.Deleted(SearchOperator.IsTrue), - ), - SearchContext.empty(), - Pageable.unpaged(), - ).content + bookRepository + .findAll( + SearchCondition.AllOfBook( + SearchCondition.LibraryId(SearchOperator.Is(library.id)), + SearchCondition.Deleted(SearchOperator.IsTrue), + ), + SearchContext.empty(), + Pageable.unpaged(), + ).content bookLifecycle.deleteMany(booksToDelete) booksToDelete.map { it.seriesId }.distinct().forEach { seriesId -> seriesRepository.findByIdOrNull(seriesId)?.let { seriesLifecycle.sortBooks(it) } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/PageHashLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/PageHashLifecycle.kt index a4c0d95f..dfd0f970 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/PageHashLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/PageHashLifecycle.kt @@ -27,7 +27,8 @@ class PageHashLifecycle( fun getBookIdsWithMissingPageHash(library: Library): Collection = if (library.hashPages) { - mediaRepository.findAllBookIdsByLibraryIdAndMediaTypeAndWithMissingPageHash(library.id, hashableMediaTypes, komgaProperties.pageHashing) + mediaRepository + .findAllBookIdsByLibraryIdAndMediaTypeAndWithMissingPageHash(library.id, hashableMediaTypes, komgaProperties.pageHashing) .also { logger.info { "Found ${it.size} books with missing page hash" } } } else { logger.info { "Page hashing is not enabled, skipping" } @@ -44,8 +45,7 @@ class PageHashLifecycle( return bookLifecycle.getBookPage(book, match.pageNumber, resizeTo = resizeTo) } - fun getBookPagesToDeleteAutomatically(library: Library): Map> = - pageHashRepository.findMatchesByKnownHashAction(listOf(PageHashKnown.Action.DELETE_AUTO), library.id) + fun getBookPagesToDeleteAutomatically(library: Library): Map> = pageHashRepository.findMatchesByKnownHashAction(listOf(PageHashKnown.Action.DELETE_AUTO), library.id) fun createOrUpdate(pageHash: PageHashKnown) { val existing = pageHashRepository.findKnown(pageHash.hash) diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/ReadListLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/ReadListLifecycle.kt index 7c74dc3d..4863f132 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/ReadListLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/ReadListLifecycle.kt @@ -147,8 +147,7 @@ class ReadListLifecycle( eventPublisher.publishEvent(DomainEvent.ThumbnailReadListDeleted(thumbnail)) } - fun getThumbnailBytes(thumbnailId: String): ByteArray? = - thumbnailReadListRepository.findByIdOrNull(thumbnailId)?.thumbnail + fun getThumbnailBytes(thumbnailId: String): ByteArray? = thumbnailReadListRepository.findByIdOrNull(thumbnailId)?.thumbnail fun getThumbnailBytes(readList: ReadList): ByteArray { thumbnailReadListRepository.findSelectedByReadListIdOrNull(readList.id)?.let { diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesCollectionLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesCollectionLifecycle.kt index e812b5f4..812552bc 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesCollectionLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesCollectionLifecycle.kt @@ -133,8 +133,7 @@ class SeriesCollectionLifecycle( eventPublisher.publishEvent(DomainEvent.ThumbnailSeriesCollectionDeleted(thumbnail)) } - fun getThumbnailBytes(thumbnailId: String): ByteArray? = - thumbnailSeriesCollectionRepository.findByIdOrNull(thumbnailId)?.thumbnail + fun getThumbnailBytes(thumbnailId: String): ByteArray? = thumbnailSeriesCollectionRepository.findByIdOrNull(thumbnailId)?.thumbnail fun getThumbnailBytes( collection: SeriesCollection, diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesLifecycle.kt index 1ccef6f5..7859ed30 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesLifecycle.kt @@ -81,8 +81,7 @@ class SeriesLifecycle( .stripAccents() .replace(whitespacePattern, " ") }, - ) - .map { book -> book to metadatas.first { it.bookId == book.id } } + ).map { book -> book to metadatas.first { it.bookId == book.id } } logger.debug { "Sorted books: $sorted" } bookRepository.update( @@ -135,14 +134,15 @@ class SeriesLifecycle( mediaRepository.insert(toAdd.map { Media(bookId = it.id) }) // create associated metadata - toAdd.map { - BookMetadata( - title = it.name, - number = it.number.toString(), - numberSort = it.number.toFloat(), - bookId = it.id, - ) - }.let { bookMetadataRepository.insert(it) } + toAdd + .map { + BookMetadata( + title = it.name, + number = it.number.toString(), + numberSort = it.number.toFloat(), + bookId = it.id, + ) + }.let { bookMetadataRepository.insert(it) } } toAdd.forEach { eventPublisher.publishEvent(DomainEvent.BookAdded(it)) } @@ -208,13 +208,15 @@ class SeriesLifecycle( user: KomgaUser, ) { val bookIds = - bookRepository.findAllIdsBySeriesId(seriesId) + bookRepository + .findAllIdsBySeriesId(seriesId) .filter { bookId -> val readProgress = readProgressRepository.findByBookIdAndUserIdOrNull(bookId, user.id) readProgress == null || !readProgress.completed } val progresses = - mediaRepository.getPagesSizes(bookIds) + mediaRepository + .getPagesSizes(bookIds) .map { (bookId, pageSize) -> ReadProgress(bookId, user.id, pageSize, true) } readProgressRepository.save(progresses) @@ -291,7 +293,8 @@ class SeriesLifecycle( ): ThumbnailSeries { // delete existing thumbnail with the same url if (thumbnail.url != null) { - thumbnailsSeriesRepository.findAllBySeriesId(thumbnail.seriesId) + thumbnailsSeriesRepository + .findAllBySeriesId(thumbnail.seriesId) .filter { it.url == thumbnail.url } .forEach { thumbnailsSeriesRepository.delete(it.id) @@ -327,11 +330,13 @@ class SeriesLifecycle( if (!series.path.isWritable()) return logger.info { "Cannot delete series folder, path is not writable: ${series.path}" } val thumbnails = - thumbnailsSeriesRepository.findAllBySeriesIdIdAndType(series.id, ThumbnailSeries.Type.SIDECAR) + thumbnailsSeriesRepository + .findAllBySeriesIdIdAndType(series.id, ThumbnailSeries.Type.SIDECAR) .mapNotNull { it.url?.toURI()?.toPath() } .filter { it.exists() && it.isWritable() } - bookRepository.findAllBySeriesId(series.id) + bookRepository + .findAllBySeriesId(series.id) .forEach { bookLifecycle.deleteBookFiles(it) } thumbnails.forEach { if (it.deleteIfExists()) logger.info { "Deleted file: $it" } @@ -349,7 +354,8 @@ class SeriesLifecycle( private fun thumbnailsHouseKeeping(seriesId: String) { logger.info { "House keeping thumbnails for series: $seriesId" } val all = - thumbnailsSeriesRepository.findAllBySeriesId(seriesId) + thumbnailsSeriesRepository + .findAllBySeriesId(seriesId) .mapNotNull { if (!it.exists()) { logger.warn { "Thumbnail doesn't exist, removing entry" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesMetadataLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesMetadataLifecycle.kt index d36aa04c..4917658b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesMetadataLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesMetadataLifecycle.kt @@ -49,7 +49,8 @@ class SeriesMetadataLifecycle( else -> { logger.debug { "Provider: ${provider.javaClass.simpleName}" } val patches = - bookRepository.findAllBySeriesId(series.id) + bookRepository + .findAllBySeriesId(series.id) .mapNotNull { book -> try { provider.getSeriesMetadataFromBook(BookWithMedia(book, mediaRepository.findById(book.id)), library.importComicInfoSeriesAppendVolume) @@ -107,7 +108,12 @@ class SeriesMetadataLifecycle( title = patches.mostFrequent { it.title }, titleSort = patches.mostFrequent { it.titleSort }, status = patches.mostFrequent { it.status }, - genres = patches.mapNotNull { it.genres }.flatten().toSet().ifEmpty { null }, + genres = + patches + .mapNotNull { it.genres } + .flatten() + .toSet() + .ifEmpty { null }, language = patches.mostFrequent { it.language }, summary = null, readingDirection = patches.mostFrequent { it.readingDirection }, diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/SyncPointLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/SyncPointLifecycle.kt index 0b22a9de..4a87c8b4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/SyncPointLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/SyncPointLifecycle.kt @@ -59,7 +59,8 @@ class SyncPointLifecycle( toSyncPointId: String, pageable: Pageable, ): Page = - syncPointRepository.findBooksById(toSyncPointId, true, pageable) + syncPointRepository + .findBooksById(toSyncPointId, true, pageable) .also { page -> syncPointRepository.markBooksSynced(toSyncPointId, false, page.content.map { it.bookId }) } /** @@ -70,7 +71,8 @@ class SyncPointLifecycle( toSyncPointId: String, pageable: Pageable, ): Page = - syncPointRepository.findBooksAdded(fromSyncPointId, toSyncPointId, true, pageable) + syncPointRepository + .findBooksAdded(fromSyncPointId, toSyncPointId, true, pageable) .also { page -> syncPointRepository.markBooksSynced(toSyncPointId, false, page.content.map { it.bookId }) } /** @@ -81,7 +83,8 @@ class SyncPointLifecycle( toSyncPointId: String, pageable: Pageable, ): Page = - syncPointRepository.findBooksChanged(fromSyncPointId, toSyncPointId, true, pageable) + syncPointRepository + .findBooksChanged(fromSyncPointId, toSyncPointId, true, pageable) .also { page -> syncPointRepository.markBooksSynced(toSyncPointId, false, page.content.map { it.bookId }) } /** @@ -92,7 +95,8 @@ class SyncPointLifecycle( toSyncPointId: String, pageable: Pageable, ): Page = - syncPointRepository.findBooksRemoved(fromSyncPointId, toSyncPointId, true, pageable) + syncPointRepository + .findBooksRemoved(fromSyncPointId, toSyncPointId, true, pageable) .also { page -> syncPointRepository.markBooksSynced(toSyncPointId, true, page.content.map { it.bookId }) } /** @@ -103,14 +107,16 @@ class SyncPointLifecycle( toSyncPointId: String, pageable: Pageable, ): Page = - syncPointRepository.findBooksReadProgressChanged(fromSyncPointId, toSyncPointId, true, pageable) + syncPointRepository + .findBooksReadProgressChanged(fromSyncPointId, toSyncPointId, true, pageable) .also { page -> syncPointRepository.markBooksSynced(toSyncPointId, false, page.content.map { it.bookId }) } fun takeReadLists( toSyncPointId: String, pageable: Pageable, ): Page = - syncPointRepository.findReadListsById(toSyncPointId, true, pageable) + syncPointRepository + .findReadListsById(toSyncPointId, true, pageable) .also { page -> syncPointRepository.markReadListsSynced(toSyncPointId, false, page.content.map { it.readListId }) } fun takeReadListsAdded( @@ -118,7 +124,8 @@ class SyncPointLifecycle( toSyncPointId: String, pageable: Pageable, ): Page = - syncPointRepository.findReadListsAdded(fromSyncPointId, toSyncPointId, true, pageable) + syncPointRepository + .findReadListsAdded(fromSyncPointId, toSyncPointId, true, pageable) .also { page -> syncPointRepository.markReadListsSynced(toSyncPointId, false, page.content.map { it.readListId }) } fun takeReadListsChanged( @@ -126,7 +133,8 @@ class SyncPointLifecycle( toSyncPointId: String, pageable: Pageable, ): Page = - syncPointRepository.findReadListsChanged(fromSyncPointId, toSyncPointId, true, pageable) + syncPointRepository + .findReadListsChanged(fromSyncPointId, toSyncPointId, true, pageable) .also { page -> syncPointRepository.markReadListsSynced(toSyncPointId, false, page.content.map { it.readListId }) } fun takeReadListsRemoved( @@ -134,6 +142,7 @@ class SyncPointLifecycle( toSyncPointId: String, pageable: Pageable, ): Page = - syncPointRepository.findReadListsRemoved(fromSyncPointId, toSyncPointId, true, pageable) + syncPointRepository + .findReadListsRemoved(fromSyncPointId, toSyncPointId, true, pageable) .also { page -> syncPointRepository.markReadListsSynced(toSyncPointId, true, page.content.map { it.readListId }) } } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/ThumbnailLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/ThumbnailLifecycle.kt index c01990e9..b152fc7e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/ThumbnailLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/ThumbnailLifecycle.kt @@ -40,8 +40,7 @@ class ThumbnailLifecycle( * * @return true if more thumbnails need fixing */ - fun fixThumbnailsMetadata(): Boolean = - fixThumbnailMetadataBook() || fixThumbnailMetadataSeries() || fixThumbnailMetadataCollection() || fixThumbnailMetadataReadList() + fun fixThumbnailsMetadata(): Boolean = fixThumbnailMetadataBook() || fixThumbnailMetadataSeries() || fixThumbnailMetadataCollection() || fixThumbnailMetadataReadList() private fun fixThumbnailMetadataBook(): Boolean = fixThumbnailMetadata( @@ -162,7 +161,14 @@ class ThumbnailLifecycle( dimension = imageAnalyzer.getDimension(url.toURI().toPath().inputStream()) ?: Dimension(0, 0), ) - private data class Result(val processed: Int, val hasMore: Boolean) + private data class Result( + val processed: Int, + val hasMore: Boolean, + ) - private data class ThumbnailMetadata(val mediaType: String, val fileSize: Long, val dimension: Dimension) + private data class ThumbnailMetadata( + val mediaType: String, + val fileSize: Long, + val dimension: Dimension, + ) } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/TransientBookLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/TransientBookLifecycle.kt index b0628249..5743942b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/TransientBookLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/TransientBookLifecycle.kt @@ -39,7 +39,12 @@ class TransientBookLifecycle( if (folderToScan.startsWith(library.path)) throw PathContainedInPath("Cannot scan folder that is part of an existing library", "ERR_1017") } - val books = fileSystemScanner.scanRootFolder(folderToScan).series.values.flatten().map { TransientBook(it, Media()) } + val books = + fileSystemScanner + .scanRootFolder(folderToScan) + .series.values + .flatten() + .map { TransientBook(it, Media()) } transientBookRepository.save(books) @@ -66,8 +71,7 @@ class TransientBookLifecycle( if (it.supportsAppendVolume) add(it.getSeriesMetadataFromBook(bookWithMedia, true)?.title) add(it.getSeriesMetadataFromBook(bookWithMedia, false)?.title) } - } - .filterNotNull() + }.filterNotNull() .firstNotNullOfOrNull { seriesRepository.findAllByTitleContaining(it).firstOrNull() } return series?.id to number diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/cache/TransientBookCache.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/cache/TransientBookCache.kt index dbc55157..5d93180c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/cache/TransientBookCache.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/cache/TransientBookCache.kt @@ -12,7 +12,8 @@ private val logger = KotlinLogging.logger {} @Service class TransientBookCache : TransientBookRepository { private val cache = - Caffeine.newBuilder() + Caffeine + .newBuilder() .expireAfterAccess(1, TimeUnit.HOURS) .build() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfiguration.kt index 0f71e9f6..a5f95930 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfiguration.kt @@ -16,8 +16,7 @@ class DataSourcesConfiguration( ) { @Bean("sqliteDataSource") @Primary - fun sqliteDataSource(): DataSource = - buildDataSource("SqliteMainPool", SqliteUdfDataSource::class.java, komgaProperties.database) + fun sqliteDataSource(): DataSource = buildDataSource("SqliteMainPool", SqliteUdfDataSource::class.java, komgaProperties.database) @Bean("tasksDataSource") fun tasksDataSource(): DataSource = @@ -41,7 +40,8 @@ class DataSourcesConfiguration( } val dataSource = - DataSourceBuilder.create() + DataSourceBuilder + .create() .driverClassName("org.sqlite.JDBC") .url("jdbc:sqlite:${databaseProps.file}$extraPragmas") .type(dataSourceClass) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/FlywaySecondaryMigrationInitializer.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/FlywaySecondaryMigrationInitializer.kt index de2e7be8..8e0a561f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/FlywaySecondaryMigrationInitializer.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/FlywaySecondaryMigrationInitializer.kt @@ -13,7 +13,8 @@ class FlywaySecondaryMigrationInitializer( ) : InitializingBean { // by default Spring Boot will perform migration only on the @Primary datasource override fun afterPropertiesSet() { - Flyway.configure() + Flyway + .configure() .locations("classpath:tasks/migration/sqlite") .dataSource(tasksDataSource) .load() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/SqliteUdfDataSource.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/SqliteUdfDataSource.kt index c8bc1049..e69fc795 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/SqliteUdfDataSource.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/SqliteUdfDataSource.kt @@ -17,14 +17,12 @@ class SqliteUdfDataSource : SQLiteDataSource() { const val COLLATION_UNICODE_3 = "COLLATION_UNICODE_3" } - override fun getConnection(): Connection = - super.getConnection().also { addAllUdf(it as SQLiteConnection) } + override fun getConnection(): Connection = super.getConnection().also { addAllUdf(it as SQLiteConnection) } override fun getConnection( username: String?, password: String?, - ): SQLiteConnection = - super.getConnection(username, password).also { addAllUdf(it) } + ): SQLiteConnection = super.getConnection(username, password).also { addAllUdf(it) } private fun addAllUdf(connection: SQLiteConnection) { createUdfRegexp(connection) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageConverter.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageConverter.kt index 56ff063e..b2736122 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageConverter.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageConverter.kt @@ -38,11 +38,14 @@ class ImageConverter( private fun chooseWebpReader() { val providers = - IIORegistry.getDefaultInstance().getServiceProviders( - ImageReaderSpi::class.java, - { it is ImageReaderSpi && it.mimeTypes.contains("image/webp") }, - false, - ).asSequence().toList() + IIORegistry + .getDefaultInstance() + .getServiceProviders( + ImageReaderSpi::class.java, + { it is ImageReaderSpi && it.mimeTypes.contains("image/webp") }, + false, + ).asSequence() + .toList() if (providers.size > 1) { logger.debug { "WebP reader providers: ${providers.map { it.javaClass.canonicalName }}" } @@ -60,8 +63,7 @@ class ImageConverter( fun canConvertMediaType( from: String, to: String, - ) = - supportedReadMediaTypes.contains(from) && supportedWriteMediaTypes.contains(to) + ) = supportedReadMediaTypes.contains(from) && supportedWriteMediaTypes.contains(to) fun convertImage( imageBytes: ByteArray, @@ -128,14 +130,14 @@ class ImageConverter( // prevent upscaling val resizeTo = if (longestEdge != null) min(longestEdge, size) else size - return Thumbnails.of(imageBytes.inputStream()) + return Thumbnails + .of(imageBytes.inputStream()) .size(resizeTo, resizeTo) .imageType(BufferedImage.TYPE_INT_ARGB) .outputFormat(format.imageIOFormat) } - private fun containsAlphaChannel(image: BufferedImage): Boolean = - image.colorModel.hasAlpha() + private fun containsAlphaChannel(image: BufferedImage): Boolean = image.colorModel.hasAlpha() private fun containsTransparency(image: BufferedImage): Boolean { for (x in 0 until image.width) { diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageType.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageType.kt index 88cc8485..91b3ea75 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageType.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/image/ImageType.kt @@ -1,6 +1,9 @@ package org.gotson.komga.infrastructure.image -enum class ImageType(val mediaType: String, val imageIOFormat: String) { +enum class ImageType( + val mediaType: String, + val imageIOFormat: String, +) { PNG("image/png", "PNG"), JPEG("image/jpeg", "JPEG"), } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/BookSearchHelper.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/BookSearchHelper.kt index 9b8fa100..83e67cf8 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/BookSearchHelper.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/BookSearchHelper.kt @@ -39,8 +39,8 @@ class BookSearchHelper( return toConditionInternal(SearchCondition.AnyOfBook(libraryIds.map { SearchCondition.LibraryId(SearchOperator.Is(it)) })) } - private fun toConditionInternal(searchCondition: SearchCondition.Book?): Pair> { - return when (searchCondition) { + private fun toConditionInternal(searchCondition: SearchCondition.Book?): Pair> = + when (searchCondition) { is SearchCondition.AllOfBook -> searchCondition.conditions.fold(DSL.noCondition() to emptySet()) { acc: Pair>, cond: SearchCondition.Book -> val bookCondition = toConditionInternal(cond) @@ -60,7 +60,8 @@ class BookSearchHelper( is SearchCondition.ReadListId -> Tables.BOOK.ID.let { field -> val inner = { readListId: String -> - DSL.select(Tables.READLIST_BOOK.BOOK_ID) + DSL + .select(Tables.READLIST_BOOK.BOOK_ID) .from(Tables.READLIST_BOOK) .where(Tables.READLIST_BOOK.READLIST_ID.eq(readListId)) } @@ -138,9 +139,14 @@ class BookSearchHelper( is SearchCondition.Tag -> Tables.BOOK.ID.let { field -> val inner = { tag: String -> - DSL.select(Tables.BOOK_METADATA_TAG.BOOK_ID) + DSL + .select(Tables.BOOK_METADATA_TAG.BOOK_ID) .from(Tables.BOOK_METADATA_TAG) - .where(Tables.BOOK_METADATA_TAG.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3).equalIgnoreCase(tag)) + .where( + Tables.BOOK_METADATA_TAG.TAG + .collate(SqliteUdfDataSource.COLLATION_UNICODE_3) + .equalIgnoreCase(tag), + ) } when (searchCondition.operator) { is SearchOperator.Is -> field.`in`(inner(searchCondition.operator.value)) @@ -151,11 +157,25 @@ class BookSearchHelper( is SearchCondition.Author -> Tables.BOOK.ID.let { field -> val inner = { name: String?, role: String? -> - DSL.select(Tables.BOOK_METADATA_AUTHOR.BOOK_ID) + DSL + .select(Tables.BOOK_METADATA_AUTHOR.BOOK_ID) .from(Tables.BOOK_METADATA_AUTHOR) .where(DSL.noCondition()) - .apply { if (name != null) and(Tables.BOOK_METADATA_AUTHOR.NAME.collate(SqliteUdfDataSource.COLLATION_UNICODE_3).equalIgnoreCase(name)) } - .apply { if (role != null) and(Tables.BOOK_METADATA_AUTHOR.ROLE.collate(SqliteUdfDataSource.COLLATION_UNICODE_3).equalIgnoreCase(role)) } + .apply { + if (name != null) + and( + Tables.BOOK_METADATA_AUTHOR.NAME + .collate(SqliteUdfDataSource.COLLATION_UNICODE_3) + .equalIgnoreCase(name), + ) + }.apply { + if (role != null) + and( + Tables.BOOK_METADATA_AUTHOR.ROLE + .collate(SqliteUdfDataSource.COLLATION_UNICODE_3) + .equalIgnoreCase(role), + ) + } } when (searchCondition.operator) { is SearchOperator.Is -> { @@ -178,5 +198,4 @@ class BookSearchHelper( null -> DSL.noCondition() to emptySet() } - } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ContentRestrictionsSearchHelper.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ContentRestrictionsSearchHelper.kt index 68b41300..fa80c354 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ContentRestrictionsSearchHelper.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ContentRestrictionsSearchHelper.kt @@ -10,7 +10,8 @@ abstract class ContentRestrictionsSearchHelper { protected fun toConditionInternal(restrictions: ContentRestrictions): Pair> { val ageAllowed = if (restrictions.ageRestriction?.restriction == AllowExclude.ALLOW_ONLY) { - Tables.SERIES_METADATA.AGE_RATING.isNotNull.and(Tables.SERIES_METADATA.AGE_RATING.lessOrEqual(restrictions.ageRestriction.age)) to setOf(RequiredJoin.SeriesMetadata) + Tables.SERIES_METADATA.AGE_RATING.isNotNull + .and(Tables.SERIES_METADATA.AGE_RATING.lessOrEqual(restrictions.ageRestriction.age)) to setOf(RequiredJoin.SeriesMetadata) } else { DSL.noCondition() to emptySet() } @@ -18,7 +19,8 @@ abstract class ContentRestrictionsSearchHelper { val labelAllowed = if (restrictions.labelsAllow.isNotEmpty()) Tables.SERIES_METADATA.SERIES_ID.`in`( - DSL.select(Tables.SERIES_METADATA_SHARING.SERIES_ID) + DSL + .select(Tables.SERIES_METADATA_SHARING.SERIES_ID) .from(Tables.SERIES_METADATA_SHARING) .where(Tables.SERIES_METADATA_SHARING.LABEL.`in`(restrictions.labelsAllow)), ) to setOf(RequiredJoin.SeriesMetadata) @@ -27,21 +29,24 @@ abstract class ContentRestrictionsSearchHelper { val ageDenied = if (restrictions.ageRestriction?.restriction == AllowExclude.EXCLUDE) - Tables.SERIES_METADATA.AGE_RATING.isNull.or(Tables.SERIES_METADATA.AGE_RATING.lessThan(restrictions.ageRestriction.age)) to setOf(RequiredJoin.SeriesMetadata) + Tables.SERIES_METADATA.AGE_RATING.isNull + .or(Tables.SERIES_METADATA.AGE_RATING.lessThan(restrictions.ageRestriction.age)) to setOf(RequiredJoin.SeriesMetadata) else DSL.noCondition() to emptySet() val labelDenied = if (restrictions.labelsExclude.isNotEmpty()) Tables.SERIES_METADATA.SERIES_ID.notIn( - DSL.select(Tables.SERIES_METADATA_SHARING.SERIES_ID) + DSL + .select(Tables.SERIES_METADATA_SHARING.SERIES_ID) .from(Tables.SERIES_METADATA_SHARING) .where(Tables.SERIES_METADATA_SHARING.LABEL.`in`(restrictions.labelsExclude)), ) to setOf(RequiredJoin.SeriesMetadata) else DSL.noCondition() to emptySet() - return ageAllowed.first.or(labelAllowed.first) + return ageAllowed.first + .or(labelAllowed.first) .and(ageDenied.first.and(labelDenied.first)) to (ageAllowed.second + labelAllowed.second + ageDenied.second + labelDenied.second) } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/KomgaJooqConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/KomgaJooqConfiguration.kt index 3be2c4ca..a657ffdb 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/KomgaJooqConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/KomgaJooqConfiguration.kt @@ -25,28 +25,25 @@ class KomgaJooqConfiguration { dataSource: DataSource, transactionProvider: ObjectProvider, executeListenerProviders: ObjectProvider, - ): DSLContext = - createDslContext(dataSource, transactionProvider, executeListenerProviders) + ): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders) @Bean("tasksDslContext") fun tasksDslContext( @Qualifier("tasksDataSource") dataSource: DataSource, transactionProvider: ObjectProvider, executeListenerProviders: ObjectProvider, - ): DSLContext = - createDslContext(dataSource, transactionProvider, executeListenerProviders) + ): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders) private fun createDslContext( dataSource: DataSource, transactionProvider: ObjectProvider, executeListenerProviders: ObjectProvider, - ) = - DefaultDSLContext( - DefaultConfiguration().also { configuration -> - configuration.set(SQLDialect.SQLITE) - configuration.set(DataSourceConnectionProvider(TransactionAwareDataSourceProxy(dataSource))) - transactionProvider.ifAvailable { newTransactionProvider: TransactionProvider? -> configuration.set(newTransactionProvider) } - configuration.set(*executeListenerProviders.orderedStream().toList().toTypedArray()) - }, - ) + ) = DefaultDSLContext( + DefaultConfiguration().also { configuration -> + configuration.set(SQLDialect.SQLITE) + configuration.set(DataSourceConnectionProvider(TransactionAwareDataSourceProxy(dataSource))) + transactionProvider.ifAvailable { newTransactionProvider: TransactionProvider? -> configuration.set(newTransactionProvider) } + configuration.set(*executeListenerProviders.orderedStream().toList().toTypedArray()) + }, + ) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/RequiredJoin.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/RequiredJoin.kt index 6a8ac7a0..978e75e3 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/RequiredJoin.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/RequiredJoin.kt @@ -8,7 +8,9 @@ sealed class RequiredJoin { data object Media : RequiredJoin() - data class ReadProgress(val userId: String) : RequiredJoin() + data class ReadProgress( + val userId: String, + ) : RequiredJoin() data object BookMetadataAggregation : RequiredJoin() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SearchOperatorUtils.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SearchOperatorUtils.kt index a059b7e9..77d5eb23 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SearchOperatorUtils.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SearchOperatorUtils.kt @@ -9,11 +9,10 @@ import java.time.temporal.ChronoUnit fun SearchOperator.Equality.toCondition( field: Field, ignoreCase: Boolean = false, -) = - when (this) { - is SearchOperator.Is -> if (ignoreCase) field.equalIgnoreCase(this.value) else field.eq(this.value) - is SearchOperator.IsNot -> if (ignoreCase) field.notEqualIgnoreCase(this.value) else field.ne(this.value) - } +) = when (this) { + is SearchOperator.Is -> if (ignoreCase) field.equalIgnoreCase(this.value) else field.eq(this.value) + is SearchOperator.IsNot -> if (ignoreCase) field.notEqualIgnoreCase(this.value) else field.ne(this.value) +} fun SearchOperator.Equality.toCondition(field: Field) = when (this) { @@ -24,11 +23,10 @@ fun SearchOperator.Equality.toCondition(field: Field) = fun SearchOperator.Equality.toCondition( field: Field, converter: (T) -> String, -) = - when (this) { - is SearchOperator.Is -> field.eq(converter(this.value)) - is SearchOperator.IsNot -> field.ne(converter(this.value)) - } +) = when (this) { + is SearchOperator.Is -> field.eq(converter(this.value)) + is SearchOperator.IsNot -> field.ne(converter(this.value)) +} fun SearchOperator.StringOp.toCondition(field: Field) = when (this) { diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesSearchHelper.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesSearchHelper.kt index 066fde20..0a0c46e4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesSearchHelper.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesSearchHelper.kt @@ -37,8 +37,8 @@ class SeriesSearchHelper( return toConditionInternal(SearchCondition.AnyOfSeries(libraryIds.map { SearchCondition.LibraryId(SearchOperator.Is(it)) })) } - private fun toConditionInternal(searchCondition: SearchCondition.Series?): Pair> { - return when (searchCondition) { + private fun toConditionInternal(searchCondition: SearchCondition.Series?): Pair> = + when (searchCondition) { is SearchCondition.AllOfSeries -> searchCondition.conditions.fold(DSL.noCondition() to emptySet()) { acc: Pair>, cond: SearchCondition.Series -> val seriesCondition = toConditionInternal(cond) @@ -98,13 +98,22 @@ class SeriesSearchHelper( is SearchCondition.Tag -> Tables.SERIES.ID.let { field -> val inner = { tag: String -> - DSL.select(Tables.SERIES_METADATA_TAG.SERIES_ID) + DSL + .select(Tables.SERIES_METADATA_TAG.SERIES_ID) .from(Tables.SERIES_METADATA_TAG) - .where(Tables.SERIES_METADATA_TAG.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3).equalIgnoreCase(tag)) - .union( - DSL.select(Tables.BOOK_METADATA_AGGREGATION_TAG.SERIES_ID) + .where( + Tables.SERIES_METADATA_TAG.TAG + .collate(SqliteUdfDataSource.COLLATION_UNICODE_3) + .equalIgnoreCase(tag), + ).union( + DSL + .select(Tables.BOOK_METADATA_AGGREGATION_TAG.SERIES_ID) .from(Tables.BOOK_METADATA_AGGREGATION_TAG) - .where(Tables.BOOK_METADATA_AGGREGATION_TAG.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3).equalIgnoreCase(tag)), + .where( + Tables.BOOK_METADATA_AGGREGATION_TAG.TAG + .collate(SqliteUdfDataSource.COLLATION_UNICODE_3) + .equalIgnoreCase(tag), + ), ) } when (searchCondition.operator) { @@ -116,23 +125,25 @@ class SeriesSearchHelper( is SearchCondition.Author -> Tables.SERIES.ID.let { field -> val inner = { name: String?, role: String? -> - DSL.select(Tables.BOOK_METADATA_AGGREGATION_AUTHOR.SERIES_ID) + DSL + .select(Tables.BOOK_METADATA_AGGREGATION_AUTHOR.SERIES_ID) .from(Tables.BOOK_METADATA_AGGREGATION_AUTHOR) .where(DSL.noCondition()) .apply { if (name != null) and( - Tables.BOOK_METADATA_AGGREGATION_AUTHOR.NAME.collate( - SqliteUdfDataSource.COLLATION_UNICODE_3, - ).equalIgnoreCase(name), + Tables.BOOK_METADATA_AGGREGATION_AUTHOR.NAME + .collate( + SqliteUdfDataSource.COLLATION_UNICODE_3, + ).equalIgnoreCase(name), ) - } - .apply { + }.apply { if (role != null) and( - Tables.BOOK_METADATA_AGGREGATION_AUTHOR.ROLE.collate( - SqliteUdfDataSource.COLLATION_UNICODE_3, - ).equalIgnoreCase(role), + Tables.BOOK_METADATA_AGGREGATION_AUTHOR.ROLE + .collate( + SqliteUdfDataSource.COLLATION_UNICODE_3, + ).equalIgnoreCase(role), ) } } @@ -160,7 +171,8 @@ class SeriesSearchHelper( is SearchCondition.CollectionId -> Tables.SERIES.ID.let { field -> val inner = { collectionId: String -> - DSL.select(Tables.COLLECTION_SERIES.SERIES_ID) + DSL + .select(Tables.COLLECTION_SERIES.SERIES_ID) .from(Tables.COLLECTION_SERIES) .where(Tables.COLLECTION_SERIES.COLLECTION_ID.eq(collectionId)) } @@ -181,9 +193,14 @@ class SeriesSearchHelper( is SearchCondition.Genre -> Tables.SERIES.ID.let { field -> val inner = { genre: String -> - DSL.select(Tables.SERIES_METADATA_GENRE.SERIES_ID) + DSL + .select(Tables.SERIES_METADATA_GENRE.SERIES_ID) .from(Tables.SERIES_METADATA_GENRE) - .where(Tables.SERIES_METADATA_GENRE.GENRE.collate(SqliteUdfDataSource.COLLATION_UNICODE_3).equalIgnoreCase(genre)) + .where( + Tables.SERIES_METADATA_GENRE.GENRE + .collate(SqliteUdfDataSource.COLLATION_UNICODE_3) + .equalIgnoreCase(genre), + ) } when (searchCondition.operator) { is SearchOperator.Is -> field.`in`(inner(searchCondition.operator.value)) @@ -198,9 +215,14 @@ class SeriesSearchHelper( is SearchCondition.SharingLabel -> Tables.SERIES.ID.let { field -> val inner = { label: String -> - DSL.select(Tables.SERIES_METADATA_SHARING.SERIES_ID) + DSL + .select(Tables.SERIES_METADATA_SHARING.SERIES_ID) .from(Tables.SERIES_METADATA_SHARING) - .where(Tables.SERIES_METADATA_SHARING.LABEL.collate(SqliteUdfDataSource.COLLATION_UNICODE_3).equalIgnoreCase(label)) + .where( + Tables.SERIES_METADATA_SHARING.LABEL + .collate(SqliteUdfDataSource.COLLATION_UNICODE_3) + .equalIgnoreCase(label), + ) } when (searchCondition.operator) { is SearchOperator.Is -> field.`in`(inner(searchCondition.operator.value)) @@ -222,5 +244,4 @@ class SeriesSearchHelper( null -> DSL.noCondition() to emptySet() } - } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/UnpagedSorted.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/UnpagedSorted.kt index bc9cbb15..61efde92 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/UnpagedSorted.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/UnpagedSorted.kt @@ -6,9 +6,7 @@ import org.springframework.data.domain.Sort class UnpagedSorted( private val sort: Sort, ) : Pageable { - override fun getPageNumber(): Int { - throw UnsupportedOperationException() - } + override fun getPageNumber(): Int = throw UnsupportedOperationException() override fun hasPrevious(): Boolean = false @@ -18,13 +16,9 @@ class UnpagedSorted( override fun next(): Pageable = this - override fun getPageSize(): Int { - throw UnsupportedOperationException() - } + override fun getPageSize(): Int = throw UnsupportedOperationException() - override fun getOffset(): Long { - throw UnsupportedOperationException() - } + override fun getOffset(): Long = throw UnsupportedOperationException() override fun first(): Pageable = this diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/Utils.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/Utils.kt index b817b7bd..e8589b66 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/Utils.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/Utils.kt @@ -45,8 +45,7 @@ fun Field.inOrNoCondition(list: Collection?): Condition = else -> this.`in`(list) } -fun Field.udfStripAccents() = - DSL.function(SqliteUdfDataSource.UDF_STRIP_ACCENTS, String::class.java, this) +fun Field.udfStripAccents() = DSL.function(SqliteUdfDataSource.UDF_STRIP_ACCENTS, String::class.java, this) fun DSLContext.insertTempStrings( batchSize: Int, @@ -55,13 +54,14 @@ fun DSLContext.insertTempStrings( this.deleteFrom(Tables.TEMP_STRING_LIST).execute() if (collection.isNotEmpty()) { collection.chunked(batchSize).forEach { chunk -> - this.batch( - this.insertInto(Tables.TEMP_STRING_LIST, Tables.TEMP_STRING_LIST.STRING).values(null as String?), - ).also { step -> - chunk.forEach { - step.bind(it) - } - }.execute() + this + .batch( + this.insertInto(Tables.TEMP_STRING_LIST, Tables.TEMP_STRING_LIST.STRING).values(null as String?), + ).also { step -> + chunk.forEach { + step.bind(it) + } + }.execute() } } } @@ -71,7 +71,8 @@ fun DSLContext.selectTempStrings() = this.select(Tables.TEMP_STRING_LIST.STRING) fun ContentRestrictions.toCondition(): Condition { val ageAllowed = if (ageRestriction?.restriction == AllowExclude.ALLOW_ONLY) { - Tables.SERIES_METADATA.AGE_RATING.isNotNull.and(Tables.SERIES_METADATA.AGE_RATING.lessOrEqual(ageRestriction.age)) + Tables.SERIES_METADATA.AGE_RATING.isNotNull + .and(Tables.SERIES_METADATA.AGE_RATING.lessOrEqual(ageRestriction.age)) } else { DSL.noCondition() } @@ -79,7 +80,8 @@ fun ContentRestrictions.toCondition(): Condition { val labelAllowed = if (labelsAllow.isNotEmpty()) Tables.SERIES_METADATA.SERIES_ID.`in`( - DSL.select(Tables.SERIES_METADATA_SHARING.SERIES_ID) + DSL + .select(Tables.SERIES_METADATA_SHARING.SERIES_ID) .from(Tables.SERIES_METADATA_SHARING) .where(Tables.SERIES_METADATA_SHARING.LABEL.`in`(labelsAllow)), ) @@ -88,21 +90,24 @@ fun ContentRestrictions.toCondition(): Condition { val ageDenied = if (ageRestriction?.restriction == AllowExclude.EXCLUDE) - Tables.SERIES_METADATA.AGE_RATING.isNull.or(Tables.SERIES_METADATA.AGE_RATING.lessThan(ageRestriction.age)) + Tables.SERIES_METADATA.AGE_RATING.isNull + .or(Tables.SERIES_METADATA.AGE_RATING.lessThan(ageRestriction.age)) else DSL.noCondition() val labelDenied = if (labelsExclude.isNotEmpty()) Tables.SERIES_METADATA.SERIES_ID.notIn( - DSL.select(Tables.SERIES_METADATA_SHARING.SERIES_ID) + DSL + .select(Tables.SERIES_METADATA_SHARING.SERIES_ID) .from(Tables.SERIES_METADATA_SHARING) .where(Tables.SERIES_METADATA_SHARING.LABEL.`in`(labelsExclude)), ) else DSL.noCondition() - return ageAllowed.or(labelAllowed) + return ageAllowed + .or(labelAllowed) .and(ageDenied.and(labelDenied)) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/AuthenticationActivityDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/AuthenticationActivityDao.kt index 7d490b2e..815d396f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/AuthenticationActivityDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/AuthenticationActivityDao.kt @@ -52,7 +52,8 @@ class AuthenticationActivityDao( user: KomgaUser, apiKeyId: String?, ): AuthenticationActivity? = - dsl.selectFrom(aa) + dsl + .selectFrom(aa) .where(aa.USER_ID.eq(user.id)) .or(aa.EMAIL.eq(user.email)) .apply { apiKeyId?.let { and(aa.API_KEY_ID.eq(it)) } } @@ -70,7 +71,8 @@ class AuthenticationActivityDao( val orderBy = pageable.sort.toOrderBy(sorts) val items = - dsl.selectFrom(aa) + dsl + .selectFrom(aa) .where(conditions) .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } @@ -89,20 +91,23 @@ class AuthenticationActivityDao( } override fun insert(activity: AuthenticationActivity) { - dsl.insertInto(aa, aa.USER_ID, aa.EMAIL, aa.API_KEY_ID, aa.API_KEY_COMMENT, aa.IP, aa.USER_AGENT, aa.SUCCESS, aa.ERROR, aa.SOURCE) + dsl + .insertInto(aa, aa.USER_ID, aa.EMAIL, aa.API_KEY_ID, aa.API_KEY_COMMENT, aa.IP, aa.USER_AGENT, aa.SUCCESS, aa.ERROR, aa.SOURCE) .values(activity.userId, activity.email, activity.apiKeyId, activity.apiKeyComment, activity.ip, activity.userAgent, activity.success, activity.error, activity.source) .execute() } override fun deleteByUser(user: KomgaUser) { - dsl.deleteFrom(aa) + dsl + .deleteFrom(aa) .where(aa.USER_ID.eq(user.id)) .or(aa.EMAIL.eq(user.email)) .execute() } override fun deleteOlderThan(dateTime: LocalDateTime) { - dsl.deleteFrom(aa) + dsl + .deleteFrom(aa) .where(aa.DATE_TIME.lt(dateTime)) .execute() } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookCommonDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookCommonDao.kt index c291bed6..1ce0d7a7 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookCommonDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookCommonDao.kt @@ -41,8 +41,10 @@ class BookCommonDao( .`as`( select(s.ID, rs.MOST_RECENT_READ_DATE) .from(s) - .innerJoin(rs).on(s.ID.eq(rs.SERIES_ID).and(rs.USER_ID.eq(userId))) - .innerJoin(sd).on(s.ID.eq(sd.SERIES_ID)) + .innerJoin(rs) + .on(s.ID.eq(rs.SERIES_ID).and(rs.USER_ID.eq(userId))) + .innerJoin(sd) + .on(s.ID.eq(sd.SERIES_ID)) .where(rs.IN_PROGRESS_COUNT.eq(0)) .and(rs.READ_COUNT.ne(s.BOOK_COUNT)) .and(restrictions.toCondition()) @@ -60,8 +62,11 @@ class BookCommonDao( cteBooksFieldSeriesId, cteBooksFieldNumberSort, ).from(b) - .innerJoin(d).on(b.ID.eq(d.BOOK_ID)) - .leftJoin(r).on(b.ID.eq(r.BOOK_ID)).and(r.USER_ID.eq(userId)) + .innerJoin(d) + .on(b.ID.eq(d.BOOK_ID)) + .leftJoin(r) + .on(b.ID.eq(r.BOOK_ID)) + .and(r.USER_ID.eq(userId)) .where(r.COMPLETED.isNull) .and( b.SERIES_ID.`in`(select(cteSeries.field(s.ID)).from(cteSeries)), @@ -77,28 +82,40 @@ class BookCommonDao( .with(cteBooks) .select(*selectFields) .from(cteSeries) - .innerJoin(b1).on(cteSeries.field(s.ID)!!.eq(b1.field(cteBooksFieldSeriesId))) + .innerJoin(b1) + .on(cteSeries.field(s.ID)!!.eq(b1.field(cteBooksFieldSeriesId))) // we join the cteBooks table on itself, using the grouping ID (seriesId) using a left outer join // it returns the row b1 for which no other row b2 exists with the same seriesId and a smaller numberSort // when b2 is null, it means the left outer join fond no such match, and therefore b1 has the smaller value of numberSort - .leftOuterJoin(b2).on( - b1.field(cteBooksFieldSeriesId)!!.eq(b2.field(cteBooksFieldSeriesId)) + .leftOuterJoin(b2) + .on( + b1 + .field(cteBooksFieldSeriesId)!! + .eq(b2.field(cteBooksFieldSeriesId)) .and( - b1.field(cteBooksFieldNumberSort)!!.gt(b2.field(cteBooksFieldNumberSort)) + b1 + .field(cteBooksFieldNumberSort)!! + .gt(b2.field(cteBooksFieldNumberSort)) .or( - b1.field(cteBooksFieldNumberSort)!!.eq(b2.field(cteBooksFieldNumberSort)) + b1 + .field(cteBooksFieldNumberSort)!! + .eq(b2.field(cteBooksFieldNumberSort)) .and(b1.field(cteBooksFieldBookId)!!.gt(b2.field(cteBooksFieldBookId))), ), ), - ) - .innerJoin(b).on(b1.field(cteBooksFieldBookId)!!.eq(b.ID)) - .innerJoin(m).on(b.ID.eq(m.BOOK_ID)) - .innerJoin(d).on(b.ID.eq(d.BOOK_ID)) - .innerJoin(sd).on(b.SERIES_ID.eq(sd.SERIES_ID)) + ).innerJoin(b) + .on(b1.field(cteBooksFieldBookId)!!.eq(b.ID)) + .innerJoin(m) + .on(b.ID.eq(m.BOOK_ID)) + .innerJoin(d) + .on(b.ID.eq(d.BOOK_ID)) + .innerJoin(sd) + .on(b.SERIES_ID.eq(sd.SERIES_ID)) // fetchAndMap expects some values for ReadProgress // On Deck books are by definition unread, thus don't have read progress // we join on the table to keep fetchAndMap, with a false condition to only get null values - .leftOuterJoin(r).on(falseCondition()) + .leftOuterJoin(r) + .on(falseCondition()) .where(b2.field(cteBooksFieldBookId)!!.isNull) val mostRecentReadDateQuery = diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDao.kt index f18c0287..ff3fce7c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDao.kt @@ -47,14 +47,14 @@ class BookDao( "number" to b.NUMBER, ) - override fun findByIdOrNull(bookId: String): Book? = - findByIdOrNull(dsl, bookId) + override fun findByIdOrNull(bookId: String): Book? = findByIdOrNull(dsl, bookId) override fun findNotDeletedByLibraryIdAndUrlOrNull( libraryId: String, url: URL, ): Book? = - dsl.selectFrom(b) + dsl + .selectFrom(b) .where(b.LIBRARY_ID.eq(libraryId).and(b.URL.eq(url.toString()))) .and(b.DELETED_DATE.isNull) .orderBy(b.LAST_MODIFIED_DATE.desc()) @@ -66,19 +66,22 @@ class BookDao( dsl: DSLContext, bookId: String, ): Book? = - dsl.selectFrom(b) + dsl + .selectFrom(b) .where(b.ID.eq(bookId)) .fetchOneInto(b) ?.toDomain() override fun findAllBySeriesId(seriesId: String): Collection = - dsl.selectFrom(b) + dsl + .selectFrom(b) .where(b.SERIES_ID.eq(seriesId)) .fetchInto(b) .map { it.toDomain() } override fun findAllBySeriesIds(seriesIds: Collection): Collection = - dsl.selectFrom(b) + dsl + .selectFrom(b) .where(b.SERIES_ID.`in`(seriesIds)) .fetchInto(b) .map { it.toDomain() } @@ -90,7 +93,8 @@ class BookDao( ): Collection { dsl.insertTempStrings(batchSize, urls.map { it.toString() }) - return dsl.selectFrom(b) + return dsl + .selectFrom(b) .where(b.LIBRARY_ID.eq(libraryId)) .and(b.DELETED_DATE.isNull) .and(b.URL.notIn(dsl.selectTempStrings())) @@ -99,13 +103,15 @@ class BookDao( } override fun findAllDeletedByFileSize(fileSize: Long): Collection = - dsl.selectFrom(b) + dsl + .selectFrom(b) .where(b.DELETED_DATE.isNotNull.and(b.FILE_SIZE.eq(fileSize))) .fetchInto(b) .map { it.toDomain() } override fun findAll(): Collection = - dsl.selectFrom(b) + dsl + .selectFrom(b) .fetchInto(b) .map { it.toDomain() } @@ -124,7 +130,8 @@ class BookDao( pageable: Pageable, ): PageImpl { val count = - dsl.selectCount() + dsl + .selectCount() .from(b) .apply { joins.forEach { join -> @@ -137,14 +144,14 @@ class BookDao( RequiredJoin.BookMetadataAggregation -> Unit } } - } - .where(conditions) + }.where(conditions) .fetchOne(0, Long::class.java) ?: 0 val orderBy = pageable.sort.toOrderBy(sorts) val items = - dsl.select(*b.fields()) + dsl + .select(*b.fields()) .from(b) .apply { joins.forEach { join -> @@ -157,8 +164,7 @@ class BookDao( RequiredJoin.BookMetadataAggregation -> Unit } } - } - .where(conditions) + }.where(conditions) .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } .fetchInto(b) @@ -176,30 +182,36 @@ class BookDao( } override fun getLibraryIdOrNull(bookId: String): String? = - dsl.select(b.LIBRARY_ID) + dsl + .select(b.LIBRARY_ID) .from(b) .where(b.ID.eq(bookId)) .fetchOne(b.LIBRARY_ID) override fun getSeriesIdOrNull(bookId: String): String? = - dsl.select(b.SERIES_ID) + dsl + .select(b.SERIES_ID) .from(b) .where(b.ID.eq(bookId)) .fetchOne(b.SERIES_ID) override fun findFirstIdInSeriesOrNull(seriesId: String): String? = - dsl.select(b.ID) + dsl + .select(b.ID) .from(b) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) .where(b.SERIES_ID.eq(seriesId)) .orderBy(d.NUMBER_SORT) .limit(1) .fetchOne(b.ID) override fun findLastIdInSeriesOrNull(seriesId: String): String? = - dsl.select(b.ID) + dsl + .select(b.ID) .from(b) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) .where(b.SERIES_ID.eq(seriesId)) .orderBy(d.NUMBER_SORT.desc()) .limit(1) @@ -209,10 +221,14 @@ class BookDao( seriesId: String, userId: String, ): String? = - dsl.select(b.ID) + dsl + .select(b.ID) .from(b) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) - .leftJoin(r).on(b.ID.eq(r.BOOK_ID)).and(r.USER_ID.eq(userId).or(r.USER_ID.isNull)) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) + .leftJoin(r) + .on(b.ID.eq(r.BOOK_ID)) + .and(r.USER_ID.eq(userId).or(r.USER_ID.isNull)) .where(b.SERIES_ID.eq(seriesId)) .and(r.COMPLETED.isNull.or(r.COMPLETED.isFalse)) .orderBy(d.NUMBER_SORT) @@ -220,27 +236,30 @@ class BookDao( .fetchOne(b.ID) override fun findAllIdsBySeriesId(seriesId: String): Collection = - dsl.select(b.ID) + dsl + .select(b.ID) .from(b) .where(b.SERIES_ID.eq(seriesId)) .fetch(b.ID) override fun findAllIdsByLibraryId(libraryId: String): Collection = - dsl.select(b.ID) + dsl + .select(b.ID) .from(b) .where(b.LIBRARY_ID.eq(libraryId)) .fetch(b.ID) - override fun existsById(bookId: String): Boolean = - dsl.fetchExists(b, b.ID.eq(bookId)) + override fun existsById(bookId: String): Boolean = dsl.fetchExists(b, b.ID.eq(bookId)) override fun findAllByLibraryIdAndMediaTypes( libraryId: String, mediaTypes: Collection, ): Collection = - dsl.select(*b.fields()) + dsl + .select(*b.fields()) .from(b) - .leftJoin(m).on(b.ID.eq(m.BOOK_ID)) + .leftJoin(m) + .on(b.ID.eq(m.BOOK_ID)) .where(b.LIBRARY_ID.eq(libraryId)) .and(m.MEDIA_TYPE.`in`(mediaTypes)) .fetchInto(b) @@ -251,9 +270,11 @@ class BookDao( mediaType: String, extension: String, ): Collection = - dsl.select(*b.fields()) + dsl + .select(*b.fields()) .from(b) - .leftJoin(m).on(b.ID.eq(m.BOOK_ID)) + .leftJoin(m) + .on(b.ID.eq(m.BOOK_ID)) .where(b.LIBRARY_ID.eq(libraryId)) .and(m.MEDIA_TYPE.eq(mediaType)) .and(b.URL.notLike("%.$extension")) @@ -261,7 +282,8 @@ class BookDao( .map { it.toDomain() } override fun findAllByLibraryIdAndWithEmptyHash(libraryId: String): Collection = - dsl.selectFrom(b) + dsl + .selectFrom(b) .where(b.LIBRARY_ID.eq(libraryId)) .and(b.FILE_HASH.eq("")) .fetchInto(b) @@ -276,38 +298,40 @@ class BookDao( override fun insert(books: Collection) { if (books.isNotEmpty()) { books.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto( - b, - b.ID, - b.NAME, - b.URL, - b.NUMBER, - b.FILE_LAST_MODIFIED, - b.FILE_SIZE, - b.FILE_HASH, - b.LIBRARY_ID, - b.SERIES_ID, - b.DELETED_DATE, - b.ONESHOT, - ).values(null as String?, null, null, null, null, null, null, null, null, null, null), - ).also { step -> - chunk.forEach { - step.bind( - it.id, - it.name, - it.url, - it.number, - it.fileLastModified, - it.fileSize, - it.fileHash, - it.libraryId, - it.seriesId, - it.deletedDate, - it.oneshot, - ) - } - }.execute() + dsl + .batch( + dsl + .insertInto( + b, + b.ID, + b.NAME, + b.URL, + b.NUMBER, + b.FILE_LAST_MODIFIED, + b.FILE_SIZE, + b.FILE_HASH, + b.LIBRARY_ID, + b.SERIES_ID, + b.DELETED_DATE, + b.ONESHOT, + ).values(null as String?, null, null, null, null, null, null, null, null, null, null), + ).also { step -> + chunk.forEach { + step.bind( + it.id, + it.name, + it.url, + it.number, + it.fileLastModified, + it.fileSize, + it.fileHash, + it.libraryId, + it.seriesId, + it.deletedDate, + it.oneshot, + ) + } + }.execute() } } } @@ -323,7 +347,8 @@ class BookDao( } private fun updateBook(book: Book) { - dsl.update(b) + dsl + .update(b) .set(b.NAME, book.name) .set(b.URL, book.url.toString()) .set(b.NUMBER, book.number) @@ -357,13 +382,15 @@ class BookDao( override fun count(): Long = dsl.fetchCount(b).toLong() override fun countGroupedByLibraryId(): Map = - dsl.select(b.LIBRARY_ID, DSL.count(b.ID)) + dsl + .select(b.LIBRARY_ID, DSL.count(b.ID)) .from(b) .groupBy(b.LIBRARY_ID) .fetchMap(b.LIBRARY_ID, DSL.count(b.ID)) override fun getFilesizeGroupedByLibraryId(): Map = - dsl.select(b.LIBRARY_ID, DSL.sum(b.FILE_SIZE)) + dsl + .select(b.LIBRARY_ID, DSL.sum(b.FILE_SIZE)) .from(b) .groupBy(b.LIBRARY_ID) .fetchMap(b.LIBRARY_ID, DSL.sum(b.FILE_SIZE)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt index a5453a39..b2e74235 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt @@ -90,8 +90,7 @@ class BookDtoDao( "readList.number" to rlb.NUMBER, ) - override fun findAll(pageable: Pageable): Page = - findAll(BookSearch(), SearchContext.ofAnonymousUser(), pageable) + override fun findAll(pageable: Pageable): Page = findAll(BookSearch(), SearchContext.ofAnonymousUser(), pageable) override fun findAll( context: SearchContext, @@ -141,12 +140,18 @@ class BookDtoDao( val count = dsl.fetchCount( - dsl.select(b.ID) + dsl + .select(b.ID) .from(b) - .leftJoin(m).on(b.ID.eq(m.BOOK_ID)) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) - .leftJoin(r).on(b.ID.eq(r.BOOK_ID)).and(readProgressCondition(userId)) - .leftJoin(sd).on(b.SERIES_ID.eq(sd.SERIES_ID)) + .leftJoin(m) + .on(b.ID.eq(m.BOOK_ID)) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) + .leftJoin(r) + .on(b.ID.eq(r.BOOK_ID)) + .and(readProgressCondition(userId)) + .leftJoin(sd) + .on(b.SERIES_ID.eq(sd.SERIES_ID)) .apply { joins.forEach { join -> when (join) { @@ -159,8 +164,7 @@ class BookDtoDao( RequiredJoin.SeriesMetadata -> Unit } } - } - .where(conditions) + }.where(conditions) .and(searchCondition) .groupBy(b.ID), ) @@ -199,14 +203,12 @@ class BookDtoDao( override fun findPreviousInSeriesOrNull( bookId: String, userId: String, - ): BookDto? = - findSiblingSeries(bookId, userId, next = false) + ): BookDto? = findSiblingSeries(bookId, userId, next = false) override fun findNextInSeriesOrNull( bookId: String, userId: String, - ): BookDto? = - findSiblingSeries(bookId, userId, next = true) + ): BookDto? = findSiblingSeries(bookId, userId, next = true) override fun findPreviousInReadListOrNull( readList: ReadList, @@ -214,8 +216,7 @@ class BookDtoDao( userId: String, filterOnLibraryIds: Collection?, restrictions: ContentRestrictions, - ): BookDto? = - findSiblingReadList(readList, bookId, userId, filterOnLibraryIds, restrictions, next = false) + ): BookDto? = findSiblingReadList(readList, bookId, userId, filterOnLibraryIds, restrictions, next = false) override fun findNextInReadListOrNull( readList: ReadList, @@ -223,8 +224,7 @@ class BookDtoDao( userId: String, filterOnLibraryIds: Collection?, restrictions: ContentRestrictions, - ): BookDto? = - findSiblingReadList(readList, bookId, userId, filterOnLibraryIds, restrictions, next = true) + ): BookDto? = findSiblingReadList(readList, bookId, userId, filterOnLibraryIds, restrictions, next = true) override fun findAllOnDeck( userId: String, @@ -256,7 +256,8 @@ class BookDtoDao( pageable: Pageable, ): Page { val hashes = - dsl.select(b.FILE_HASH, DSL.count(b.ID)) + dsl + .select(b.FILE_HASH, DSL.count(b.ID)) .from(b) .where(b.FILE_HASH.ne("")) .groupBy(b.FILE_HASH, b.FILE_SIZE) @@ -293,9 +294,11 @@ class BookDtoDao( next: Boolean, ): BookDto? { val record = - dsl.select(b.SERIES_ID, d.NUMBER_SORT) + dsl + .select(b.SERIES_ID, d.NUMBER_SORT) .from(b) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) .where(b.ID.eq(bookId)) .fetchOne()!! val seriesId = record.get(0, String::class.java) @@ -320,9 +323,11 @@ class BookDtoDao( ): BookDto? { if (readList.ordered) { val numberSort = - dsl.select(rlb.NUMBER) + dsl + .select(rlb.NUMBER) .from(b) - .leftJoin(rlb).on(b.ID.eq(rlb.BOOK_ID)) + .leftJoin(rlb) + .on(b.ID.eq(rlb.BOOK_ID)) .where(b.ID.eq(bookId)) .and(rlb.READLIST_ID.eq(readList.id)) .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } @@ -341,10 +346,13 @@ class BookDtoDao( // it is too complex to perform a seek by release date as it could be null and could also have multiple occurrences of the same value // instead we pull the whole list of ids, and perform the seek on the list val bookIds = - dsl.select(b.ID) + dsl + .select(b.ID) .from(b) - .leftJoin(rlb).on(b.ID.eq(rlb.BOOK_ID)) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) + .leftJoin(rlb) + .on(b.ID.eq(rlb.BOOK_ID)) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) .apply { if (restrictions.isRestricted) leftJoin(sd).on(sd.SERIES_ID.eq(b.SERIES_ID)) } .where(rlb.READLIST_ID.eq(readList.id)) .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } @@ -382,10 +390,15 @@ class BookDtoDao( return dsl .let { if (joinOnReadList) it.selectDistinct(selectFields) else it.select(selectFields) } .from(b) - .leftJoin(m).on(b.ID.eq(m.BOOK_ID)) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) - .leftJoin(r).on(b.ID.eq(r.BOOK_ID)).and(readProgressCondition(userId)) - .leftJoin(sd).on(b.SERIES_ID.eq(sd.SERIES_ID)) + .leftJoin(m) + .on(b.ID.eq(m.BOOK_ID)) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) + .leftJoin(r) + .on(b.ID.eq(r.BOOK_ID)) + .and(readProgressCondition(userId)) + .leftJoin(sd) + .on(b.SERIES_ID.eq(sd.SERIES_ID)) .apply { if (joinOnReadList) leftJoin(rlb).on(b.ID.eq(rlb.BOOK_ID)) joins.forEach { join -> @@ -412,18 +425,21 @@ class BookDtoDao( transactionTemplate.executeWithoutResult { dsl.insertTempStrings(batchSize, bookIds) authors = - dsl.selectFrom(a) + dsl + .selectFrom(a) .where(a.BOOK_ID.`in`(dsl.selectTempStrings())) .filter { it.name != null } .groupBy({ it.bookId }, { AuthorDto(it.name, it.role) }) tags = - dsl.selectFrom(bt) + dsl + .selectFrom(bt) .where(bt.BOOK_ID.`in`(dsl.selectTempStrings())) .groupBy({ it.bookId }, { it.tag }) links = - dsl.selectFrom(bl) + dsl + .selectFrom(bl) .where(bl.BOOK_ID.`in`(dsl.selectTempStrings())) .groupBy({ it.bookId }, { WebLinkDto(it.label, it.url) }) } @@ -445,26 +461,25 @@ class BookDtoDao( metadata: BookMetadataDto, readProgress: ReadProgressDto?, seriesTitle: String, - ) = - BookDto( - id = id, - seriesId = seriesId, - seriesTitle = seriesTitle, - libraryId = libraryId, - name = name, - url = URL(url).toFilePath(), - number = number, - created = createdDate, - lastModified = lastModifiedDate, - fileLastModified = fileLastModified.toUTC(), - sizeBytes = fileSize, - media = media, - metadata = metadata, - readProgress = readProgress, - deleted = deletedDate != null, - fileHash = fileHash, - oneshot = oneshot, - ) + ) = BookDto( + id = id, + seriesId = seriesId, + seriesTitle = seriesTitle, + libraryId = libraryId, + name = name, + url = URL(url).toFilePath(), + number = number, + created = createdDate, + lastModified = lastModifiedDate, + fileLastModified = fileLastModified.toUTC(), + sizeBytes = fileSize, + media = media, + metadata = metadata, + readProgress = readProgress, + deleted = deletedDate != null, + fileHash = fileHash, + oneshot = oneshot, + ) private fun MediaRecord.toDto() = MediaDto( @@ -480,29 +495,28 @@ class BookDtoDao( authors: List, tags: Set, links: List, - ) = - BookMetadataDto( - title = title, - titleLock = titleLock, - summary = summary, - summaryLock = summaryLock, - number = number, - numberLock = numberLock, - numberSort = numberSort, - numberSortLock = numberSortLock, - releaseDate = releaseDate, - releaseDateLock = releaseDateLock, - authors = authors, - authorsLock = authorsLock, - tags = tags, - tagsLock = tagsLock, - isbn = isbn, - isbnLock = isbnLock, - links = links, - linksLock = linksLock, - created = createdDate, - lastModified = lastModifiedDate, - ) + ) = BookMetadataDto( + title = title, + titleLock = titleLock, + summary = summary, + summaryLock = summaryLock, + number = number, + numberLock = numberLock, + numberSort = numberSort, + numberSortLock = numberSortLock, + releaseDate = releaseDate, + releaseDateLock = releaseDateLock, + authors = authors, + authorsLock = authorsLock, + tags = tags, + tagsLock = tagsLock, + isbn = isbn, + isbnLock = isbnLock, + links = links, + linksLock = linksLock, + created = createdDate, + lastModified = lastModifiedDate, + ) private fun ReadProgressRecord.toDto() = ReadProgressDto( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataAggregationDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataAggregationDao.kt index 682b9c9c..4cf08236 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataAggregationDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataAggregationDao.kt @@ -25,16 +25,16 @@ class BookMetadataAggregationDao( private val a = Tables.BOOK_METADATA_AGGREGATION_AUTHOR private val t = Tables.BOOK_METADATA_AGGREGATION_TAG - override fun findById(seriesId: String): BookMetadataAggregation = - findOne(listOf(seriesId)).first() + override fun findById(seriesId: String): BookMetadataAggregation = findOne(listOf(seriesId)).first() - override fun findByIdOrNull(seriesId: String): BookMetadataAggregation? = - findOne(listOf(seriesId)).firstOrNull() + override fun findByIdOrNull(seriesId: String): BookMetadataAggregation? = findOne(listOf(seriesId)).firstOrNull() private fun findOne(seriesIds: Collection) = - dsl.select(*d.fields(), *a.fields()) + dsl + .select(*d.fields(), *a.fields()) .from(d) - .leftJoin(a).on(d.SERIES_ID.eq(a.SERIES_ID)) + .leftJoin(a) + .on(d.SERIES_ID.eq(a.SERIES_ID)) .where(d.SERIES_ID.`in`(seriesIds)) .fetchGroups( { it.into(d) }, @@ -44,14 +44,16 @@ class BookMetadataAggregationDao( } private fun findTags(seriesId: String) = - dsl.select(t.TAG) + dsl + .select(t.TAG) .from(t) .where(t.SERIES_ID.eq(seriesId)) .fetchSet(t.TAG) @Transactional override fun insert(metadata: BookMetadataAggregation) { - dsl.insertInto(d) + dsl + .insertInto(d) .set(d.SERIES_ID, metadata.seriesId) .set(d.RELEASE_DATE, metadata.releaseDate) .set(d.SUMMARY, metadata.summary) @@ -64,7 +66,8 @@ class BookMetadataAggregationDao( @Transactional override fun update(metadata: BookMetadataAggregation) { - dsl.update(d) + dsl + .update(d) .set(d.SUMMARY, metadata.summary) .set(d.SUMMARY_NUMBER, metadata.summaryNumber) .set(d.RELEASE_DATE, metadata.releaseDate) @@ -72,11 +75,13 @@ class BookMetadataAggregationDao( .where(d.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl.deleteFrom(a) + dsl + .deleteFrom(a) .where(a.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl.deleteFrom(t) + dsl + .deleteFrom(t) .where(t.SERIES_ID.eq(metadata.seriesId)) .execute() @@ -87,14 +92,16 @@ class BookMetadataAggregationDao( private fun insertAuthors(metadata: BookMetadataAggregation) { if (metadata.authors.isNotEmpty()) { metadata.authors.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(a, a.SERIES_ID, a.NAME, a.ROLE) - .values(null as String?, null, null), - ).also { step -> - chunk.forEach { - step.bind(metadata.seriesId, it.name, it.role) - } - }.execute() + dsl + .batch( + dsl + .insertInto(a, a.SERIES_ID, a.NAME, a.ROLE) + .values(null as String?, null, null), + ).also { step -> + chunk.forEach { + step.bind(metadata.seriesId, it.name, it.role) + } + }.execute() } } } @@ -102,14 +109,16 @@ class BookMetadataAggregationDao( private fun insertTags(metadata: BookMetadataAggregation) { if (metadata.tags.isNotEmpty()) { metadata.tags.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(t, t.SERIES_ID, t.TAG) - .values(null as String?, null), - ).also { step -> - chunk.forEach { - step.bind(metadata.seriesId, it) - } - }.execute() + dsl + .batch( + dsl + .insertInto(t, t.SERIES_ID, t.TAG) + .values(null as String?, null), + ).also { step -> + chunk.forEach { + step.bind(metadata.seriesId, it) + } + }.execute() } } } @@ -135,17 +144,16 @@ class BookMetadataAggregationDao( private fun BookMetadataAggregationRecord.toDomain( authors: List, tags: Set, - ) = - BookMetadataAggregation( - authors = authors, - tags = tags, - releaseDate = releaseDate, - summary = summary, - summaryNumber = summaryNumber, - seriesId = seriesId, - createdDate = createdDate.toCurrentTimeZone(), - lastModifiedDate = lastModifiedDate.toCurrentTimeZone(), - ) + ) = BookMetadataAggregation( + authors = authors, + tags = tags, + releaseDate = releaseDate, + summary = summary, + summaryNumber = summaryNumber, + seriesId = seriesId, + createdDate = createdDate.toCurrentTimeZone(), + lastModifiedDate = lastModifiedDate.toCurrentTimeZone(), + ) private fun BookMetadataAggregationAuthorRecord.toDomain() = Author( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataDao.kt index 4012d63e..08f983c3 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataDao.kt @@ -30,39 +30,39 @@ class BookMetadataDao( private val groupFields = arrayOf(*d.fields(), *a.fields()) - override fun findById(bookId: String): BookMetadata = - find(dsl, listOf(bookId)).first() + override fun findById(bookId: String): BookMetadata = find(dsl, listOf(bookId)).first() - override fun findByIdOrNull(bookId: String): BookMetadata? = - find(dsl, listOf(bookId)).firstOrNull() + override fun findByIdOrNull(bookId: String): BookMetadata? = find(dsl, listOf(bookId)).firstOrNull() - override fun findAllByIds(bookIds: Collection): Collection = - find(dsl, bookIds) + override fun findAllByIds(bookIds: Collection): Collection = find(dsl, bookIds) private fun find( dsl: DSLContext, bookIds: Collection, - ) = - dsl.select(*groupFields) - .from(d) - .leftJoin(a).on(d.BOOK_ID.eq(a.BOOK_ID)) - .where(d.BOOK_ID.`in`(bookIds)) - .groupBy(*groupFields) - .fetchGroups( - { it.into(d) }, - { it.into(a) }, - ).map { (dr, ar) -> - dr.toDomain(ar.filterNot { it.name == null }.map { it.toDomain() }, findTags(dr.bookId), findLinks(dr.bookId)) - } + ) = dsl + .select(*groupFields) + .from(d) + .leftJoin(a) + .on(d.BOOK_ID.eq(a.BOOK_ID)) + .where(d.BOOK_ID.`in`(bookIds)) + .groupBy(*groupFields) + .fetchGroups( + { it.into(d) }, + { it.into(a) }, + ).map { (dr, ar) -> + dr.toDomain(ar.filterNot { it.name == null }.map { it.toDomain() }, findTags(dr.bookId), findLinks(dr.bookId)) + } private fun findTags(bookId: String) = - dsl.select(bt.TAG) + dsl + .select(bt.TAG) .from(bt) .where(bt.BOOK_ID.eq(bookId)) .fetchSet(bt.TAG) private fun findLinks(bookId: String) = - dsl.select(bl.LABEL, bl.URL) + dsl + .select(bl.LABEL, bl.URL) .from(bl) .where(bl.BOOK_ID.eq(bookId)) .fetchInto(bl) @@ -77,48 +77,50 @@ class BookMetadataDao( override fun insert(metadatas: Collection) { if (metadatas.isNotEmpty()) { metadatas.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto( - d, - d.BOOK_ID, - d.TITLE, - d.TITLE_LOCK, - d.SUMMARY, - d.SUMMARY_LOCK, - d.NUMBER, - d.NUMBER_LOCK, - d.NUMBER_SORT, - d.NUMBER_SORT_LOCK, - d.RELEASE_DATE, - d.RELEASE_DATE_LOCK, - d.AUTHORS_LOCK, - d.TAGS_LOCK, - d.ISBN, - d.ISBN_LOCK, - d.LINKS_LOCK, - ).values(null as String?, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null), - ).also { step -> - chunk.forEach { - step.bind( - it.bookId, - it.title, - it.titleLock, - it.summary, - it.summaryLock, - it.number, - it.numberLock, - it.numberSort, - it.numberSortLock, - it.releaseDate, - it.releaseDateLock, - it.authorsLock, - it.tagsLock, - it.isbn, - it.isbnLock, - it.linksLock, - ) - } - }.execute() + dsl + .batch( + dsl + .insertInto( + d, + d.BOOK_ID, + d.TITLE, + d.TITLE_LOCK, + d.SUMMARY, + d.SUMMARY_LOCK, + d.NUMBER, + d.NUMBER_LOCK, + d.NUMBER_SORT, + d.NUMBER_SORT_LOCK, + d.RELEASE_DATE, + d.RELEASE_DATE_LOCK, + d.AUTHORS_LOCK, + d.TAGS_LOCK, + d.ISBN, + d.ISBN_LOCK, + d.LINKS_LOCK, + ).values(null as String?, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null), + ).also { step -> + chunk.forEach { + step.bind( + it.bookId, + it.title, + it.titleLock, + it.summary, + it.summaryLock, + it.number, + it.numberLock, + it.numberSort, + it.numberSortLock, + it.releaseDate, + it.releaseDateLock, + it.authorsLock, + it.tagsLock, + it.isbn, + it.isbnLock, + it.linksLock, + ) + } + }.execute() } insertAuthors(metadatas) @@ -138,7 +140,8 @@ class BookMetadataDao( } private fun updateMetadata(metadata: BookMetadata) { - dsl.update(d) + dsl + .update(d) .set(d.TITLE, metadata.title) .set(d.TITLE_LOCK, metadata.titleLock) .set(d.SUMMARY, metadata.summary) @@ -158,13 +161,16 @@ class BookMetadataDao( .where(d.BOOK_ID.eq(metadata.bookId)) .execute() - dsl.deleteFrom(a) + dsl + .deleteFrom(a) .where(a.BOOK_ID.eq(metadata.bookId)) .execute() - dsl.deleteFrom(bt) + dsl + .deleteFrom(bt) .where(bt.BOOK_ID.eq(metadata.bookId)) .execute() - dsl.deleteFrom(bl) + dsl + .deleteFrom(bl) .where(bl.BOOK_ID.eq(metadata.bookId)) .execute() @@ -176,16 +182,18 @@ class BookMetadataDao( private fun insertAuthors(metadatas: Collection) { if (metadatas.any { it.authors.isNotEmpty() }) { metadatas.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(a, a.BOOK_ID, a.NAME, a.ROLE) - .values(null as String?, null, null), - ).also { step -> - chunk.forEach { metadata -> - metadata.authors.forEach { - step.bind(metadata.bookId, it.name, it.role) + dsl + .batch( + dsl + .insertInto(a, a.BOOK_ID, a.NAME, a.ROLE) + .values(null as String?, null, null), + ).also { step -> + chunk.forEach { metadata -> + metadata.authors.forEach { + step.bind(metadata.bookId, it.name, it.role) + } } - } - }.execute() + }.execute() } } } @@ -193,16 +201,18 @@ class BookMetadataDao( private fun insertTags(metadatas: Collection) { if (metadatas.any { it.tags.isNotEmpty() }) { metadatas.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(bt, bt.BOOK_ID, bt.TAG) - .values(null as String?, null), - ).also { step -> - chunk.forEach { metadata -> - metadata.tags.forEach { - step.bind(metadata.bookId, it) + dsl + .batch( + dsl + .insertInto(bt, bt.BOOK_ID, bt.TAG) + .values(null as String?, null), + ).also { step -> + chunk.forEach { metadata -> + metadata.tags.forEach { + step.bind(metadata.bookId, it) + } } - } - }.execute() + }.execute() } } } @@ -210,16 +220,18 @@ class BookMetadataDao( private fun insertLinks(metadatas: Collection) { if (metadatas.any { it.links.isNotEmpty() }) { metadatas.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(bl, bl.BOOK_ID, bl.LABEL, bl.URL) - .values(null as String?, null, null), - ).also { step -> - chunk.forEach { metadata -> - metadata.links.forEach { - step.bind(metadata.bookId, it.label, it.url.toString()) + dsl + .batch( + dsl + .insertInto(bl, bl.BOOK_ID, bl.LABEL, bl.URL) + .values(null as String?, null, null), + ).also { step -> + chunk.forEach { metadata -> + metadata.links.forEach { + step.bind(metadata.bookId, it.label, it.url.toString()) + } } - } - }.execute() + }.execute() } } } @@ -248,30 +260,29 @@ class BookMetadataDao( authors: List, tags: Set, links: List, - ) = - BookMetadata( - title = title, - summary = summary, - number = number, - numberSort = numberSort, - releaseDate = releaseDate, - authors = authors, - tags = tags, - isbn = isbn, - links = links, - bookId = bookId, - createdDate = createdDate.toCurrentTimeZone(), - lastModifiedDate = lastModifiedDate.toCurrentTimeZone(), - titleLock = titleLock, - summaryLock = summaryLock, - numberLock = numberLock, - numberSortLock = numberSortLock, - releaseDateLock = releaseDateLock, - authorsLock = authorsLock, - tagsLock = tagsLock, - isbnLock = isbnLock, - linksLock = linksLock, - ) + ) = BookMetadata( + title = title, + summary = summary, + number = number, + numberSort = numberSort, + releaseDate = releaseDate, + authors = authors, + tags = tags, + isbn = isbn, + links = links, + bookId = bookId, + createdDate = createdDate.toCurrentTimeZone(), + lastModifiedDate = lastModifiedDate.toCurrentTimeZone(), + titleLock = titleLock, + summaryLock = summaryLock, + numberLock = numberLock, + numberSortLock = numberSortLock, + releaseDateLock = releaseDateLock, + authorsLock = authorsLock, + tagsLock = tagsLock, + isbnLock = isbnLock, + linksLock = linksLock, + ) private fun BookMetadataAuthorRecord.toDomain() = Author( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDao.kt index 8177b431..c8b4d82e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDao.kt @@ -16,7 +16,8 @@ class HistoricalEventDao( @Transactional override fun insert(event: HistoricalEvent) { - dsl.insertInto(e) + dsl + .insertInto(e) .set(e.ID, event.id) .set(e.TYPE, event.type) .set(e.BOOK_ID, event.bookId) @@ -25,14 +26,16 @@ class HistoricalEventDao( .execute() if (event.properties.isNotEmpty()) { - dsl.batch( - dsl.insertInto(ep, ep.ID, ep.KEY, ep.VALUE) - .values(null as String?, null, null), - ).also { step -> - event.properties.forEach { (key, value) -> - step.bind(event.id, key, value) - } - }.execute() + dsl + .batch( + dsl + .insertInto(ep, ep.ID, ep.KEY, ep.VALUE) + .values(null as String?, null, null), + ).also { step -> + event.properties.forEach { (key, value) -> + step.bind(event.id, key, value) + } + }.execute() } } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDtoDao.kt index af6601d5..e2c468f3 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDtoDao.kt @@ -33,7 +33,8 @@ class HistoricalEventDtoDao( val orderBy = pageable.sort.toOrderBy(sorts) val items = - dsl.selectFrom(e) + dsl + .selectFrom(e) .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } .map { er -> diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt index e031f87c..00299da9 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt @@ -29,30 +29,36 @@ class KoboDtoDao( bookIds: Collection, ): Collection { val records = - dsl.select( - d.BOOK_ID, - d.TITLE, - d.NUMBER, - d.NUMBER_SORT, - d.ISBN, - d.SUMMARY, - d.RELEASE_DATE, - d.CREATED_DATE, - sd.SERIES_ID, - sd.TITLE, - sd.PUBLISHER, - sd.LANGUAGE, - b.FILE_SIZE, - b.ONESHOT, - m.EPUB_IS_KEPUB, - m.EXTENSION_CLASS, - m.EXTENSION_VALUE_BLOB, - bt.ID, - ).from(b) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) - .leftJoin(sd).on(b.SERIES_ID.eq(sd.SERIES_ID)) - .leftJoin(m).on(b.ID.eq(m.BOOK_ID)) - .leftJoin(bt).on(b.ID.eq(bt.BOOK_ID)).and(bt.SELECTED.isTrue) + dsl + .select( + d.BOOK_ID, + d.TITLE, + d.NUMBER, + d.NUMBER_SORT, + d.ISBN, + d.SUMMARY, + d.RELEASE_DATE, + d.CREATED_DATE, + sd.SERIES_ID, + sd.TITLE, + sd.PUBLISHER, + sd.LANGUAGE, + b.FILE_SIZE, + b.ONESHOT, + m.EPUB_IS_KEPUB, + m.EXTENSION_CLASS, + m.EXTENSION_VALUE_BLOB, + bt.ID, + ).from(b) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) + .leftJoin(sd) + .on(b.SERIES_ID.eq(sd.SERIES_ID)) + .leftJoin(m) + .on(b.ID.eq(m.BOOK_ID)) + .leftJoin(bt) + .on(b.ID.eq(bt.BOOK_ID)) + .and(bt.SELECTED.isTrue) .where(d.BOOK_ID.`in`(bookIds)) .fetch() @@ -65,7 +71,8 @@ class KoboDtoDao( val mediaExtension = mapper.deserializeMediaExtension(mr.extensionClass, mr.extensionValueBlob) as? MediaExtensionEpub val authors = - dsl.selectFrom(a) + dsl + .selectFrom(a) .where(a.BOOK_ID.`in`(bookIds)) .filter { it.name != null } .groupBy({ it.bookId }, { it }) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt index aa7fd986..8a33936b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt @@ -35,7 +35,8 @@ class KomgaUserDao( .fetchAndMap() override fun findApiKeyByUserId(userId: String): Collection = - dsl.selectFrom(uak) + dsl + .selectFrom(uak) .where(uak.USER_ID.eq(userId)) .fetchInto(uak) .map { @@ -53,13 +54,16 @@ class KomgaUserDao( .select(*u.fields()) .select(ul.LIBRARY_ID) .from(u) - .leftJoin(ul).onKey() + .leftJoin(ul) + .onKey() private fun ResultQuery.fetchAndMap() = - this.fetchGroups({ it.into(u) }, { it.into(ul) }) + this + .fetchGroups({ it.into(u) }, { it.into(ul) }) .map { (ur, ulr) -> val usr = - dsl.selectFrom(us) + dsl + .selectFrom(us) .where(us.USER_ID.eq(ur.id)) .toList() KomgaUser( @@ -89,7 +93,8 @@ class KomgaUserDao( @Transactional override fun insert(user: KomgaUser) { - dsl.insertInto(u) + dsl + .insertInto(u) .set(u.ID, user.id) .set(u.EMAIL, user.email) .set(u.PASSWORD, user.password) @@ -106,15 +111,15 @@ class KomgaUserDao( AllowExclude.EXCLUDE -> false null -> null }, - ) - .execute() + ).execute() insertSharedLibraries(user) insertSharingRestrictions(user) } override fun insert(apiKey: ApiKey) { - dsl.insertInto(uak) + dsl + .insertInto(uak) .set(uak.ID, apiKey.id) .set(uak.USER_ID, apiKey.userId) .set(uak.API_KEY, apiKey.key) @@ -124,7 +129,8 @@ class KomgaUserDao( @Transactional override fun update(user: KomgaUser) { - dsl.update(u) + dsl + .update(u) .set(u.EMAIL, user.email) .set(u.PASSWORD, user.password) .set(u.ROLE_ADMIN, user.roleAdmin) @@ -140,16 +146,17 @@ class KomgaUserDao( AllowExclude.EXCLUDE -> false null -> null }, - ) - .set(u.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z"))) + ).set(u.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z"))) .where(u.ID.eq(user.id)) .execute() - dsl.deleteFrom(ul) + dsl + .deleteFrom(ul) .where(ul.USER_ID.eq(user.id)) .execute() - dsl.deleteFrom(us) + dsl + .deleteFrom(us) .where(us.USER_ID.eq(user.id)) .execute() @@ -166,7 +173,8 @@ class KomgaUserDao( private fun insertSharedLibraries(user: KomgaUser) { user.sharedLibrariesIds.forEach { - dsl.insertInto(ul) + dsl + .insertInto(ul) .columns(ul.USER_ID, ul.LIBRARY_ID) .values(user.id, it) .execute() @@ -175,14 +183,16 @@ class KomgaUserDao( private fun insertSharingRestrictions(user: KomgaUser) { user.restrictions.labelsAllow.forEach { label -> - dsl.insertInto(us) + dsl + .insertInto(us) .columns(us.USER_ID, us.ALLOW, us.LABEL) .values(user.id, true, label) .execute() } user.restrictions.labelsExclude.forEach { label -> - dsl.insertInto(us) + dsl + .insertInto(us) .columns(us.USER_ID, us.ALLOW, us.LABEL) .values(user.id, false, label) .execute() @@ -211,7 +221,8 @@ class KomgaUserDao( apiKeyId: String, userId: String, ) { - dsl.deleteFrom(uak) + dsl + .deleteFrom(uak) .where(uak.ID.eq(apiKeyId)) .and(uak.USER_ID.eq(userId)) .execute() @@ -222,28 +233,28 @@ class KomgaUserDao( } override fun findAnnouncementIdsReadByUserId(userId: String): Set = - dsl.select(ar.ANNOUNCEMENT_ID) + dsl + .select(ar.ANNOUNCEMENT_ID) .from(ar) .where(ar.USER_ID.eq(userId)) .fetchSet(ar.ANNOUNCEMENT_ID) override fun existsByEmailIgnoreCase(email: String): Boolean = dsl.fetchExists( - dsl.selectFrom(u) + dsl + .selectFrom(u) .where(u.EMAIL.equalIgnoreCase(email)), ) override fun existsApiKeyByIdAndUserId( apiKeyId: String, userId: String, - ): Boolean = - dsl.fetchExists(uak, uak.ID.eq(apiKeyId).and(uak.USER_ID.eq(userId))) + ): Boolean = dsl.fetchExists(uak, uak.ID.eq(apiKeyId).and(uak.USER_ID.eq(userId))) override fun existsApiKeyByCommentAndUserId( comment: String, userId: String, - ): Boolean = - dsl.fetchExists(uak, uak.COMMENT.equalIgnoreCase(comment).and(uak.USER_ID.eq(userId))) + ): Boolean = dsl.fetchExists(uak, uak.COMMENT.equalIgnoreCase(comment).and(uak.USER_ID.eq(userId))) override fun findByEmailIgnoreCaseOrNull(email: String): KomgaUser? = selectBase() @@ -254,13 +265,15 @@ class KomgaUserDao( override fun findByApiKeyOrNull(apiKey: String): Pair? { val user = selectBase() - .leftJoin(uak).on(u.ID.eq(uak.USER_ID)) + .leftJoin(uak) + .on(u.ID.eq(uak.USER_ID)) .where(uak.API_KEY.eq(apiKey)) .fetchAndMap() .firstOrNull() ?: return null val key = - dsl.selectFrom(uak) + dsl + .selectFrom(uak) .where(uak.API_KEY.eq(apiKey)) .fetchInto(uak) .map { it.toDomain() } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/LibraryDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/LibraryDao.kt index 464d7270..98552c18 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/LibraryDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/LibraryDao.kt @@ -46,12 +46,15 @@ class LibraryDao( .fetchAndMap() private fun selectBase() = - dsl.select() + dsl + .select() .from(l) - .leftJoin(le).onKey() + .leftJoin(le) + .onKey() private fun ResultQuery.fetchAndMap(): Collection = - this.fetchGroups({ it.into(l) }, { it.into(le) }) + this + .fetchGroups({ it.into(l) }, { it.into(le) }) .map { (lr, ler) -> lr.toDomain(ler.mapNotNull { it.exclusion }.toSet()) } @@ -72,7 +75,8 @@ class LibraryDao( @Transactional override fun insert(library: Library) { - dsl.insertInto(l) + dsl + .insertInto(l) .set(l.ID, library.id) .set(l.NAME, library.name) .set(l.ROOT, library.root.toString()) @@ -108,7 +112,8 @@ class LibraryDao( @Transactional override fun update(library: Library) { - dsl.update(l) + dsl + .update(l) .set(l.NAME, library.name) .set(l.ROOT, library.root.toString()) .set(l.IMPORT_COMICINFO_BOOK, library.importComicInfoBook) @@ -147,21 +152,24 @@ class LibraryDao( override fun count(): Long = dsl.fetchCount(l).toLong() fun findDirectoryExclusions(libraryId: String): Set = - dsl.select(le.EXCLUSION) + dsl + .select(le.EXCLUSION) .from(le) .where(le.LIBRARY_ID.eq(libraryId)) .fetchSet(le.EXCLUSION) private fun insertDirectoryExclusions(library: Library) { if (library.scanDirectoryExclusions.isNotEmpty()) { - dsl.batch( - dsl.insertInto(le, le.LIBRARY_ID, le.EXCLUSION) - .values(null as String?, null), - ).also { step -> - library.scanDirectoryExclusions.forEach { - step.bind(library.id, it) - } - }.execute() + dsl + .batch( + dsl + .insertInto(le, le.LIBRARY_ID, le.EXCLUSION) + .values(null as String?, null), + ).also { step -> + library.scanDirectoryExclusions.forEach { + step.bind(library.id, it) + } + }.execute() } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt index 40c64bb3..a406503f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt @@ -54,14 +54,13 @@ class MediaDao( *p.fields(), ) - override fun findById(bookId: String): Media = - find(dsl, bookId)!! + override fun findById(bookId: String): Media = find(dsl, bookId)!! - override fun findByIdOrNull(bookId: String): Media? = - find(dsl, bookId) + override fun findByIdOrNull(bookId: String): Media? = find(dsl, bookId) override fun findExtensionByIdOrNull(bookId: String): MediaExtension? = - dsl.select(m.EXTENSION_CLASS, m.EXTENSION_VALUE_BLOB) + dsl + .select(m.EXTENSION_CLASS, m.EXTENSION_VALUE_BLOB) .from(m) .where(m.BOOK_ID.eq(bookId)) .fetchOne() @@ -77,10 +76,13 @@ class MediaDao( val neededHash = pageHashing * 2 val neededHashForBook = DSL.`when`(pagesCount.lt(neededHash), pagesCount).otherwise(neededHash) - return dsl.select(b.ID) + return dsl + .select(b.ID) .from(b) - .leftJoin(p).on(b.ID.eq(p.BOOK_ID)) - .leftJoin(m).on(b.ID.eq(m.BOOK_ID)) + .leftJoin(p) + .on(b.ID.eq(p.BOOK_ID)) + .leftJoin(m) + .on(b.ID.eq(m.BOOK_ID)) .where(b.LIBRARY_ID.eq(libraryId)) .and(m.STATUS.eq(Media.Status.READY.name)) .and(m.MEDIA_TYPE.`in`(mediaTypes)) @@ -91,7 +93,8 @@ class MediaDao( } override fun getPagesSizes(bookIds: Collection): Collection> = - dsl.select(m.BOOK_ID, m.PAGE_COUNT) + dsl + .select(m.BOOK_ID, m.PAGE_COUNT) .from(m) .where(m.BOOK_ID.`in`(bookIds)) .fetch() @@ -101,9 +104,11 @@ class MediaDao( dsl: DSLContext, bookId: String, ): Media? = - dsl.select(*groupFields) + dsl + .select(*groupFields) .from(m) - .leftJoin(p).on(m.BOOK_ID.eq(p.BOOK_ID)) + .leftJoin(p) + .on(m.BOOK_ID.eq(p.BOOK_ID)) .where(m.BOOK_ID.eq(bookId)) .groupBy(*groupFields) .orderBy(p.NUMBER.asc()) @@ -112,7 +117,8 @@ class MediaDao( { it.into(p) }, ).map { (mr, pr) -> val files = - dsl.selectFrom(f) + dsl + .selectFrom(f) .where(f.BOOK_ID.eq(bookId)) .fetchInto(f) @@ -128,34 +134,36 @@ class MediaDao( override fun insert(medias: Collection) { if (medias.isNotEmpty()) { medias.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto( - m, - m.BOOK_ID, - m.STATUS, - m.MEDIA_TYPE, - m.COMMENT, - m.PAGE_COUNT, - m.EPUB_DIVINA_COMPATIBLE, - m.EPUB_IS_KEPUB, - m.EXTENSION_CLASS, - m.EXTENSION_VALUE_BLOB, - ).values(null as String?, null, null, null, null, null, null, null, null), - ).also { step -> - chunk.forEach { media -> - step.bind( - media.bookId, - media.status, - media.mediaType, - media.comment, - media.pageCount, - media.epubDivinaCompatible, - media.epubIsKepub, - media.extension?.let { if (it is ProxyExtension) null else it::class.qualifiedName }, - media.extension?.let { if (it is ProxyExtension) null else mapper.serializeJsonGz(it) }, - ) - } - }.execute() + dsl + .batch( + dsl + .insertInto( + m, + m.BOOK_ID, + m.STATUS, + m.MEDIA_TYPE, + m.COMMENT, + m.PAGE_COUNT, + m.EPUB_DIVINA_COMPATIBLE, + m.EPUB_IS_KEPUB, + m.EXTENSION_CLASS, + m.EXTENSION_VALUE_BLOB, + ).values(null as String?, null, null, null, null, null, null, null, null), + ).also { step -> + chunk.forEach { media -> + step.bind( + media.bookId, + media.status, + media.mediaType, + media.comment, + media.pageCount, + media.epubDivinaCompatible, + media.epubIsKepub, + media.extension?.let { if (it is ProxyExtension) null else it::class.qualifiedName }, + media.extension?.let { if (it is ProxyExtension) null else mapper.serializeJsonGz(it) }, + ) + } + }.execute() } insertPages(medias) @@ -166,34 +174,36 @@ class MediaDao( private fun insertPages(medias: Collection) { if (medias.any { it.pages.isNotEmpty() }) { medias.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto( - p, - p.BOOK_ID, - p.FILE_NAME, - p.MEDIA_TYPE, - p.NUMBER, - p.WIDTH, - p.HEIGHT, - p.FILE_HASH, - p.FILE_SIZE, - ).values(null as String?, null, null, null, null, null, null, null), - ).also { step -> - chunk.forEach { media -> - media.pages.forEachIndexed { index, page -> - step.bind( - media.bookId, - page.fileName, - page.mediaType, - index, - page.dimension?.width, - page.dimension?.height, - page.fileHash, - page.fileSize, - ) + dsl + .batch( + dsl + .insertInto( + p, + p.BOOK_ID, + p.FILE_NAME, + p.MEDIA_TYPE, + p.NUMBER, + p.WIDTH, + p.HEIGHT, + p.FILE_HASH, + p.FILE_SIZE, + ).values(null as String?, null, null, null, null, null, null, null), + ).also { step -> + chunk.forEach { media -> + media.pages.forEachIndexed { index, page -> + step.bind( + media.bookId, + page.fileName, + page.mediaType, + index, + page.dimension?.width, + page.dimension?.height, + page.fileHash, + page.fileSize, + ) + } } - } - }.execute() + }.execute() } } } @@ -201,35 +211,38 @@ class MediaDao( private fun insertFiles(medias: Collection) { if (medias.any { it.files.isNotEmpty() }) { medias.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto( - f, - f.BOOK_ID, - f.FILE_NAME, - f.MEDIA_TYPE, - f.SUB_TYPE, - f.FILE_SIZE, - ).values(null as String?, null, null, null, null), - ).also { step -> - chunk.forEach { media -> - media.files.forEach { - step.bind( - media.bookId, - it.fileName, - it.mediaType, - it.subType, - it.fileSize, - ) + dsl + .batch( + dsl + .insertInto( + f, + f.BOOK_ID, + f.FILE_NAME, + f.MEDIA_TYPE, + f.SUB_TYPE, + f.FILE_SIZE, + ).values(null as String?, null, null, null, null), + ).also { step -> + chunk.forEach { media -> + media.files.forEach { + step.bind( + media.bookId, + it.fileName, + it.mediaType, + it.subType, + it.fileSize, + ) + } } - } - }.execute() + }.execute() } } } @Transactional override fun update(media: Media) { - dsl.update(m) + dsl + .update(m) .set(m.STATUS, media.status.toString()) .set(m.MEDIA_TYPE, media.mediaType) .set(m.COMMENT, media.comment) @@ -241,16 +254,17 @@ class MediaDao( set(m.EXTENSION_CLASS, media.extension::class.qualifiedName) set(m.EXTENSION_VALUE_BLOB, mapper.serializeJsonGz(media.extension)) } - } - .set(m.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z"))) + }.set(m.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z"))) .where(m.BOOK_ID.eq(media.bookId)) .execute() - dsl.deleteFrom(p) + dsl + .deleteFrom(p) .where(p.BOOK_ID.eq(media.bookId)) .execute() - dsl.deleteFrom(f) + dsl + .deleteFrom(f) .where(f.BOOK_ID.eq(media.bookId)) .execute() @@ -279,21 +293,20 @@ class MediaDao( private fun MediaRecord.toDomain( pages: List, files: List, - ) = - Media( - status = Media.Status.valueOf(status), - mediaType = mediaType, - pages = pages, - pageCount = pageCount, - files = files, - extension = ProxyExtension.of(extensionClass), - comment = comment, - bookId = bookId, - epubDivinaCompatible = epubDivinaCompatible, - epubIsKepub = epubIsKepub, - createdDate = createdDate.toCurrentTimeZone(), - lastModifiedDate = lastModifiedDate.toCurrentTimeZone(), - ) + ) = Media( + status = Media.Status.valueOf(status), + mediaType = mediaType, + pages = pages, + pageCount = pageCount, + files = files, + extension = ProxyExtension.of(extensionClass), + comment = comment, + bookId = bookId, + epubDivinaCompatible = epubDivinaCompatible, + epubIsKepub = epubIsKepub, + createdDate = createdDate.toCurrentTimeZone(), + lastModifiedDate = lastModifiedDate.toCurrentTimeZone(), + ) private fun MediaPageRecord.toDomain() = BookPage( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/PageHashDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/PageHashDao.kt index 30ba8630..957bd1cf 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/PageHashDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/PageHashDao.kt @@ -54,7 +54,8 @@ class PageHashDao( ) override fun findKnown(pageHash: String): PageHashKnown? = - dsl.selectFrom(ph) + dsl + .selectFrom(ph) .where(ph.HASH.eq(pageHash)) .fetchOneInto(ph) ?.toDomain() @@ -64,9 +65,11 @@ class PageHashDao( pageable: Pageable, ): Page { val query = - dsl.select(*ph.fields(), DSL.count(p.FILE_HASH).`as`("count")) + dsl + .select(*ph.fields(), DSL.count(p.FILE_HASH).`as`("count")) .from(ph) - .leftJoin(p).on(ph.HASH.eq(p.FILE_HASH)) + .leftJoin(p) + .on(ph.HASH.eq(p.FILE_HASH)) .apply { actions?.let { where(ph.ACTION.`in`(actions)) } } .groupBy(*ph.fields()) @@ -94,22 +97,22 @@ class PageHashDao( override fun findAllUnknown(pageable: Pageable): Page { val bookCount = DSL.count(p.BOOK_ID) val query = - dsl.select( - p.FILE_HASH, - p.FILE_SIZE, - bookCount.`as`("count"), - (bookCount * p.FILE_SIZE).`as`("totalSize"), - ) - .from(p) + dsl + .select( + p.FILE_HASH, + p.FILE_SIZE, + bookCount.`as`("count"), + (bookCount * p.FILE_SIZE).`as`("totalSize"), + ).from(p) .where(p.FILE_HASH.ne("")) .and( DSL.notExists( - dsl.selectOne() + dsl + .selectOne() .from(ph) .where(ph.HASH.eq(p.FILE_HASH)), ), - ) - .groupBy(p.FILE_HASH) + ).groupBy(p.FILE_HASH) .having(DSL.count(p.BOOK_ID).gt(1)) val count = dsl.fetchCount(query) @@ -139,9 +142,11 @@ class PageHashDao( pageable: Pageable, ): Page { val query = - dsl.select(p.BOOK_ID, b.URL, p.NUMBER, p.FILE_NAME, p.FILE_SIZE, p.MEDIA_TYPE) + dsl + .select(p.BOOK_ID, b.URL, p.NUMBER, p.FILE_NAME, p.FILE_SIZE, p.MEDIA_TYPE) .from(p) - .leftJoin(b).on(p.BOOK_ID.eq(b.ID)) + .leftJoin(b) + .on(p.BOOK_ID.eq(b.ID)) .where(p.FILE_HASH.eq(pageHash)) val count = dsl.fetchCount(query) @@ -177,9 +182,11 @@ class PageHashDao( actions: List?, libraryId: String?, ): Map> = - dsl.select(p.BOOK_ID, p.FILE_NAME, p.NUMBER, p.FILE_HASH, p.MEDIA_TYPE, p.FILE_SIZE) + dsl + .select(p.BOOK_ID, p.FILE_NAME, p.NUMBER, p.FILE_HASH, p.MEDIA_TYPE, p.FILE_SIZE) .from(p) - .innerJoin(ph).on(p.FILE_HASH.eq(ph.HASH)) + .innerJoin(ph) + .on(p.FILE_HASH.eq(ph.HASH)) .apply { libraryId?.let { innerJoin(b).on(b.ID.eq(p.BOOK_ID)) } } .where(ph.ACTION.`in`(actions)) .apply { libraryId?.let { and(b.LIBRARY_ID.eq(it)) } } @@ -196,24 +203,28 @@ class PageHashDao( .fold(emptyList()) { acc, (_, new) -> acc + new } override fun getKnownThumbnail(pageHash: String): ByteArray? = - dsl.select(pht.THUMBNAIL) + dsl + .select(pht.THUMBNAIL) .from(pht) .where(pht.HASH.eq(pageHash)) - .fetchOne()?.value1() + .fetchOne() + ?.value1() @Transactional override fun insert( pageHash: PageHashKnown, thumbnail: ByteArray?, ) { - dsl.insertInto(ph) + dsl + .insertInto(ph) .set(ph.HASH, pageHash.hash) .set(ph.SIZE, pageHash.size) .set(ph.ACTION, pageHash.action.name) .execute() if (thumbnail != null) { - dsl.insertInto(pht) + dsl + .insertInto(pht) .set(pht.HASH, pageHash.hash) .set(pht.THUMBNAIL, thumbnail) .execute() @@ -221,7 +232,8 @@ class PageHashDao( } override fun update(pageHash: PageHashKnown) { - dsl.update(ph) + dsl + .update(ph) .set(ph.ACTION, pageHash.action.name) .set(ph.SIZE, pageHash.size) .set(ph.DELETE_COUNT, pageHash.deleteCount) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDao.kt index a1d35afd..7b02ffb6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDao.kt @@ -80,10 +80,13 @@ class ReadListDao( if (belongsToLibraryIds == null && filterOnLibraryIds == null && !restrictions.isRestricted) null else - dsl.selectDistinct(rl.ID) + dsl + .selectDistinct(rl.ID) .from(rl) - .leftJoin(rlb).on(rl.ID.eq(rlb.READLIST_ID)) - .leftJoin(b).on(rlb.BOOK_ID.eq(b.ID)) + .leftJoin(rlb) + .on(rl.ID.eq(rlb.READLIST_ID)) + .leftJoin(b) + .on(rlb.BOOK_ID.eq(b.ID)) .apply { if (restrictions.isRestricted) leftJoin(sd).on(sd.SERIES_ID.eq(b.SERIES_ID)) } .where(conditions) @@ -126,9 +129,11 @@ class ReadListDao( restrictions: ContentRestrictions, ): Collection { val queryIds = - dsl.select(rl.ID) + dsl + .select(rl.ID) .from(rl) - .leftJoin(rlb).on(rl.ID.eq(rlb.READLIST_ID)) + .leftJoin(rlb) + .on(rl.ID.eq(rlb.READLIST_ID)) .apply { if (restrictions.isRestricted) leftJoin(b).on(rlb.BOOK_ID.eq(b.ID)).leftJoin(sd).on(sd.SERIES_ID.eq(b.SERIES_ID)) } .where(rlb.BOOK_ID.eq(containsBookId)) .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } @@ -141,12 +146,15 @@ class ReadListDao( } override fun findAllEmpty(): Collection = - dsl.selectFrom(rl) + dsl + .selectFrom(rl) .where( rl.ID.`in`( - dsl.select(rl.ID) + dsl + .select(rl.ID) .from(rl) - .leftJoin(rlb).on(rl.ID.eq(rlb.READLIST_ID)) + .leftJoin(rlb) + .on(rl.ID.eq(rlb.READLIST_ID)) .where(rlb.READLIST_ID.isNull), ), ).fetchInto(rl) @@ -159,10 +167,13 @@ class ReadListDao( .firstOrNull() private fun selectBase(joinOnSeriesMetadata: Boolean = false) = - dsl.selectDistinct(*rl.fields()) + dsl + .selectDistinct(*rl.fields()) .from(rl) - .leftJoin(rlb).on(rl.ID.eq(rlb.READLIST_ID)) - .leftJoin(b).on(rlb.BOOK_ID.eq(b.ID)) + .leftJoin(rlb) + .on(rl.ID.eq(rlb.READLIST_ID)) + .leftJoin(b) + .on(rlb.BOOK_ID.eq(b.ID)) .apply { if (joinOnSeriesMetadata) leftJoin(sd).on(sd.SERIES_ID.eq(b.SERIES_ID)) } private fun ResultQuery.fetchAndMap( @@ -172,9 +183,11 @@ class ReadListDao( fetchInto(rl) .map { rr -> val bookIds = - dsl.select(*rlb.fields()) + dsl + .select(*rlb.fields()) .from(rlb) - .leftJoin(b).on(rlb.BOOK_ID.eq(b.ID)) + .leftJoin(b) + .on(rlb.BOOK_ID.eq(b.ID)) .apply { if (restrictions.isRestricted) leftJoin(sd).on(sd.SERIES_ID.eq(b.SERIES_ID)) } .where(rlb.READLIST_ID.eq(rr.id)) .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } @@ -182,13 +195,15 @@ class ReadListDao( .orderBy(rlb.NUMBER.asc()) .fetchInto(rlb) .mapNotNull { it.number to it.bookId } - .toMap().toSortedMap() + .toMap() + .toSortedMap() rr.toDomain(bookIds) } @Transactional override fun insert(readList: ReadList) { - dsl.insertInto(rl) + dsl + .insertInto(rl) .set(rl.ID, readList.id) .set(rl.NAME, readList.name) .set(rl.SUMMARY, readList.summary) @@ -201,7 +216,8 @@ class ReadListDao( private fun insertBooks(readList: ReadList) { readList.bookIds.map { (index, id) -> - dsl.insertInto(rlb) + dsl + .insertInto(rlb) .set(rlb.READLIST_ID, readList.id) .set(rlb.BOOK_ID, id) .set(rlb.NUMBER, index) @@ -211,7 +227,8 @@ class ReadListDao( @Transactional override fun update(readList: ReadList) { - dsl.update(rl) + dsl + .update(rl) .set(rl.NAME, readList.name) .set(rl.SUMMARY, readList.summary) .set(rl.ORDERED, readList.ordered) @@ -226,7 +243,8 @@ class ReadListDao( } override fun removeBookFromAll(bookId: String) { - dsl.deleteFrom(rlb) + dsl + .deleteFrom(rlb) .where(rlb.BOOK_ID.eq(bookId)) .execute() } @@ -235,7 +253,8 @@ class ReadListDao( override fun removeBooksFromAll(bookIds: Collection) { dsl.insertTempStrings(batchSize, bookIds) - dsl.deleteFrom(rlb) + dsl + .deleteFrom(rlb) .where(rlb.BOOK_ID.`in`(dsl.selectTempStrings())) .execute() } @@ -260,7 +279,8 @@ class ReadListDao( override fun existsByName(name: String): Boolean = dsl.fetchExists( - dsl.selectFrom(rl) + dsl + .selectFrom(rl) .where(rl.NAME.equalIgnoreCase(name)), ) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListRequestDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListRequestDao.kt index 75a712be..426ee3f9 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListRequestDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListRequestDao.kt @@ -32,21 +32,26 @@ class ReadListRequestDao( val numberField = "number" val requestsTable = values(*requestsAsRows.toTypedArray()).`as`("request", indexField, seriesField, numberField) val matchedRequests = - dsl.select( - requestsTable.field(indexField, Int::class.java), - sd.SERIES_ID, - sd.TITLE, - bd.BOOK_ID, - bd.NUMBER, - bd.TITLE, - bma.RELEASE_DATE, - ) - .from(requestsTable) - .innerJoin(sd).on(requestsTable.field(seriesField, String::class.java)?.eq(sd.TITLE.noCase())) - .leftJoin(bma).on(sd.SERIES_ID.eq(bma.SERIES_ID)) - .innerJoin(b).on(sd.SERIES_ID.eq(b.SERIES_ID)) - .innerJoin(bd).on( - b.ID.eq(bd.BOOK_ID) + dsl + .select( + requestsTable.field(indexField, Int::class.java), + sd.SERIES_ID, + sd.TITLE, + bd.BOOK_ID, + bd.NUMBER, + bd.TITLE, + bma.RELEASE_DATE, + ).from(requestsTable) + .innerJoin(sd) + .on(requestsTable.field(seriesField, String::class.java)?.eq(sd.TITLE.noCase())) + .leftJoin(bma) + .on(sd.SERIES_ID.eq(bma.SERIES_ID)) + .innerJoin(b) + .on(sd.SERIES_ID.eq(b.SERIES_ID)) + .innerJoin(bd) + .on( + b.ID + .eq(bd.BOOK_ID) .and(ltrim(bd.NUMBER, value("0")).eq(ltrim(requestsTable.field(numberField, String::class.java), value("0")).noCase())), ).fetchGroups(requestsTable.field(indexField, Int::class.java)) .mapValues { (_, records) -> diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDao.kt index ea17d702..6739b5aa 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDao.kt @@ -32,7 +32,8 @@ class ReadProgressDao( private val b = Tables.BOOK override fun findAll(): Collection = - dsl.selectFrom(r) + dsl + .selectFrom(r) .fetchInto(r) .map { it.toDomain() } @@ -40,19 +41,22 @@ class ReadProgressDao( bookId: String, userId: String, ): ReadProgress? = - dsl.selectFrom(r) + dsl + .selectFrom(r) .where(r.BOOK_ID.eq(bookId).and(r.USER_ID.eq(userId))) .fetchOneInto(r) ?.toDomain() override fun findAllByUserId(userId: String): Collection = - dsl.selectFrom(r) + dsl + .selectFrom(r) .where(r.USER_ID.eq(userId)) .fetchInto(r) .map { it.toDomain() } override fun findAllByBookId(bookId: String): Collection = - dsl.selectFrom(r) + dsl + .selectFrom(r) .where(r.BOOK_ID.eq(bookId)) .fetchInto(r) .map { it.toDomain() } @@ -61,7 +65,8 @@ class ReadProgressDao( bookIds: Collection, userId: String, ): Collection = - dsl.selectFrom(r) + dsl + .selectFrom(r) .where(r.BOOK_ID.`in`(bookIds).and(r.USER_ID.eq(userId))) .fetchInto(r) .map { it.toDomain() } @@ -87,18 +92,18 @@ class ReadProgressDao( } private fun ReadProgress.toQuery(): Query = - dsl.insertInto( - r, - r.BOOK_ID, - r.USER_ID, - r.PAGE, - r.COMPLETED, - r.READ_DATE, - r.DEVICE_ID, - r.DEVICE_NAME, - r.LOCATOR, - ) - .values( + dsl + .insertInto( + r, + r.BOOK_ID, + r.USER_ID, + r.PAGE, + r.COMPLETED, + r.READ_DATE, + r.DEVICE_ID, + r.DEVICE_NAME, + r.LOCATOR, + ).values( bookId, userId, page, @@ -107,8 +112,7 @@ class ReadProgressDao( deviceId, deviceName, locator?.let { mapper.serializeJsonGz(it) }, - ) - .onDuplicateKeyUpdate() + ).onDuplicateKeyUpdate() .set(r.PAGE, page) .set(r.COMPLETED, completed) .set(r.READ_DATE, readDate.toUTC()) @@ -160,7 +164,11 @@ class ReadProgressDao( ) { dsl.insertTempStrings(batchSize, bookIds) - dsl.deleteFrom(r).where(r.BOOK_ID.`in`(dsl.selectTempStrings())).and(r.USER_ID.eq(userId)).execute() + dsl + .deleteFrom(r) + .where(r.BOOK_ID.`in`(dsl.selectTempStrings())) + .and(r.USER_ID.eq(userId)) + .execute() aggregateSeriesProgress(bookIds, userId) } @@ -177,24 +185,29 @@ class ReadProgressDao( dsl.insertTempStrings(batchSize, bookIds) val seriesIdsQuery = - dsl.select(b.SERIES_ID) + dsl + .select(b.SERIES_ID) .from(b) .where(b.ID.`in`(dsl.selectTempStrings())) - dsl.deleteFrom(rs) + dsl + .deleteFrom(rs) .where(rs.SERIES_ID.`in`(seriesIdsQuery)) .apply { userId?.let { and(rs.USER_ID.eq(it)) } } .execute() - dsl.insertInto(rs) + dsl + .insertInto(rs) .select( - dsl.select(b.SERIES_ID, r.USER_ID) + dsl + .select(b.SERIES_ID, r.USER_ID) .select(DSL.sum(DSL.`when`(r.COMPLETED.isTrue, 1).otherwise(0))) .select(DSL.sum(DSL.`when`(r.COMPLETED.isFalse, 1).otherwise(0))) .select(DSL.max(r.READ_DATE)) .select(DSL.currentTimestamp()) .from(b) - .innerJoin(r).on(b.ID.eq(r.BOOK_ID)) + .innerJoin(r) + .on(b.ID.eq(r.BOOK_ID)) .where(b.SERIES_ID.`in`(seriesIdsQuery)) .apply { userId?.let { and(r.USER_ID.eq(it)) } } .groupBy(b.SERIES_ID, r.USER_ID), diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDtoDao.kt index 242b2718..b0151bcb 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDtoDao.kt @@ -31,22 +31,27 @@ class ReadProgressDtoDao( userId: String, ): TachiyomiReadProgressV2Dto { val numberSortReadProgress = - dsl.select( - d.NUMBER_SORT, - r.COMPLETED, - ) - .from(b) - .leftJoin(r).on(b.ID.eq(r.BOOK_ID)).and(readProgressCondition(userId)) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) + dsl + .select( + d.NUMBER_SORT, + r.COMPLETED, + ).from(b) + .leftJoin(r) + .on(b.ID.eq(r.BOOK_ID)) + .and(readProgressCondition(userId)) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) .where(b.SERIES_ID.eq(seriesId)) .orderBy(d.NUMBER_SORT) .fetch() .toList() val maxNumberSort = - dsl.select(DSL.max(d.NUMBER_SORT)) + dsl + .select(DSL.max(d.NUMBER_SORT)) .from(b) - .leftJoin(d).on(b.ID.eq(d.BOOK_ID)) + .leftJoin(d) + .on(b.ID.eq(d.BOOK_ID)) .where(b.SERIES_ID.eq(seriesId)) .fetchOne(DSL.max(d.NUMBER_SORT)) ?: 0F @@ -58,36 +63,40 @@ class ReadProgressDtoDao( private fun getSeriesBooksCount( seriesId: String, userId: String, - ) = - dsl - .select(countUnread.`as`(BOOKS_UNREAD_COUNT)) - .select(countRead.`as`(BOOKS_READ_COUNT)) - .select(countInProgress.`as`(BOOKS_IN_PROGRESS_COUNT)) - .from(b) - .leftJoin(r).on(b.ID.eq(r.BOOK_ID)).and(readProgressCondition(userId)) - .where(b.SERIES_ID.eq(seriesId)) - .fetch() - .first() - .map { - BooksCount( - unreadCount = it.get(BOOKS_UNREAD_COUNT, Int::class.java), - readCount = it.get(BOOKS_READ_COUNT, Int::class.java), - inProgressCount = it.get(BOOKS_IN_PROGRESS_COUNT, Int::class.java), - ) - } + ) = dsl + .select(countUnread.`as`(BOOKS_UNREAD_COUNT)) + .select(countRead.`as`(BOOKS_READ_COUNT)) + .select(countInProgress.`as`(BOOKS_IN_PROGRESS_COUNT)) + .from(b) + .leftJoin(r) + .on(b.ID.eq(r.BOOK_ID)) + .and(readProgressCondition(userId)) + .where(b.SERIES_ID.eq(seriesId)) + .fetch() + .first() + .map { + BooksCount( + unreadCount = it.get(BOOKS_UNREAD_COUNT, Int::class.java), + readCount = it.get(BOOKS_READ_COUNT, Int::class.java), + inProgressCount = it.get(BOOKS_IN_PROGRESS_COUNT, Int::class.java), + ) + } override fun findProgressByReadList( readListId: String, userId: String, ): TachiyomiReadProgressDto { val indexedReadProgress = - dsl.select( - rowNumber().over().orderBy(rlb.NUMBER), - r.COMPLETED, - ) - .from(b) - .leftJoin(r).on(b.ID.eq(r.BOOK_ID)).and(readProgressCondition(userId)) - .leftJoin(rlb).on(b.ID.eq(rlb.BOOK_ID)) + dsl + .select( + rowNumber().over().orderBy(rlb.NUMBER), + r.COMPLETED, + ).from(b) + .leftJoin(r) + .on(b.ID.eq(r.BOOK_ID)) + .and(readProgressCondition(userId)) + .leftJoin(rlb) + .on(b.ID.eq(rlb.BOOK_ID)) .where(rlb.READLIST_ID.eq(readListId)) .orderBy(rlb.NUMBER) .fetch() @@ -99,8 +108,11 @@ class ReadProgressDtoDao( .select(countRead.`as`(BOOKS_READ_COUNT)) .select(countInProgress.`as`(BOOKS_IN_PROGRESS_COUNT)) .from(b) - .leftJoin(r).on(b.ID.eq(r.BOOK_ID)).and(readProgressCondition(userId)) - .leftJoin(rlb).on(b.ID.eq(rlb.BOOK_ID)) + .leftJoin(r) + .on(b.ID.eq(r.BOOK_ID)) + .and(readProgressCondition(userId)) + .leftJoin(rlb) + .on(b.ID.eq(rlb.BOOK_ID)) .where(rlb.READLIST_ID.eq(readListId)) .fetch() .first() @@ -144,7 +156,8 @@ class ReadProgressDtoDao( private fun readProgressCondition(userId: String): Condition = r.USER_ID.eq(userId).or(r.USER_ID.isNull) private fun List>.lastRead(): T? = - this.takeWhile { it.component2() == true } + this + .takeWhile { it.component2() == true } .lastOrNull() ?.component1() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt index 41e92204..b1306b19 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt @@ -41,7 +41,8 @@ class ReferentialDao( search: String, filterOnLibraryIds: Collection?, ): List = - dsl.selectDistinct(a.NAME, a.ROLE) + dsl + .selectDistinct(a.NAME, a.ROLE) .from(a) .apply { filterOnLibraryIds?.let { leftJoin(b).on(a.BOOK_ID.eq(b.ID)) } } .where(a.NAME.udfStripAccents().containsIgnoreCase(search.stripAccents())) @@ -55,9 +56,11 @@ class ReferentialDao( libraryId: String, filterOnLibraryIds: Collection?, ): List = - dsl.selectDistinct(bmaa.NAME, bmaa.ROLE) + dsl + .selectDistinct(bmaa.NAME, bmaa.ROLE) .from(bmaa) - .leftJoin(s).on(bmaa.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(bmaa.SERIES_ID.eq(s.ID)) .where(bmaa.NAME.udfStripAccents().containsIgnoreCase(search.stripAccents())) .and(s.LIBRARY_ID.eq(libraryId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } @@ -70,9 +73,11 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): List = - dsl.selectDistinct(bmaa.NAME, bmaa.ROLE) + dsl + .selectDistinct(bmaa.NAME, bmaa.ROLE) .from(bmaa) - .leftJoin(cs).on(bmaa.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(cs) + .on(bmaa.SERIES_ID.eq(cs.SERIES_ID)) .apply { filterOnLibraryIds?.let { leftJoin(s).on(bmaa.SERIES_ID.eq(s.ID)) } } .where(bmaa.NAME.udfStripAccents().containsIgnoreCase(search.stripAccents())) .and(cs.COLLECTION_ID.eq(collectionId)) @@ -86,7 +91,8 @@ class ReferentialDao( seriesId: String, filterOnLibraryIds: Collection?, ): List = - dsl.selectDistinct(bmaa.NAME, bmaa.ROLE) + dsl + .selectDistinct(bmaa.NAME, bmaa.ROLE) .from(bmaa) .apply { filterOnLibraryIds?.let { leftJoin(s).on(bmaa.SERIES_ID.eq(s.ID)) } } .where(bmaa.NAME.udfStripAccents().containsIgnoreCase(search.stripAccents())) @@ -101,9 +107,7 @@ class ReferentialDao( role: String?, filterOnLibraryIds: Collection?, pageable: Pageable, - ): Page { - return findAuthorsByName(search, role, filterOnLibraryIds, pageable, null) - } + ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, null) override fun findAllAuthorsByNameAndLibrary( search: String?, @@ -111,9 +115,7 @@ class ReferentialDao( libraryId: String, filterOnLibraryIds: Collection?, pageable: Pageable, - ): Page { - return findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.LIBRARY, libraryId)) - } + ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.LIBRARY, libraryId)) override fun findAllAuthorsByNameAndCollection( search: String?, @@ -121,9 +123,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, pageable: Pageable, - ): Page { - return findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.COLLECTION, collectionId)) - } + ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.COLLECTION, collectionId)) override fun findAllAuthorsByNameAndSeries( search: String?, @@ -131,9 +131,7 @@ class ReferentialDao( seriesId: String, filterOnLibraryIds: Collection?, pageable: Pageable, - ): Page { - return findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.SERIES, seriesId)) - } + ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.SERIES, seriesId)) override fun findAllAuthorsByNameAndReadList( search: String?, @@ -141,9 +139,7 @@ class ReferentialDao( readListId: String, filterOnLibraryIds: Collection?, pageable: Pageable, - ): Page { - return findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.READLIST, readListId)) - } + ): Page = findAuthorsByName(search, role, filterOnLibraryIds, pageable, FilterBy(FilterByType.READLIST, readListId)) private enum class FilterByType { LIBRARY, @@ -165,16 +161,18 @@ class ReferentialDao( filterBy: FilterBy?, ): Page { val query = - dsl.selectDistinct(bmaa.NAME, bmaa.ROLE) + dsl + .selectDistinct(bmaa.NAME, bmaa.ROLE) .from(bmaa) .apply { if (filterOnLibraryIds != null || filterBy?.type == FilterByType.LIBRARY) leftJoin(s).on(bmaa.SERIES_ID.eq(s.ID)) } .apply { if (filterBy?.type == FilterByType.COLLECTION) leftJoin(cs).on(bmaa.SERIES_ID.eq(cs.SERIES_ID)) } .apply { if (filterBy?.type == FilterByType.READLIST) - leftJoin(b).on(bmaa.SERIES_ID.eq(b.SERIES_ID)) - .leftJoin(rb).on(b.ID.eq(rb.BOOK_ID)) - } - .where(noCondition()) + leftJoin(b) + .on(bmaa.SERIES_ID.eq(b.SERIES_ID)) + .leftJoin(rb) + .on(b.ID.eq(rb.BOOK_ID)) + }.where(noCondition()) .apply { search?.let { and(bmaa.NAME.udfStripAccents().containsIgnoreCase(search.stripAccents())) } } .apply { role?.let { and(bmaa.ROLE.eq(role)) } } .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } @@ -214,7 +212,8 @@ class ReferentialDao( search: String, filterOnLibraryIds: Collection?, ): List = - dsl.selectDistinct(a.NAME) + dsl + .selectDistinct(a.NAME) .from(a) .apply { filterOnLibraryIds?.let { leftJoin(b).on(a.BOOK_ID.eq(b.ID)) } } .where(a.NAME.udfStripAccents().containsIgnoreCase(search.stripAccents())) @@ -223,36 +222,40 @@ class ReferentialDao( .fetch(a.NAME) override fun findAllAuthorsRoles(filterOnLibraryIds: Collection?): List = - dsl.selectDistinct(a.ROLE) + dsl + .selectDistinct(a.ROLE) .from(a) .apply { filterOnLibraryIds?.let { - leftJoin(b).on(a.BOOK_ID.eq(b.ID)) + leftJoin(b) + .on(a.BOOK_ID.eq(b.ID)) .where(b.LIBRARY_ID.`in`(it)) } - } - .orderBy(a.ROLE) + }.orderBy(a.ROLE) .fetch(a.ROLE) override fun findAllGenres(filterOnLibraryIds: Collection?): Set = - dsl.selectDistinct(g.GENRE) + dsl + .selectDistinct(g.GENRE) .from(g) .apply { filterOnLibraryIds?.let { - leftJoin(s).on(g.SERIES_ID.eq(s.ID)) + leftJoin(s) + .on(g.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.`in`(it)) } - } - .orderBy(g.GENRE.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) + }.orderBy(g.GENRE.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) .fetchSet(g.GENRE) override fun findAllGenresByLibrary( libraryId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(g.GENRE) + dsl + .selectDistinct(g.GENRE) .from(g) - .leftJoin(s).on(g.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(g.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.eq(libraryId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(g.GENRE.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) @@ -262,9 +265,11 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(g.GENRE) + dsl + .selectDistinct(g.GENRE) .from(g) - .leftJoin(cs).on(g.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(cs) + .on(g.SERIES_ID.eq(cs.SERIES_ID)) .apply { filterOnLibraryIds?.let { leftJoin(s).on(g.SERIES_ID.eq(s.ID)) } } .where(cs.COLLECTION_ID.eq(collectionId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } @@ -272,15 +277,15 @@ class ReferentialDao( .fetchSet(g.GENRE) override fun findAllSeriesAndBookTags(filterOnLibraryIds: Collection?): Set = - dsl.select(bt.TAG.`as`("tag")) + dsl + .select(bt.TAG.`as`("tag")) .from(bt) .apply { filterOnLibraryIds?.let { leftJoin(b).on(bt.BOOK_ID.eq(b.ID)).where(b.LIBRARY_ID.`in`(it)) } } .union( select(st.TAG.`as`("tag")) .from(st) .apply { filterOnLibraryIds?.let { leftJoin(s).on(st.SERIES_ID.eq(s.ID)).where(s.LIBRARY_ID.`in`(it)) } }, - ) - .fetchSet(0, String::class.java) + ).fetchSet(0, String::class.java) .sortedBy { it.stripAccents().lowercase() } .toSet() @@ -288,19 +293,21 @@ class ReferentialDao( libraryId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.select(bt.TAG.`as`("tag")) + dsl + .select(bt.TAG.`as`("tag")) .from(bt) - .leftJoin(b).on(bt.BOOK_ID.eq(b.ID)) + .leftJoin(b) + .on(bt.BOOK_ID.eq(b.ID)) .where(b.LIBRARY_ID.eq(libraryId)) .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } .union( select(st.TAG.`as`("tag")) .from(st) - .leftJoin(s).on(st.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(st.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.eq(libraryId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } }, - ) - .fetchSet(0, String::class.java) + ).fetchSet(0, String::class.java) .sortedBy { it.stripAccents().lowercase() } .toSet() @@ -308,43 +315,50 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.select(bmat.TAG.`as`("tag")) + dsl + .select(bmat.TAG.`as`("tag")) .from(bmat) - .leftJoin(s).on(bmat.SERIES_ID.eq(s.ID)) - .leftJoin(cs).on(bmat.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(s) + .on(bmat.SERIES_ID.eq(s.ID)) + .leftJoin(cs) + .on(bmat.SERIES_ID.eq(cs.SERIES_ID)) .where(cs.COLLECTION_ID.eq(collectionId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .union( select(st.TAG.`as`("tag")) .from(st) - .leftJoin(cs).on(st.SERIES_ID.eq(cs.SERIES_ID)) - .leftJoin(s).on(st.SERIES_ID.eq(s.ID)) + .leftJoin(cs) + .on(st.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(s) + .on(st.SERIES_ID.eq(s.ID)) .where(cs.COLLECTION_ID.eq(collectionId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } }, - ) - .fetchSet(0, String::class.java) + ).fetchSet(0, String::class.java) .sortedBy { it.stripAccents().lowercase() } .toSet() override fun findAllSeriesTags(filterOnLibraryIds: Collection?): Set = - dsl.select(st.TAG) + dsl + .select(st.TAG) .from(st) .apply { filterOnLibraryIds?.let { - leftJoin(s).on(st.SERIES_ID.eq(s.ID)) + leftJoin(s) + .on(st.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.`in`(it)) } - } - .orderBy(st.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) + }.orderBy(st.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) .fetchSet(st.TAG) override fun findAllSeriesTagsByLibrary( libraryId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.select(st.TAG) + dsl + .select(st.TAG) .from(st) - .leftJoin(s).on(st.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(st.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.eq(libraryId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(st.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) @@ -354,9 +368,11 @@ class ReferentialDao( seriesId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.select(bt.TAG) + dsl + .select(bt.TAG) .from(bt) - .leftJoin(b).on(bt.BOOK_ID.eq(b.ID)) + .leftJoin(b) + .on(bt.BOOK_ID.eq(b.ID)) .where(b.SERIES_ID.eq(seriesId)) .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } .orderBy(bt.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) @@ -366,10 +382,13 @@ class ReferentialDao( readListId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.select(bt.TAG) + dsl + .select(bt.TAG) .from(bt) - .leftJoin(b).on(bt.BOOK_ID.eq(b.ID)) - .leftJoin(rb).on(bt.BOOK_ID.eq(rb.BOOK_ID)) + .leftJoin(b) + .on(bt.BOOK_ID.eq(b.ID)) + .leftJoin(rb) + .on(bt.BOOK_ID.eq(rb.BOOK_ID)) .where(rb.READLIST_ID.eq(readListId)) .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } .orderBy(bt.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) @@ -379,9 +398,11 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.select(st.TAG) + dsl + .select(st.TAG) .from(st) - .leftJoin(cs).on(st.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(cs) + .on(st.SERIES_ID.eq(cs.SERIES_ID)) .apply { filterOnLibraryIds?.let { leftJoin(s).on(st.SERIES_ID.eq(s.ID)) } } .where(cs.COLLECTION_ID.eq(collectionId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } @@ -389,19 +410,21 @@ class ReferentialDao( .fetchSet(st.TAG) override fun findAllBookTags(filterOnLibraryIds: Collection?): Set = - dsl.select(bt.TAG) + dsl + .select(bt.TAG) .from(bt) .apply { filterOnLibraryIds?.let { - leftJoin(b).on(bt.BOOK_ID.eq(b.ID)) + leftJoin(b) + .on(bt.BOOK_ID.eq(b.ID)) .where(b.LIBRARY_ID.`in`(it)) } - } - .orderBy(st.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) + }.orderBy(st.TAG.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) .fetchSet(st.TAG) override fun findAllLanguages(filterOnLibraryIds: Collection?): Set = - dsl.selectDistinct(sd.LANGUAGE) + dsl + .selectDistinct(sd.LANGUAGE) .from(sd) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) } } .where(sd.LANGUAGE.ne("")) @@ -413,9 +436,11 @@ class ReferentialDao( libraryId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(sd.LANGUAGE) + dsl + .selectDistinct(sd.LANGUAGE) .from(sd) - .leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(sd.SERIES_ID.eq(s.ID)) .where(sd.LANGUAGE.ne("")) .and(s.LIBRARY_ID.eq(libraryId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } @@ -426,9 +451,11 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(sd.LANGUAGE) + dsl + .selectDistinct(sd.LANGUAGE) .from(sd) - .leftJoin(cs).on(sd.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(cs) + .on(sd.SERIES_ID.eq(cs.SERIES_ID)) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) } } .where(sd.LANGUAGE.ne("")) .and(cs.COLLECTION_ID.eq(collectionId)) @@ -437,7 +464,8 @@ class ReferentialDao( .fetchSet(sd.LANGUAGE) override fun findAllPublishers(filterOnLibraryIds: Collection?): Set = - dsl.selectDistinct(sd.PUBLISHER) + dsl + .selectDistinct(sd.PUBLISHER) .from(sd) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) } } .where(sd.PUBLISHER.ne("")) @@ -450,7 +478,8 @@ class ReferentialDao( pageable: Pageable, ): Page { val query = - dsl.selectDistinct(sd.PUBLISHER) + dsl + .selectDistinct(sd.PUBLISHER) .from(sd) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) } } .where(sd.PUBLISHER.ne("")) @@ -480,9 +509,11 @@ class ReferentialDao( libraryId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(sd.PUBLISHER) + dsl + .selectDistinct(sd.PUBLISHER) .from(sd) - .leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(sd.SERIES_ID.eq(s.ID)) .where(sd.PUBLISHER.ne("")) .and(s.LIBRARY_ID.eq(libraryId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } @@ -493,9 +524,11 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(sd.PUBLISHER) + dsl + .selectDistinct(sd.PUBLISHER) .from(sd) - .leftJoin(cs).on(sd.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(cs) + .on(sd.SERIES_ID.eq(cs.SERIES_ID)) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) } } .where(sd.PUBLISHER.ne("")) .and(cs.COLLECTION_ID.eq(collectionId)) @@ -504,24 +537,27 @@ class ReferentialDao( .fetchSet(sd.PUBLISHER) override fun findAllAgeRatings(filterOnLibraryIds: Collection?): Set = - dsl.selectDistinct(sd.AGE_RATING) + dsl + .selectDistinct(sd.AGE_RATING) .from(sd) .apply { filterOnLibraryIds?.let { - leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) + leftJoin(s) + .on(sd.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.`in`(it)) } - } - .orderBy(sd.AGE_RATING) + }.orderBy(sd.AGE_RATING) .fetchSet(sd.AGE_RATING) override fun findAllAgeRatingsByLibrary( libraryId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(sd.AGE_RATING) + dsl + .selectDistinct(sd.AGE_RATING) .from(sd) - .leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(sd.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.eq(libraryId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(sd.AGE_RATING) @@ -531,9 +567,11 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(sd.AGE_RATING) + dsl + .selectDistinct(sd.AGE_RATING) .from(sd) - .leftJoin(cs).on(sd.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(cs) + .on(sd.SERIES_ID.eq(cs.SERIES_ID)) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) } } .where(cs.COLLECTION_ID.eq(collectionId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } @@ -541,7 +579,8 @@ class ReferentialDao( .fetchSet(sd.AGE_RATING) override fun findAllSeriesReleaseDates(filterOnLibraryIds: Collection?): Set = - dsl.selectDistinct(bma.RELEASE_DATE) + dsl + .selectDistinct(bma.RELEASE_DATE) .from(bma) .apply { filterOnLibraryIds?.let { leftJoin(s).on(bma.SERIES_ID.eq(s.ID)) } } .where(bma.RELEASE_DATE.isNotNull) @@ -553,9 +592,11 @@ class ReferentialDao( libraryId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(bma.RELEASE_DATE) + dsl + .selectDistinct(bma.RELEASE_DATE) .from(bma) - .leftJoin(s).on(bma.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(bma.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.eq(libraryId)) .and(bma.RELEASE_DATE.isNotNull) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } @@ -566,9 +607,11 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(bma.RELEASE_DATE) + dsl + .selectDistinct(bma.RELEASE_DATE) .from(bma) - .leftJoin(cs).on(bma.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(cs) + .on(bma.SERIES_ID.eq(cs.SERIES_ID)) .apply { filterOnLibraryIds?.let { leftJoin(s).on(bma.SERIES_ID.eq(s.ID)) } } .where(cs.COLLECTION_ID.eq(collectionId)) .and(bma.RELEASE_DATE.isNotNull) @@ -577,24 +620,27 @@ class ReferentialDao( .fetchSet(bma.RELEASE_DATE) override fun findAllSharingLabels(filterOnLibraryIds: Collection?): Set = - dsl.selectDistinct(sl.LABEL) + dsl + .selectDistinct(sl.LABEL) .from(sl) .apply { filterOnLibraryIds?.let { - leftJoin(s).on(sl.SERIES_ID.eq(s.ID)) + leftJoin(s) + .on(sl.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.`in`(it)) } - } - .orderBy(sl.LABEL.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) + }.orderBy(sl.LABEL.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) .fetchSet(sl.LABEL) override fun findAllSharingLabelsByLibrary( libraryId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(sl.LABEL) + dsl + .selectDistinct(sl.LABEL) .from(sl) - .leftJoin(s).on(sl.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(sl.SERIES_ID.eq(s.ID)) .where(s.LIBRARY_ID.eq(libraryId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .orderBy(sl.LABEL.collate(SqliteUdfDataSource.COLLATION_UNICODE_3)) @@ -604,9 +650,11 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl.selectDistinct(sl.LABEL) + dsl + .selectDistinct(sl.LABEL) .from(sl) - .leftJoin(cs).on(sl.SERIES_ID.eq(cs.SERIES_ID)) + .leftJoin(cs) + .on(sl.SERIES_ID.eq(cs.SERIES_ID)) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sl.SERIES_ID.eq(s.ID)) } } .where(cs.COLLECTION_ID.eq(collectionId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesCollectionDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesCollectionDao.kt index 37679aea..e5e29b6e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesCollectionDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesCollectionDao.kt @@ -77,11 +77,15 @@ class SeriesCollectionDao( if (belongsToLibraryIds == null && filterOnLibraryIds == null && !restrictions.isRestricted) null else - dsl.selectDistinct(c.ID) + dsl + .selectDistinct(c.ID) .from(c) - .leftJoin(cs).on(c.ID.eq(cs.COLLECTION_ID)) - .leftJoin(s).on(cs.SERIES_ID.eq(s.ID)) - .leftJoin(sd).on(cs.SERIES_ID.eq(sd.SERIES_ID)) + .leftJoin(cs) + .on(c.ID.eq(cs.COLLECTION_ID)) + .leftJoin(s) + .on(cs.SERIES_ID.eq(s.ID)) + .leftJoin(sd) + .on(cs.SERIES_ID.eq(sd.SERIES_ID)) .where(conditions) val count = @@ -123,9 +127,11 @@ class SeriesCollectionDao( restrictions: ContentRestrictions, ): Collection { val queryIds = - dsl.select(c.ID) + dsl + .select(c.ID) .from(c) - .leftJoin(cs).on(c.ID.eq(cs.COLLECTION_ID)) + .leftJoin(cs) + .on(c.ID.eq(cs.COLLECTION_ID)) .apply { if (restrictions.isRestricted) leftJoin(sd).on(cs.SERIES_ID.eq(sd.SERIES_ID)) } .where(cs.SERIES_ID.eq(containsSeriesId)) .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } @@ -138,12 +144,15 @@ class SeriesCollectionDao( } override fun findAllEmpty(): Collection = - dsl.selectFrom(c) + dsl + .selectFrom(c) .where( c.ID.`in`( - dsl.select(c.ID) + dsl + .select(c.ID) .from(c) - .leftJoin(cs).on(c.ID.eq(cs.COLLECTION_ID)) + .leftJoin(cs) + .on(c.ID.eq(cs.COLLECTION_ID)) .where(cs.COLLECTION_ID.isNull), ), ).fetchInto(c) @@ -156,10 +165,13 @@ class SeriesCollectionDao( .firstOrNull() private fun selectBase(joinOnSeriesMetadata: Boolean = false) = - dsl.selectDistinct(*c.fields()) + dsl + .selectDistinct(*c.fields()) .from(c) - .leftJoin(cs).on(c.ID.eq(cs.COLLECTION_ID)) - .leftJoin(s).on(cs.SERIES_ID.eq(s.ID)) + .leftJoin(cs) + .on(c.ID.eq(cs.COLLECTION_ID)) + .leftJoin(s) + .on(cs.SERIES_ID.eq(s.ID)) .apply { if (joinOnSeriesMetadata) leftJoin(sd).on(cs.SERIES_ID.eq(sd.SERIES_ID)) } private fun ResultQuery.fetchAndMap( @@ -169,9 +181,11 @@ class SeriesCollectionDao( fetchInto(c) .map { cr -> val seriesIds = - dsl.select(*cs.fields()) + dsl + .select(*cs.fields()) .from(cs) - .leftJoin(s).on(cs.SERIES_ID.eq(s.ID)) + .leftJoin(s) + .on(cs.SERIES_ID.eq(s.ID)) .apply { if (restrictions.isRestricted) leftJoin(sd).on(cs.SERIES_ID.eq(sd.SERIES_ID)) } .where(cs.COLLECTION_ID.eq(cr.id)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } @@ -184,7 +198,8 @@ class SeriesCollectionDao( @Transactional override fun insert(collection: SeriesCollection) { - dsl.insertInto(c) + dsl + .insertInto(c) .set(c.ID, collection.id) .set(c.NAME, collection.name) .set(c.ORDERED, collection.ordered) @@ -196,7 +211,8 @@ class SeriesCollectionDao( private fun insertSeries(collection: SeriesCollection) { collection.seriesIds.forEachIndexed { index, id -> - dsl.insertInto(cs) + dsl + .insertInto(cs) .set(cs.COLLECTION_ID, collection.id) .set(cs.SERIES_ID, id) .set(cs.NUMBER, index) @@ -206,7 +222,8 @@ class SeriesCollectionDao( @Transactional override fun update(collection: SeriesCollection) { - dsl.update(c) + dsl + .update(c) .set(c.NAME, collection.name) .set(c.ORDERED, collection.ordered) .set(c.SERIES_COUNT, collection.seriesIds.size) @@ -221,7 +238,8 @@ class SeriesCollectionDao( @Transactional override fun removeSeriesFromAll(seriesId: String) { - dsl.deleteFrom(cs) + dsl + .deleteFrom(cs) .where(cs.SERIES_ID.eq(seriesId)) .execute() } @@ -230,7 +248,8 @@ class SeriesCollectionDao( override fun removeSeriesFromAll(seriesIds: Collection) { dsl.insertTempStrings(batchSize, seriesIds) - dsl.deleteFrom(cs) + dsl + .deleteFrom(cs) .where(cs.SERIES_ID.`in`(dsl.selectTempStrings())) .execute() } @@ -255,7 +274,8 @@ class SeriesCollectionDao( override fun existsByName(name: String): Boolean = dsl.fetchExists( - dsl.selectFrom(c) + dsl + .selectFrom(c) .where(c.NAME.equalIgnoreCase(name)), ) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDao.kt index 318db6d6..cf15c7f8 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDao.kt @@ -38,18 +38,21 @@ class SeriesDao( private val bma = Tables.BOOK_METADATA_AGGREGATION override fun findAll(): Collection = - dsl.selectFrom(s) + dsl + .selectFrom(s) .fetchInto(s) .map { it.toDomain() } override fun findByIdOrNull(seriesId: String): Series? = - dsl.selectFrom(s) + dsl + .selectFrom(s) .where(s.ID.eq(seriesId)) .fetchOneInto(s) ?.toDomain() override fun findAllByLibraryId(libraryId: String): List = - dsl.selectFrom(s) + dsl + .selectFrom(s) .where(s.LIBRARY_ID.eq(libraryId)) .fetchInto(s) .map { it.toDomain() } @@ -61,7 +64,8 @@ class SeriesDao( ): List { dsl.insertTempStrings(batchSize, urls.map { it.toString() }) - return dsl.selectFrom(s) + return dsl + .selectFrom(s) .where(s.LIBRARY_ID.eq(libraryId)) .and(s.DELETED_DATE.isNull) .and(s.URL.notIn(dsl.selectTempStrings())) @@ -73,7 +77,8 @@ class SeriesDao( libraryId: String, url: URL, ): Series? = - dsl.selectFrom(s) + dsl + .selectFrom(s) .where(s.LIBRARY_ID.eq(libraryId).and(s.URL.eq(url.toString()))) .and(s.DELETED_DATE.isNull) .orderBy(s.LAST_MODIFIED_DATE.desc()) @@ -82,21 +87,25 @@ class SeriesDao( ?.toDomain() override fun findAllByTitleContaining(title: String): Collection = - dsl.selectDistinct(*s.fields()) + dsl + .selectDistinct(*s.fields()) .from(s) - .leftJoin(d).on(s.ID.eq(d.SERIES_ID)) + .leftJoin(d) + .on(s.ID.eq(d.SERIES_ID)) .where(d.TITLE.containsIgnoreCase(title)) .fetchInto(s) .map { it.toDomain() } override fun getLibraryId(seriesId: String): String? = - dsl.select(s.LIBRARY_ID) + dsl + .select(s.LIBRARY_ID) .from(s) .where(s.ID.eq(seriesId)) .fetchOne(0, String::class.java) override fun findAllIdsByLibraryId(libraryId: String): Collection = - dsl.select(s.ID) + dsl + .select(s.ID) .from(s) .where(s.LIBRARY_ID.eq(libraryId)) .fetch(s.ID) @@ -116,7 +125,8 @@ class SeriesDao( pageable: Pageable, ): Page { val query = - dsl.selectDistinct(*s.fields()) + dsl + .selectDistinct(*s.fields()) .from(s) .apply { joins.forEach { join -> @@ -129,8 +139,7 @@ class SeriesDao( RequiredJoin.Media -> Unit } } - } - .where(conditions) + }.where(conditions) val count = dsl.fetchCount(query) val items = @@ -150,7 +159,8 @@ class SeriesDao( } override fun insert(series: Series) { - dsl.insertInto(s) + dsl + .insertInto(s) .set(s.ID, series.id) .set(s.NAME, series.name) .set(s.URL, series.url.toString()) @@ -165,7 +175,8 @@ class SeriesDao( series: Series, updateModifiedTime: Boolean, ) { - dsl.update(s) + dsl + .update(s) .set(s.NAME, series.name) .set(s.URL, series.url.toString()) .set(s.FILE_LAST_MODIFIED, series.fileLastModified) @@ -196,7 +207,8 @@ class SeriesDao( override fun count(): Long = dsl.fetchCount(s).toLong() override fun countGroupedByLibraryId(): Map = - dsl.select(s.LIBRARY_ID, DSL.count(s.ID)) + dsl + .select(s.LIBRARY_ID, DSL.count(s.ID)) .from(s) .groupBy(s.LIBRARY_ID) .fetchMap(s.LIBRARY_ID, DSL.count(s.ID)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDao.kt index e5644197..ac39b5ed 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDao.kt @@ -95,8 +95,7 @@ class SeriesDtoDao( "booksCount" to s.BOOK_COUNT, ) - override fun findAll(pageable: Pageable): Page = - findAll(SeriesSearch(), SearchContext.ofAnonymousUser(), pageable) + override fun findAll(pageable: Pageable): Page = findAll(SeriesSearch(), SearchContext.ofAnonymousUser(), pageable) override fun findAll( context: SearchContext, @@ -142,11 +141,16 @@ class SeriesDtoDao( val searchCondition = s.ID.inOrNoCondition(seriesIds) val firstChar = lower(substring(d.TITLE_SORT, 1, 1)) - return dsl.select(firstChar, count()) + return dsl + .select(firstChar, count()) .from(s) - .leftJoin(d).on(s.ID.eq(d.SERIES_ID)) - .leftJoin(bma).on(s.ID.eq(bma.SERIES_ID)) - .leftJoin(rs).on(s.ID.eq(rs.SERIES_ID)).and(readProgressConditionSeries(context.userId)) + .leftJoin(d) + .on(s.ID.eq(d.SERIES_ID)) + .leftJoin(bma) + .on(s.ID.eq(bma.SERIES_ID)) + .leftJoin(rs) + .on(s.ID.eq(rs.SERIES_ID)) + .and(readProgressConditionSeries(context.userId)) .apply { joins.forEach { join -> when (join) { @@ -159,8 +163,7 @@ class SeriesDtoDao( RequiredJoin.BookMetadataAggregation -> Unit } } - } - .where(conditionsRefined) + }.where(conditionsRefined) .and(searchCondition) .groupBy(firstChar) .map { @@ -186,9 +189,13 @@ class SeriesDtoDao( dsl .let { if (joinOnCollection) it.selectDistinct(*groupFields) else it.select(*groupFields) } .from(s) - .leftJoin(d).on(s.ID.eq(d.SERIES_ID)) - .leftJoin(bma).on(s.ID.eq(bma.SERIES_ID)) - .leftJoin(rs).on(s.ID.eq(rs.SERIES_ID)).and(readProgressConditionSeries(userId)) + .leftJoin(d) + .on(s.ID.eq(d.SERIES_ID)) + .leftJoin(bma) + .on(s.ID.eq(bma.SERIES_ID)) + .leftJoin(rs) + .on(s.ID.eq(rs.SERIES_ID)) + .and(readProgressConditionSeries(userId)) .apply { if (joinOnCollection)leftJoin(cs).on(s.ID.eq(cs.SERIES_ID)) joins.forEach { join -> @@ -215,11 +222,16 @@ class SeriesDtoDao( val searchCondition = s.ID.inOrNoCondition(seriesIds) val count = - dsl.select(countDistinct(s.ID)) + dsl + .select(countDistinct(s.ID)) .from(s) - .leftJoin(d).on(s.ID.eq(d.SERIES_ID)) - .leftJoin(bma).on(s.ID.eq(bma.SERIES_ID)) - .leftJoin(rs).on(s.ID.eq(rs.SERIES_ID)).and(readProgressConditionSeries(userId)) + .leftJoin(d) + .on(s.ID.eq(d.SERIES_ID)) + .leftJoin(bma) + .on(s.ID.eq(bma.SERIES_ID)) + .leftJoin(rs) + .on(s.ID.eq(rs.SERIES_ID)) + .and(readProgressConditionSeries(userId)) .apply { joins.forEach { join -> when (join) { @@ -232,8 +244,7 @@ class SeriesDtoDao( RequiredJoin.Media -> Unit } } - } - .where(conditions) + }.where(conditions) .and(searchCondition) .fetchOne(countDistinct(s.ID)) ?: 0 @@ -280,38 +291,45 @@ class SeriesDtoDao( transactionTemplate.executeWithoutResult { dsl.insertTempStrings(batchSize, seriesIds) genres = - dsl.selectFrom(g) + dsl + .selectFrom(g) .where(g.SERIES_ID.`in`(dsl.selectTempStrings())) .groupBy({ it.seriesId }, { it.genre }) tags = - dsl.selectFrom(st) + dsl + .selectFrom(st) .where(st.SERIES_ID.`in`(dsl.selectTempStrings())) .groupBy({ it.seriesId }, { it.tag }) sharingLabels = - dsl.selectFrom(sl) + dsl + .selectFrom(sl) .where(sl.SERIES_ID.`in`(dsl.selectTempStrings())) .groupBy({ it.seriesId }, { it.label }) links = - dsl.selectFrom(slk) + dsl + .selectFrom(slk) .where(slk.SERIES_ID.`in`(dsl.selectTempStrings())) .groupBy({ it.seriesId }, { WebLinkDto(it.label, it.url) }) alternateTitles = - dsl.selectFrom(sat) + dsl + .selectFrom(sat) .where(sat.SERIES_ID.`in`(dsl.selectTempStrings())) .groupBy({ it.seriesId }, { AlternateTitleDto(it.label, it.title) }) aggregatedAuthors = - dsl.selectFrom(bmaa) + dsl + .selectFrom(bmaa) .where(bmaa.SERIES_ID.`in`(dsl.selectTempStrings())) .filter { it.name != null } .groupBy({ it.seriesId }, { AuthorDto(it.name, it.role) }) aggregatedTags = - dsl.selectFrom(bmat) + dsl + .selectFrom(bmat) .where(bmat.SERIES_ID.`in`(dsl.selectTempStrings())) .groupBy({ it.seriesId }, { it.tag }) } @@ -350,24 +368,23 @@ class SeriesDtoDao( booksInProgressCount: Int, metadata: SeriesMetadataDto, booksMetadata: BookMetadataAggregationDto, - ) = - SeriesDto( - id = id, - libraryId = libraryId, - name = name, - url = URL(url).toFilePath(), - created = createdDate, - lastModified = lastModifiedDate, - fileLastModified = fileLastModified, - booksCount = booksCount, - booksReadCount = booksReadCount, - booksUnreadCount = booksUnreadCount, - booksInProgressCount = booksInProgressCount, - metadata = metadata, - booksMetadata = booksMetadata, - deleted = deletedDate != null, - oneshot = oneshot, - ) + ) = SeriesDto( + id = id, + libraryId = libraryId, + name = name, + url = URL(url).toFilePath(), + created = createdDate, + lastModified = lastModifiedDate, + fileLastModified = fileLastModified, + booksCount = booksCount, + booksReadCount = booksReadCount, + booksUnreadCount = booksUnreadCount, + booksInProgressCount = booksInProgressCount, + metadata = metadata, + booksMetadata = booksMetadata, + deleted = deletedDate != null, + oneshot = oneshot, + ) private fun SeriesMetadataRecord.toDto( genres: Set, @@ -375,51 +392,49 @@ class SeriesDtoDao( sharingLabels: Set, links: List, alternateTitles: List, - ) = - SeriesMetadataDto( - status = status, - statusLock = statusLock, - created = createdDate, - lastModified = lastModifiedDate, - title = title, - titleLock = titleLock, - titleSort = titleSort, - titleSortLock = titleSortLock, - summary = summary, - summaryLock = summaryLock, - readingDirection = readingDirection ?: "", - readingDirectionLock = readingDirectionLock, - publisher = publisher, - publisherLock = publisherLock, - ageRating = ageRating, - ageRatingLock = ageRatingLock, - language = language, - languageLock = languageLock, - genres = genres, - genresLock = genresLock, - tags = tags, - tagsLock = tagsLock, - totalBookCount = totalBookCount, - totalBookCountLock = totalBookCountLock, - sharingLabels = sharingLabels, - sharingLabelsLock = sharingLabelsLock, - links = links, - linksLock = linksLock, - alternateTitles = alternateTitles, - alternateTitlesLock = alternateTitlesLock, - ) + ) = SeriesMetadataDto( + status = status, + statusLock = statusLock, + created = createdDate, + lastModified = lastModifiedDate, + title = title, + titleLock = titleLock, + titleSort = titleSort, + titleSortLock = titleSortLock, + summary = summary, + summaryLock = summaryLock, + readingDirection = readingDirection ?: "", + readingDirectionLock = readingDirectionLock, + publisher = publisher, + publisherLock = publisherLock, + ageRating = ageRating, + ageRatingLock = ageRatingLock, + language = language, + languageLock = languageLock, + genres = genres, + genresLock = genresLock, + tags = tags, + tagsLock = tagsLock, + totalBookCount = totalBookCount, + totalBookCountLock = totalBookCountLock, + sharingLabels = sharingLabels, + sharingLabelsLock = sharingLabelsLock, + links = links, + linksLock = linksLock, + alternateTitles = alternateTitles, + alternateTitlesLock = alternateTitlesLock, + ) private fun BookMetadataAggregationRecord.toDto( authors: List, tags: Set, - ) = - BookMetadataAggregationDto( - authors = authors, - tags = tags, - releaseDate = releaseDate, - summary = summary, - summaryNumber = summaryNumber, - created = createdDate, - lastModified = lastModifiedDate, - ) + ) = BookMetadataAggregationDto( + authors = authors, + tags = tags, + releaseDate = releaseDate, + summary = summary, + summaryNumber = summaryNumber, + created = createdDate, + lastModified = lastModifiedDate, + ) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesMetadataDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesMetadataDao.kt index d336700b..12ecc851 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesMetadataDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesMetadataDao.kt @@ -29,44 +29,48 @@ class SeriesMetadataDao( private val slk = Tables.SERIES_METADATA_LINK private val sat = Tables.SERIES_METADATA_ALTERNATE_TITLE - override fun findById(seriesId: String): SeriesMetadata = - findOne(seriesId)!!.toDomain(findGenres(seriesId), findTags(seriesId), findSharingLabels(seriesId), findLinks(seriesId), findAlternateTitles(seriesId)) + override fun findById(seriesId: String): SeriesMetadata = findOne(seriesId)!!.toDomain(findGenres(seriesId), findTags(seriesId), findSharingLabels(seriesId), findLinks(seriesId), findAlternateTitles(seriesId)) - override fun findByIdOrNull(seriesId: String): SeriesMetadata? = - findOne(seriesId)?.toDomain(findGenres(seriesId), findTags(seriesId), findSharingLabels(seriesId), findLinks(seriesId), findAlternateTitles(seriesId)) + override fun findByIdOrNull(seriesId: String): SeriesMetadata? = findOne(seriesId)?.toDomain(findGenres(seriesId), findTags(seriesId), findSharingLabels(seriesId), findLinks(seriesId), findAlternateTitles(seriesId)) private fun findOne(seriesId: String) = - dsl.selectFrom(d) + dsl + .selectFrom(d) .where(d.SERIES_ID.eq(seriesId)) .fetchOneInto(d) private fun findGenres(seriesId: String) = - dsl.select(g.GENRE) + dsl + .select(g.GENRE) .from(g) .where(g.SERIES_ID.eq(seriesId)) .fetchSet(g.GENRE) private fun findTags(seriesId: String) = - dsl.select(st.TAG) + dsl + .select(st.TAG) .from(st) .where(st.SERIES_ID.eq(seriesId)) .fetchSet(st.TAG) private fun findSharingLabels(seriesId: String) = - dsl.select(sl.LABEL) + dsl + .select(sl.LABEL) .from(sl) .where(sl.SERIES_ID.eq(seriesId)) .fetchSet(sl.LABEL) private fun findLinks(seriesId: String) = - dsl.select(slk.LABEL, slk.URL) + dsl + .select(slk.LABEL, slk.URL) .from(slk) .where(slk.SERIES_ID.eq(seriesId)) .fetchInto(slk) .map { WebLink(it.label, URI(it.url)) } private fun findAlternateTitles(seriesId: String) = - dsl.select(sat.LABEL, sat.TITLE) + dsl + .select(sat.LABEL, sat.TITLE) .from(sat) .where(sat.SERIES_ID.eq(seriesId)) .fetchInto(sat) @@ -74,7 +78,8 @@ class SeriesMetadataDao( @Transactional override fun insert(metadata: SeriesMetadata) { - dsl.insertInto(d) + dsl + .insertInto(d) .set(d.SERIES_ID, metadata.seriesId) .set(d.STATUS, metadata.status.toString()) .set(d.TITLE, metadata.title) @@ -110,7 +115,8 @@ class SeriesMetadataDao( @Transactional override fun update(metadata: SeriesMetadata) { - dsl.update(d) + dsl + .update(d) .set(d.STATUS, metadata.status.toString()) .set(d.TITLE, metadata.title) .set(d.TITLE_SORT, metadata.titleSort) @@ -138,23 +144,28 @@ class SeriesMetadataDao( .where(d.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl.deleteFrom(g) + dsl + .deleteFrom(g) .where(g.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl.deleteFrom(st) + dsl + .deleteFrom(st) .where(st.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl.deleteFrom(sl) + dsl + .deleteFrom(sl) .where(sl.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl.deleteFrom(slk) + dsl + .deleteFrom(slk) .where(slk.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl.deleteFrom(sat) + dsl + .deleteFrom(sat) .where(sat.SERIES_ID.eq(metadata.seriesId)) .execute() @@ -168,14 +179,16 @@ class SeriesMetadataDao( private fun insertGenres(metadata: SeriesMetadata) { if (metadata.genres.isNotEmpty()) { metadata.genres.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(g, g.SERIES_ID, g.GENRE) - .values(null as String?, null), - ).also { step -> - chunk.forEach { - step.bind(metadata.seriesId, it) - } - }.execute() + dsl + .batch( + dsl + .insertInto(g, g.SERIES_ID, g.GENRE) + .values(null as String?, null), + ).also { step -> + chunk.forEach { + step.bind(metadata.seriesId, it) + } + }.execute() } } } @@ -183,14 +196,16 @@ class SeriesMetadataDao( private fun insertTags(metadata: SeriesMetadata) { if (metadata.tags.isNotEmpty()) { metadata.tags.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(st, st.SERIES_ID, st.TAG) - .values(null as String?, null), - ).also { step -> - chunk.forEach { - step.bind(metadata.seriesId, it) - } - }.execute() + dsl + .batch( + dsl + .insertInto(st, st.SERIES_ID, st.TAG) + .values(null as String?, null), + ).also { step -> + chunk.forEach { + step.bind(metadata.seriesId, it) + } + }.execute() } } } @@ -198,14 +213,16 @@ class SeriesMetadataDao( private fun insertSharingLabels(metadata: SeriesMetadata) { if (metadata.sharingLabels.isNotEmpty()) { metadata.sharingLabels.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(sl, sl.SERIES_ID, sl.LABEL) - .values(null as String?, null), - ).also { step -> - chunk.forEach { - step.bind(metadata.seriesId, it) - } - }.execute() + dsl + .batch( + dsl + .insertInto(sl, sl.SERIES_ID, sl.LABEL) + .values(null as String?, null), + ).also { step -> + chunk.forEach { + step.bind(metadata.seriesId, it) + } + }.execute() } } } @@ -213,14 +230,16 @@ class SeriesMetadataDao( private fun insertLinks(metadata: SeriesMetadata) { if (metadata.links.isNotEmpty()) { metadata.links.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(slk, slk.SERIES_ID, slk.LABEL, slk.URL) - .values(null as String?, null, null), - ).also { step -> - chunk.forEach { - step.bind(metadata.seriesId, it.label, it.url.toString()) - } - }.execute() + dsl + .batch( + dsl + .insertInto(slk, slk.SERIES_ID, slk.LABEL, slk.URL) + .values(null as String?, null, null), + ).also { step -> + chunk.forEach { + step.bind(metadata.seriesId, it.label, it.url.toString()) + } + }.execute() } } } @@ -228,14 +247,16 @@ class SeriesMetadataDao( private fun insertAlternateTitles(metadata: SeriesMetadata) { if (metadata.alternateTitles.isNotEmpty()) { metadata.alternateTitles.chunked(batchSize).forEach { chunk -> - dsl.batch( - dsl.insertInto(sat, sat.SERIES_ID, sat.LABEL, sat.TITLE) - .values(null as String?, null, null), - ).also { step -> - chunk.forEach { - step.bind(metadata.seriesId, it.label, it.title) - } - }.execute() + dsl + .batch( + dsl + .insertInto(sat, sat.SERIES_ID, sat.LABEL, sat.TITLE) + .values(null as String?, null, null), + ).also { step -> + chunk.forEach { + step.bind(metadata.seriesId, it.label, it.title) + } + }.execute() } } } @@ -270,41 +291,40 @@ class SeriesMetadataDao( sharingLabels: Set, links: List, alternateTitles: List, - ) = - SeriesMetadata( - status = SeriesMetadata.Status.valueOf(status), - title = title, - titleSort = titleSort, - summary = summary, - readingDirection = - readingDirection?.let { - SeriesMetadata.ReadingDirection.valueOf(readingDirection) - }, - publisher = publisher, - ageRating = ageRating, - language = language, - genres = genres, - tags = tags, - totalBookCount = totalBookCount, - sharingLabels = sharingLabels, - links = links, - alternateTitles = alternateTitles, - statusLock = statusLock, - titleLock = titleLock, - titleSortLock = titleSortLock, - summaryLock = summaryLock, - readingDirectionLock = readingDirectionLock, - publisherLock = publisherLock, - ageRatingLock = ageRatingLock, - languageLock = languageLock, - genresLock = genresLock, - tagsLock = tagsLock, - totalBookCountLock = totalBookCountLock, - sharingLabelsLock = sharingLabelsLock, - linksLock = linksLock, - alternateTitlesLock = alternateTitlesLock, - seriesId = seriesId, - createdDate = createdDate.toCurrentTimeZone(), - lastModifiedDate = lastModifiedDate.toCurrentTimeZone(), - ) + ) = SeriesMetadata( + status = SeriesMetadata.Status.valueOf(status), + title = title, + titleSort = titleSort, + summary = summary, + readingDirection = + readingDirection?.let { + SeriesMetadata.ReadingDirection.valueOf(readingDirection) + }, + publisher = publisher, + ageRating = ageRating, + language = language, + genres = genres, + tags = tags, + totalBookCount = totalBookCount, + sharingLabels = sharingLabels, + links = links, + alternateTitles = alternateTitles, + statusLock = statusLock, + titleLock = titleLock, + titleSortLock = titleSortLock, + summaryLock = summaryLock, + readingDirectionLock = readingDirectionLock, + publisherLock = publisherLock, + ageRatingLock = ageRatingLock, + languageLock = languageLock, + genresLock = genresLock, + tagsLock = tagsLock, + totalBookCountLock = totalBookCountLock, + sharingLabelsLock = sharingLabelsLock, + linksLock = linksLock, + alternateTitlesLock = alternateTitlesLock, + seriesId = seriesId, + createdDate = createdDate.toCurrentTimeZone(), + lastModifiedDate = lastModifiedDate.toCurrentTimeZone(), + ) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ServerSettingsDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ServerSettingsDao.kt index e6138b3f..92dbf5e7 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ServerSettingsDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ServerSettingsDao.kt @@ -14,7 +14,8 @@ class ServerSettingsDao( key: String, clazz: Class, ): T? = - dsl.select(s.VALUE) + dsl + .select(s.VALUE) .from(s) .where(s.KEY.eq(key)) .fetchOneInto(clazz) @@ -23,7 +24,8 @@ class ServerSettingsDao( key: String, value: String, ) { - dsl.insertInto(s) + dsl + .insertInto(s) .values(key, value) .onDuplicateKeyUpdate() .set(s.VALUE, value) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SidecarDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SidecarDao.kt index 0746c35f..9a602496 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SidecarDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SidecarDao.kt @@ -22,21 +22,20 @@ class SidecarDao( private val sc = Tables.SIDECAR private val l = Tables.LIBRARY - override fun findAll(): Collection = - dsl.selectFrom(sc).fetch().map { it.toDomain() } + override fun findAll(): Collection = dsl.selectFrom(sc).fetch().map { it.toDomain() } override fun save( libraryId: String, sidecar: Sidecar, ) { - dsl.insertInto(sc) + dsl + .insertInto(sc) .values( sidecar.url.toString(), sidecar.parentUrl.toString(), sidecar.lastModifiedTime, libraryId, - ) - .onDuplicateKeyUpdate() + ).onDuplicateKeyUpdate() .set(sc.LAST_MODIFIED_TIME, sidecar.lastModifiedTime) .set(sc.PARENT_URL, sidecar.parentUrl.toString()) .set(sc.LIBRARY_ID, libraryId) @@ -50,20 +49,23 @@ class SidecarDao( ) { dsl.insertTempStrings(batchSize, urls.map { it.toString() }) - dsl.deleteFrom(sc) + dsl + .deleteFrom(sc) .where(sc.LIBRARY_ID.eq(libraryId)) .and(sc.URL.`in`(dsl.selectTempStrings())) .execute() } override fun deleteByLibraryId(libraryId: String) { - dsl.deleteFrom(sc) + dsl + .deleteFrom(sc) .where(sc.LIBRARY_ID.eq(libraryId)) .execute() } override fun countGroupedByLibraryId(): Map = - dsl.select(sc.LIBRARY_ID, DSL.count(sc.URL)) + dsl + .select(sc.LIBRARY_ID, DSL.count(sc.URL)) .from(sc) .groupBy(sc.LIBRARY_ID) .fetchMap(sc.LIBRARY_ID, DSL.count(sc.URL)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SyncPointDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SyncPointDao.kt index efa7726b..7fa499d4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SyncPointDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SyncPointDao.kt @@ -56,63 +56,72 @@ class SyncPointDao( val syncPointId = TsidCreator.getTsid256().toString() val createdAt = LocalDateTime.now(ZoneId.of("Z")) - dsl.insertInto( - sp, - sp.ID, - sp.USER_ID, - sp.API_KEY_ID, - sp.CREATED_DATE, - ).values( - syncPointId, - context.userId, - apiKeyId, - createdAt, - ).execute() + dsl + .insertInto( + sp, + sp.ID, + sp.USER_ID, + sp.API_KEY_ID, + sp.CREATED_DATE, + ).values( + syncPointId, + context.userId, + apiKeyId, + createdAt, + ).execute() - dsl.insertInto( - spb, - spb.SYNC_POINT_ID, - spb.BOOK_ID, - spb.BOOK_CREATED_DATE, - spb.BOOK_LAST_MODIFIED_DATE, - spb.BOOK_FILE_LAST_MODIFIED, - spb.BOOK_FILE_SIZE, - spb.BOOK_FILE_HASH, - spb.BOOK_METADATA_LAST_MODIFIED_DATE, - spb.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE, - spb.BOOK_THUMBNAIL_ID, - ).select( - dsl.select( - DSL.`val`(syncPointId), - b.ID, - b.CREATED_DATE, - b.LAST_MODIFIED_DATE, - b.FILE_LAST_MODIFIED, - b.FILE_SIZE, - b.FILE_HASH, - d.LAST_MODIFIED_DATE, - r.LAST_MODIFIED_DATE, - bt.ID, - ).from(b) - .apply { - joins.forEach { - when (it) { - // we don't have to handle those since we already join on those tables anyway, the 'when' is here for future proofing - RequiredJoin.BookMetadata -> Unit - RequiredJoin.SeriesMetadata -> Unit - RequiredJoin.Media -> Unit - is RequiredJoin.ReadProgress -> Unit - RequiredJoin.BookMetadataAggregation -> Unit + dsl + .insertInto( + spb, + spb.SYNC_POINT_ID, + spb.BOOK_ID, + spb.BOOK_CREATED_DATE, + spb.BOOK_LAST_MODIFIED_DATE, + spb.BOOK_FILE_LAST_MODIFIED, + spb.BOOK_FILE_SIZE, + spb.BOOK_FILE_HASH, + spb.BOOK_METADATA_LAST_MODIFIED_DATE, + spb.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE, + spb.BOOK_THUMBNAIL_ID, + ).select( + dsl + .select( + DSL.`val`(syncPointId), + b.ID, + b.CREATED_DATE, + b.LAST_MODIFIED_DATE, + b.FILE_LAST_MODIFIED, + b.FILE_SIZE, + b.FILE_HASH, + d.LAST_MODIFIED_DATE, + r.LAST_MODIFIED_DATE, + bt.ID, + ).from(b) + .apply { + joins.forEach { + when (it) { + // we don't have to handle those since we already join on those tables anyway, the 'when' is here for future proofing + RequiredJoin.BookMetadata -> Unit + RequiredJoin.SeriesMetadata -> Unit + RequiredJoin.Media -> Unit + is RequiredJoin.ReadProgress -> Unit + RequiredJoin.BookMetadataAggregation -> Unit + } } - } - } - .join(m).on(b.ID.eq(m.BOOK_ID)) - .join(d).on(b.ID.eq(d.BOOK_ID)) - .join(sd).on(b.SERIES_ID.eq(sd.SERIES_ID)) - .leftJoin(r).on(b.ID.eq(r.BOOK_ID)).and(r.USER_ID.eq(context.userId)) - .leftJoin(bt).on(b.ID.eq(bt.BOOK_ID)).and(bt.SELECTED.isTrue) - .where(condition), - ).execute() + }.join(m) + .on(b.ID.eq(m.BOOK_ID)) + .join(d) + .on(b.ID.eq(d.BOOK_ID)) + .join(sd) + .on(b.SERIES_ID.eq(sd.SERIES_ID)) + .leftJoin(r) + .on(b.ID.eq(r.BOOK_ID)) + .and(r.USER_ID.eq(context.userId)) + .leftJoin(bt) + .on(b.ID.eq(bt.BOOK_ID)) + .and(bt.SELECTED.isTrue) + .where(condition), + ).execute() return findByIdOrNull(syncPointId)!! } @@ -131,7 +140,8 @@ class SyncPointDao( val (query, _, queryMostRecentDate) = bookCommonDao.getBooksOnDeckQuery(context.userId, context.restrictions, filterOnLibraryIds, onDeckFields) val count = - dsl.insertInto(sprlb) + dsl + .insertInto(sprlb) .select(query) .execute() @@ -139,25 +149,27 @@ class SyncPointDao( if (count > 0) { val mostRecentDate = dsl.fetch(queryMostRecentDate).into(LocalDateTime::class.java).firstOrNull() ?: createdAt - dsl.insertInto( - sprl, - sprl.SYNC_POINT_ID, - sprl.READLIST_ID, - sprl.READLIST_NAME, - sprl.READLIST_CREATED_DATE, - sprl.READLIST_LAST_MODIFIED_DATE, - ).values( - syncPointId, - ON_DECK_ID, - "On Deck", - createdAt, - mostRecentDate, - ).execute() + dsl + .insertInto( + sprl, + sprl.SYNC_POINT_ID, + sprl.READLIST_ID, + sprl.READLIST_NAME, + sprl.READLIST_CREATED_DATE, + sprl.READLIST_LAST_MODIFIED_DATE, + ).values( + syncPointId, + ON_DECK_ID, + "On Deck", + createdAt, + mostRecentDate, + ).execute() } } override fun findByIdOrNull(syncPointId: String): SyncPoint? = - dsl.selectFrom(sp) + dsl + .selectFrom(sp) .where(sp.ID.eq(syncPointId)) .fetchInto(sp) .map { @@ -175,7 +187,8 @@ class SyncPointDao( pageable: Pageable, ): Page { val query = - dsl.selectFrom(spb) + dsl + .selectFrom(spb) .where(spb.SYNC_POINT_ID.eq(syncPointId)) .apply { if (onlyNotSynced) { @@ -193,14 +206,14 @@ class SyncPointDao( pageable: Pageable, ): Page { val query = - dsl.selectFrom(spb) + dsl + .selectFrom(spb) .where(spb.SYNC_POINT_ID.eq(toSyncPointId)) .apply { if (onlyNotSynced) { and(spb.SYNCED.isFalse) } - } - .and( + }.and( spb.BOOK_ID.notIn( dsl.select(spb.BOOK_ID).from(spb).where(spb.SYNC_POINT_ID.eq(fromSyncPointId)), ), @@ -216,14 +229,14 @@ class SyncPointDao( pageable: Pageable, ): Page { val query = - dsl.selectFrom(spb) + dsl + .selectFrom(spb) .where(spb.SYNC_POINT_ID.eq(fromSyncPointId)) .and( spb.BOOK_ID.notIn( dsl.select(spb.BOOK_ID).from(spb).where(spb.SYNC_POINT_ID.eq(toSyncPointId)), ), - ) - .apply { + ).apply { if (onlyNotSynced) and( spb.BOOK_ID.notIn( @@ -243,18 +256,20 @@ class SyncPointDao( ): Page { val spbFrom = spb.`as`("spbFrom") val query = - dsl.select(*spb.fields()) + dsl + .select(*spb.fields()) .from(spb) - .join(spbFrom).on(spb.BOOK_ID.eq(spbFrom.BOOK_ID)) + .join(spbFrom) + .on(spb.BOOK_ID.eq(spbFrom.BOOK_ID)) .where(spb.SYNC_POINT_ID.eq(toSyncPointId)) .and(spbFrom.SYNC_POINT_ID.eq(fromSyncPointId)) .apply { if (onlyNotSynced) { and(spb.SYNCED.isFalse) } - } - .and( - spb.BOOK_FILE_LAST_MODIFIED.ne(spbFrom.BOOK_FILE_LAST_MODIFIED) + }.and( + spb.BOOK_FILE_LAST_MODIFIED + .ne(spbFrom.BOOK_FILE_LAST_MODIFIED) .or(spb.BOOK_FILE_SIZE.ne(spbFrom.BOOK_FILE_SIZE)) .or(spb.BOOK_FILE_HASH.ne(spbFrom.BOOK_FILE_HASH).and(spbFrom.BOOK_FILE_HASH.isNotNull)) .or(spb.BOOK_METADATA_LAST_MODIFIED_DATE.ne(spbFrom.BOOK_METADATA_LAST_MODIFIED_DATE)) @@ -272,26 +287,29 @@ class SyncPointDao( ): Page { val spbFrom = spb.`as`("spbFrom") val query = - dsl.select(*spb.fields()) + dsl + .select(*spb.fields()) .from(spb) - .join(spbFrom).on(spb.BOOK_ID.eq(spbFrom.BOOK_ID)) + .join(spbFrom) + .on(spb.BOOK_ID.eq(spbFrom.BOOK_ID)) .where(spb.SYNC_POINT_ID.eq(toSyncPointId)) .and(spbFrom.SYNC_POINT_ID.eq(fromSyncPointId)) .apply { if (onlyNotSynced) { and(spb.SYNCED.isFalse) } - } - .and( + }.and( // unchanged book - spb.BOOK_FILE_LAST_MODIFIED.eq(spbFrom.BOOK_FILE_LAST_MODIFIED) + spb.BOOK_FILE_LAST_MODIFIED + .eq(spbFrom.BOOK_FILE_LAST_MODIFIED) .and(spb.BOOK_FILE_SIZE.eq(spbFrom.BOOK_FILE_SIZE)) .and(spb.BOOK_FILE_HASH.eq(spbFrom.BOOK_FILE_HASH).or(spbFrom.BOOK_FILE_HASH.isNull)) .and(spb.BOOK_METADATA_LAST_MODIFIED_DATE.eq(spbFrom.BOOK_METADATA_LAST_MODIFIED_DATE)) .and(spb.BOOK_THUMBNAIL_ID.eq(spbFrom.BOOK_THUMBNAIL_ID)) // with changed read progress .and( - spb.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE.ne(spbFrom.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE) + spb.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE + .ne(spbFrom.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE) .or(spb.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE.isNull.and(spbFrom.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE.isNotNull)) .or(spb.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE.isNotNull.and(spbFrom.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE.isNull)), ), @@ -306,7 +324,8 @@ class SyncPointDao( pageable: Pageable, ): Page { val query = - dsl.selectFrom(sprl) + dsl + .selectFrom(sprl) .where(sprl.SYNC_POINT_ID.eq(syncPointId)) .apply { if (onlyNotSynced) { @@ -326,9 +345,11 @@ class SyncPointDao( val to = sprl.`as`("to") val from = sprl.`as`("from") val query = - dsl.select(*to.fields()) + dsl + .select(*to.fields()) .from(to) - .leftOuterJoin(from).on(to.READLIST_ID.eq(from.READLIST_ID).and(from.SYNC_POINT_ID.eq(fromSyncPointId))) + .leftOuterJoin(from) + .on(to.READLIST_ID.eq(from.READLIST_ID).and(from.SYNC_POINT_ID.eq(fromSyncPointId))) .where(to.SYNC_POINT_ID.eq(toSyncPointId)) .apply { if (onlyNotSynced) and(to.SYNCED.isFalse) } .and(from.READLIST_ID.isNull) @@ -344,14 +365,17 @@ class SyncPointDao( ): Page { val from = sprl.`as`("from") val query = - dsl.select(*sprl.fields()) + dsl + .select(*sprl.fields()) .from(sprl) - .join(from).on(sprl.READLIST_ID.eq(from.READLIST_ID)) + .join(from) + .on(sprl.READLIST_ID.eq(from.READLIST_ID)) .where(sprl.SYNC_POINT_ID.eq(toSyncPointId)) .and(from.SYNC_POINT_ID.eq(fromSyncPointId)) .apply { if (onlyNotSynced) and(sprl.SYNCED.isFalse) } .and( - sprl.READLIST_LAST_MODIFIED_DATE.ne(from.READLIST_LAST_MODIFIED_DATE) + sprl.READLIST_LAST_MODIFIED_DATE + .ne(from.READLIST_LAST_MODIFIED_DATE) .or(sprl.READLIST_NAME.ne(from.READLIST_NAME)), ) @@ -367,9 +391,11 @@ class SyncPointDao( val from = sprl.`as`("from") val to = sprl.`as`("to") val query = - dsl.select(*from.fields()) + dsl + .select(*from.fields()) .from(from) - .leftOuterJoin(to).on(from.READLIST_ID.eq(to.READLIST_ID).and(to.SYNC_POINT_ID.eq(toSyncPointId))) + .leftOuterJoin(to) + .on(from.READLIST_ID.eq(to.READLIST_ID).and(to.SYNC_POINT_ID.eq(toSyncPointId))) .where(from.SYNC_POINT_ID.eq(fromSyncPointId)) .apply { if (onlyNotSynced) @@ -378,8 +404,7 @@ class SyncPointDao( dsl.select(sprls.READLIST_ID).from(sprls).where(sprls.SYNC_POINT_ID.eq(toSyncPointId)), ), ) - } - .and(to.READLIST_ID.isNull) + }.and(to.READLIST_ID.isNull) return queryToPageReadList(query, pageable) } @@ -388,7 +413,8 @@ class SyncPointDao( syncPointId: String, readListIds: Collection, ): List = - dsl.select(*sprlb.fields()) + dsl + .select(*sprlb.fields()) .from(sprlb) .where(sprlb.SYNC_POINT_ID.eq(syncPointId)) .and(sprlb.READLIST_ID.`in`(readListIds)) @@ -404,13 +430,15 @@ class SyncPointDao( // we store status in a separate table if (bookIds.isNotEmpty()) { if (forRemovedBooks) - dsl.batch( - dsl.insertInto(spbs, spbs.SYNC_POINT_ID, spbs.BOOK_ID).values(null as String?, null).onDuplicateKeyIgnore(), - ).also { step -> - bookIds.map { step.bind(syncPointId, it) } - }.execute() + dsl + .batch( + dsl.insertInto(spbs, spbs.SYNC_POINT_ID, spbs.BOOK_ID).values(null as String?, null).onDuplicateKeyIgnore(), + ).also { step -> + bookIds.map { step.bind(syncPointId, it) } + }.execute() else - dsl.update(spb) + dsl + .update(spb) .set(spb.SYNCED, true) .where(spb.SYNC_POINT_ID.eq(syncPointId)) .and(spb.BOOK_ID.`in`(bookIds)) @@ -427,13 +455,15 @@ class SyncPointDao( // we store status in a separate table if (readListIds.isNotEmpty()) { if (forRemovedReadLists) - dsl.batch( - dsl.insertInto(sprls, sprls.SYNC_POINT_ID, sprls.READLIST_ID).values(null as String?, null).onDuplicateKeyIgnore(), - ).also { step -> - readListIds.map { step.bind(syncPointId, it) } - }.execute() + dsl + .batch( + dsl.insertInto(sprls, sprls.SYNC_POINT_ID, sprls.READLIST_ID).values(null as String?, null).onDuplicateKeyIgnore(), + ).also { step -> + readListIds.map { step.bind(syncPointId, it) } + }.execute() else - dsl.update(sprl) + dsl + .update(sprl) .set(sprl.SYNCED, true) .where(sprl.SYNC_POINT_ID.eq(syncPointId)) .and(sprl.READLIST_ID.`in`(readListIds)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailBookDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailBookDao.kt index 83cb7865..fdc75523 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailBookDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailBookDao.kt @@ -24,7 +24,8 @@ class ThumbnailBookDao( private val tb = Tables.THUMBNAIL_BOOK override fun findAllByBookId(bookId: String): Collection = - dsl.selectFrom(tb) + dsl + .selectFrom(tb) .where(tb.BOOK_ID.eq(bookId)) .fetchInto(tb) .map { it.toDomain() } @@ -33,20 +34,23 @@ class ThumbnailBookDao( bookId: String, type: Set, ): Collection = - dsl.selectFrom(tb) + dsl + .selectFrom(tb) .where(tb.BOOK_ID.eq(bookId)) .and(tb.TYPE.`in`(type.map { it.name })) .fetchInto(tb) .map { it.toDomain() } override fun findByIdOrNull(thumbnailId: String): ThumbnailBook? = - dsl.selectFrom(tb) + dsl + .selectFrom(tb) .where(tb.ID.eq(thumbnailId)) .fetchOneInto(tb) ?.toDomain() override fun findSelectedByBookIdOrNull(bookId: String): ThumbnailBook? = - dsl.selectFrom(tb) + dsl + .selectFrom(tb) .where(tb.BOOK_ID.eq(bookId)) .and(tb.SELECTED.isTrue) .limit(1) @@ -56,7 +60,8 @@ class ThumbnailBookDao( override fun findAllWithoutMetadata(pageable: Pageable): Page { val query = - dsl.selectFrom(tb) + dsl + .selectFrom(tb) .where(tb.FILE_SIZE.eq(0)) .or(tb.MEDIA_TYPE.eq("")) .or(tb.WIDTH.eq(0)) @@ -76,7 +81,8 @@ class ThumbnailBookDao( type: ThumbnailBook.Type, size: Int, ): Collection = - dsl.select(tb.BOOK_ID) + dsl + .select(tb.BOOK_ID) .from(tb) .where(tb.TYPE.eq(type.toString())) .and(tb.WIDTH.lt(size)) @@ -86,7 +92,8 @@ class ThumbnailBookDao( override fun existsById(thumbnailId: String): Boolean = dsl.fetchExists(tb, tb.ID.eq(thumbnailId)) override fun insert(thumbnail: ThumbnailBook) { - dsl.insertInto(tb) + dsl + .insertInto(tb) .set(tb.ID, thumbnail.id) .set(tb.BOOK_ID, thumbnail.bookId) .set(tb.THUMBNAIL, thumbnail.thumbnail) @@ -101,7 +108,8 @@ class ThumbnailBookDao( } override fun update(thumbnail: ThumbnailBook) { - dsl.update(tb) + dsl + .update(tb) .set(tb.BOOK_ID, thumbnail.bookId) .set(tb.THUMBNAIL, thumbnail.thumbnail) .set(tb.URL, thumbnail.url?.toString()) @@ -118,7 +126,9 @@ class ThumbnailBookDao( override fun updateMetadata(thumbnails: Collection) { dsl.batched { c -> thumbnails.forEach { - c.dsl().update(tb) + c + .dsl() + .update(tb) .set(tb.MEDIA_TYPE, it.mediaType) .set(tb.WIDTH, it.dimension.width) .set(tb.HEIGHT, it.dimension.height) @@ -131,13 +141,15 @@ class ThumbnailBookDao( @Transactional override fun markSelected(thumbnail: ThumbnailBook) { - dsl.update(tb) + dsl + .update(tb) .set(tb.SELECTED, false) .where(tb.BOOK_ID.eq(thumbnail.bookId)) .and(tb.ID.ne(thumbnail.id)) .execute() - dsl.update(tb) + dsl + .update(tb) .set(tb.SELECTED, true) .where(tb.BOOK_ID.eq(thumbnail.bookId)) .and(tb.ID.eq(thumbnail.id)) @@ -163,7 +175,8 @@ class ThumbnailBookDao( bookId: String, type: ThumbnailBook.Type, ) { - dsl.deleteFrom(tb) + dsl + .deleteFrom(tb) .where(tb.BOOK_ID.eq(bookId)) .and(tb.TYPE.eq(type.toString())) .execute() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailReadListDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailReadListDao.kt index f603d8af..10848242 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailReadListDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailReadListDao.kt @@ -19,19 +19,22 @@ class ThumbnailReadListDao( private val tr = Tables.THUMBNAIL_READLIST override fun findAllByReadListId(readListId: String): Collection = - dsl.selectFrom(tr) + dsl + .selectFrom(tr) .where(tr.READLIST_ID.eq(readListId)) .fetchInto(tr) .map { it.toDomain() } override fun findByIdOrNull(thumbnailId: String): ThumbnailReadList? = - dsl.selectFrom(tr) + dsl + .selectFrom(tr) .where(tr.ID.eq(thumbnailId)) .fetchOneInto(tr) ?.toDomain() override fun findSelectedByReadListIdOrNull(readListId: String): ThumbnailReadList? = - dsl.selectFrom(tr) + dsl + .selectFrom(tr) .where(tr.READLIST_ID.eq(readListId)) .and(tr.SELECTED.isTrue) .limit(1) @@ -41,7 +44,8 @@ class ThumbnailReadListDao( override fun findAllWithoutMetadata(pageable: Pageable): Page { val query = - dsl.selectFrom(tr) + dsl + .selectFrom(tr) .where(tr.FILE_SIZE.eq(0)) .or(tr.MEDIA_TYPE.eq("")) .or(tr.WIDTH.eq(0)) @@ -58,7 +62,8 @@ class ThumbnailReadListDao( } override fun insert(thumbnail: ThumbnailReadList) { - dsl.insertInto(tr) + dsl + .insertInto(tr) .set(tr.ID, thumbnail.id) .set(tr.READLIST_ID, thumbnail.readListId) .set(tr.THUMBNAIL, thumbnail.thumbnail) @@ -72,7 +77,8 @@ class ThumbnailReadListDao( } override fun update(thumbnail: ThumbnailReadList) { - dsl.update(tr) + dsl + .update(tr) .set(tr.READLIST_ID, thumbnail.readListId) .set(tr.THUMBNAIL, thumbnail.thumbnail) .set(tr.SELECTED, thumbnail.selected) @@ -88,7 +94,9 @@ class ThumbnailReadListDao( override fun updateMetadata(thumbnails: Collection) { dsl.batched { c -> thumbnails.forEach { - c.dsl().update(tr) + c + .dsl() + .update(tr) .set(tr.MEDIA_TYPE, it.mediaType) .set(tr.WIDTH, it.dimension.width) .set(tr.HEIGHT, it.dimension.height) @@ -101,13 +109,15 @@ class ThumbnailReadListDao( @Transactional override fun markSelected(thumbnail: ThumbnailReadList) { - dsl.update(tr) + dsl + .update(tr) .set(tr.SELECTED, false) .where(tr.READLIST_ID.eq(thumbnail.readListId)) .and(tr.ID.ne(thumbnail.id)) .execute() - dsl.update(tr) + dsl + .update(tr) .set(tr.SELECTED, true) .where(tr.READLIST_ID.eq(thumbnail.readListId)) .and(tr.ID.eq(thumbnail.id)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesCollectionDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesCollectionDao.kt index 73403984..976fd723 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesCollectionDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesCollectionDao.kt @@ -19,13 +19,15 @@ class ThumbnailSeriesCollectionDao( private val tc = Tables.THUMBNAIL_COLLECTION override fun findByIdOrNull(thumbnailId: String): ThumbnailSeriesCollection? = - dsl.selectFrom(tc) + dsl + .selectFrom(tc) .where(tc.ID.eq(thumbnailId)) .fetchOneInto(tc) ?.toDomain() override fun findSelectedByCollectionIdOrNull(collectionId: String): ThumbnailSeriesCollection? = - dsl.selectFrom(tc) + dsl + .selectFrom(tc) .where(tc.COLLECTION_ID.eq(collectionId)) .and(tc.SELECTED.isTrue) .limit(1) @@ -34,14 +36,16 @@ class ThumbnailSeriesCollectionDao( .firstOrNull() override fun findAllByCollectionId(collectionId: String): Collection = - dsl.selectFrom(tc) + dsl + .selectFrom(tc) .where(tc.COLLECTION_ID.eq(collectionId)) .fetchInto(tc) .map { it.toDomain() } override fun findAllWithoutMetadata(pageable: Pageable): Page { val query = - dsl.selectFrom(tc) + dsl + .selectFrom(tc) .where(tc.FILE_SIZE.eq(0)) .or(tc.MEDIA_TYPE.eq("")) .or(tc.WIDTH.eq(0)) @@ -58,7 +62,8 @@ class ThumbnailSeriesCollectionDao( } override fun insert(thumbnail: ThumbnailSeriesCollection) { - dsl.insertInto(tc) + dsl + .insertInto(tc) .set(tc.ID, thumbnail.id) .set(tc.COLLECTION_ID, thumbnail.collectionId) .set(tc.THUMBNAIL, thumbnail.thumbnail) @@ -72,7 +77,8 @@ class ThumbnailSeriesCollectionDao( } override fun update(thumbnail: ThumbnailSeriesCollection) { - dsl.update(tc) + dsl + .update(tc) .set(tc.COLLECTION_ID, thumbnail.collectionId) .set(tc.THUMBNAIL, thumbnail.thumbnail) .set(tc.SELECTED, thumbnail.selected) @@ -88,7 +94,9 @@ class ThumbnailSeriesCollectionDao( override fun updateMetadata(thumbnails: Collection) { dsl.batched { c -> thumbnails.forEach { - c.dsl().update(tc) + c + .dsl() + .update(tc) .set(tc.MEDIA_TYPE, it.mediaType) .set(tc.WIDTH, it.dimension.width) .set(tc.HEIGHT, it.dimension.height) @@ -101,13 +109,15 @@ class ThumbnailSeriesCollectionDao( @Transactional override fun markSelected(thumbnail: ThumbnailSeriesCollection) { - dsl.update(tc) + dsl + .update(tc) .set(tc.SELECTED, false) .where(tc.COLLECTION_ID.eq(thumbnail.collectionId)) .and(tc.ID.ne(thumbnail.id)) .execute() - dsl.update(tc) + dsl + .update(tc) .set(tc.SELECTED, true) .where(tc.COLLECTION_ID.eq(thumbnail.collectionId)) .and(tc.ID.eq(thumbnail.id)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesDao.kt index f0743119..01d169e9 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesDao.kt @@ -24,13 +24,15 @@ class ThumbnailSeriesDao( private val ts = Tables.THUMBNAIL_SERIES override fun findByIdOrNull(thumbnailId: String): ThumbnailSeries? = - dsl.selectFrom(ts) + dsl + .selectFrom(ts) .where(ts.ID.eq(thumbnailId)) .fetchOneInto(ts) ?.toDomain() override fun findAllBySeriesId(seriesId: String): Collection = - dsl.selectFrom(ts) + dsl + .selectFrom(ts) .where(ts.SERIES_ID.eq(seriesId)) .fetchInto(ts) .map { it.toDomain() } @@ -39,14 +41,16 @@ class ThumbnailSeriesDao( seriesId: String, type: ThumbnailSeries.Type, ): Collection = - dsl.selectFrom(ts) + dsl + .selectFrom(ts) .where(ts.SERIES_ID.eq(seriesId)) .and(ts.TYPE.eq(type.toString())) .fetchInto(ts) .map { it.toDomain() } override fun findSelectedBySeriesIdOrNull(seriesId: String): ThumbnailSeries? = - dsl.selectFrom(ts) + dsl + .selectFrom(ts) .where(ts.SERIES_ID.eq(seriesId)) .and(ts.SELECTED.isTrue) .limit(1) @@ -56,7 +60,8 @@ class ThumbnailSeriesDao( override fun findAllWithoutMetadata(pageable: Pageable): Page { val query = - dsl.selectFrom(ts) + dsl + .selectFrom(ts) .where(ts.FILE_SIZE.eq(0)) .or(ts.MEDIA_TYPE.eq("")) .or(ts.WIDTH.eq(0)) @@ -73,7 +78,8 @@ class ThumbnailSeriesDao( } override fun insert(thumbnail: ThumbnailSeries) { - dsl.insertInto(ts) + dsl + .insertInto(ts) .set(ts.ID, thumbnail.id) .set(ts.SERIES_ID, thumbnail.seriesId) .set(ts.URL, thumbnail.url?.toString()) @@ -88,7 +94,8 @@ class ThumbnailSeriesDao( } override fun update(thumbnail: ThumbnailSeries) { - dsl.update(ts) + dsl + .update(ts) .set(ts.SERIES_ID, thumbnail.seriesId) .set(ts.THUMBNAIL, thumbnail.thumbnail) .set(ts.URL, thumbnail.url?.toString()) @@ -105,7 +112,9 @@ class ThumbnailSeriesDao( override fun updateMetadata(thumbnails: Collection) { dsl.batched { c -> thumbnails.forEach { - c.dsl().update(ts) + c + .dsl() + .update(ts) .set(ts.MEDIA_TYPE, it.mediaType) .set(ts.WIDTH, it.dimension.width) .set(ts.HEIGHT, it.dimension.height) @@ -118,13 +127,15 @@ class ThumbnailSeriesDao( @Transactional override fun markSelected(thumbnail: ThumbnailSeries) { - dsl.update(ts) + dsl + .update(ts) .set(ts.SELECTED, false) .where(ts.SERIES_ID.eq(thumbnail.seriesId)) .and(ts.ID.ne(thumbnail.id)) .execute() - dsl.update(ts) + dsl + .update(ts) .set(ts.SELECTED, true) .where(ts.SERIES_ID.eq(thumbnail.seriesId)) .and(ts.ID.eq(thumbnail.id)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDao.kt index 55a69f70..ac7e2375 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDao.kt @@ -32,18 +32,21 @@ class TasksDao( private val tasksAvailableCondition = t.OWNER.isNull .and( - t.GROUP_ID.notIn( - dsl.select(t.GROUP_ID).from(t).where(t.OWNER.isNotNull).and(t.GROUP_ID.isNotNull), - ) - .or(t.GROUP_ID.isNull), + t.GROUP_ID + .notIn( + dsl + .select(t.GROUP_ID) + .from(t) + .where(t.OWNER.isNotNull) + .and(t.GROUP_ID.isNotNull), + ).or(t.GROUP_ID.isNull), ) - override fun hasAvailable(): Boolean { - return dsl.fetchExists( + override fun hasAvailable(): Boolean = + dsl.fetchExists( t, tasksAvailableCondition, ) - } @Transactional override fun takeFirst(owner: String): Task? { @@ -62,7 +65,8 @@ class TasksDao( } } ?: return null - dsl.update(t) + dsl + .update(t) .set(t.OWNER, owner) .where(t.ID.eq(task.uniqueId)) .execute() @@ -76,7 +80,8 @@ class TasksDao( .mapNotNull { it.toDomain() } override fun findAllGroupedByOwner(): Map> = - dsl.select(t.OWNER, t.CLASS, t.PAYLOAD) + dsl + .select(t.OWNER, t.CLASS, t.PAYLOAD) .from(t) .fetch() .mapNotNull { @@ -84,7 +89,8 @@ class TasksDao( }.groupBy({ it.first }, { it.second }) private fun selectBase() = - dsl.select(t.CLASS, t.PAYLOAD) + dsl + .select(t.CLASS, t.PAYLOAD) .from(t) private fun Record2.toDomain(): Task? = @@ -95,17 +101,15 @@ class TasksDao( null } - override fun count(): Int { - return dsl.fetchCount(t) - } + override fun count(): Int = dsl.fetchCount(t) - override fun countBySimpleType(): Map { - return dsl.select(t.SIMPLE_TYPE, DSL.count(t.SIMPLE_TYPE)) + override fun countBySimpleType(): Map = + dsl + .select(t.SIMPLE_TYPE, DSL.count(t.SIMPLE_TYPE)) .from(t) .groupBy(t.SIMPLE_TYPE) .fetch() .associate { it.value1() to it.value2() } - } override fun save(task: Task) { task.toQuery().execute() @@ -119,7 +123,8 @@ class TasksDao( } override fun disown(): Int = - dsl.update(t) + dsl + .update(t) .set(t.OWNER, null as String?) .where(t.OWNER.isNotNull) .execute() @@ -132,28 +137,26 @@ class TasksDao( dsl.deleteFrom(t).execute() } - override fun deleteAllWithoutOwner(): Int = - dsl.deleteFrom(t).where(t.OWNER.isNull).execute() + override fun deleteAllWithoutOwner(): Int = dsl.deleteFrom(t).where(t.OWNER.isNull).execute() private fun Task.toQuery(): Query = - dsl.insertInto( - t, - t.ID, - t.PRIORITY, - t.GROUP_ID, - t.CLASS, - t.SIMPLE_TYPE, - t.PAYLOAD, - ) - .values( + dsl + .insertInto( + t, + t.ID, + t.PRIORITY, + t.GROUP_ID, + t.CLASS, + t.SIMPLE_TYPE, + t.PAYLOAD, + ).values( uniqueId, priority, groupId, javaClass.typeName, javaClass.simpleName, objectMapper.writeValueAsString(this), - ) - .onDuplicateKeyUpdate() + ).onDuplicateKeyUpdate() .set(t.GROUP_ID, groupId) .set(t.PRIORITY, priority) .set(t.CLASS, javaClass.typeName) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KoboProxy.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KoboProxy.kt index 5ae442a2..8ccab139 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KoboProxy.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KoboProxy.kt @@ -30,16 +30,17 @@ class KoboProxy( private val komgaSettingsProvider: KomgaSettingsProvider, ) { private val koboApiClient = - RestClient.builder() + RestClient + .builder() .baseUrl("https://storeapi.kobo.com") .requestFactory( ClientHttpRequestFactoryBuilder.reactor().build( - ClientHttpRequestFactorySettings.defaults() + ClientHttpRequestFactorySettings + .defaults() .withReadTimeout(1.minutes.toJavaDuration()) .withConnectTimeout(1.minutes.toJavaDuration()), ), - ) - .build() + ).build() private val pathRegex = """\/kobo\/[-\w]*(.*)""".toRegex() @@ -82,15 +83,17 @@ class KoboProxy( null val response = - koboApiClient.method(HttpMethod.valueOf(request.method)) + koboApiClient + .method(HttpMethod.valueOf(request.method)) .uri { uriBuilder -> - uriBuilder.path(path) + uriBuilder + .path(path) .queryParams(LinkedMultiValueMap(request.parameterMap.mapValues { it.value.toList() })) .build() .also { logger.debug { "Proxy URL: $it" } } - } - .headers { headersOut -> - request.headerNames.toList() + }.headers { headersOut -> + request.headerNames + .toList() .filterNot { headersOutExclude.contains(it, true) } .filter { headersOutInclude.contains(it, true) || isKoboHeader(it) } .forEach { @@ -104,13 +107,11 @@ class KoboProxy( } } logger.debug { "Headers out: $headersOut" } - } - .apply { if (body != null) body(body) } + }.apply { if (body != null) body(body) } .retrieve() .onStatus(HttpStatusCode::isError) { _, response -> throw ResponseStatusException(response.statusCode, response.statusText) - } - .toEntity() + }.toEntity() logger.debug { "Kobo response: $response" } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KomgaSyncTokenGenerator.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KomgaSyncTokenGenerator.kt index 248c1e51..cf74dfac 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KomgaSyncTokenGenerator.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KomgaSyncTokenGenerator.kt @@ -56,8 +56,7 @@ class KomgaSyncTokenGenerator( return KomgaSyncToken() } - fun toBase64(token: KomgaSyncToken): String = - KOMGA_TOKEN_PREFIX + base64Encoder.encodeToString(objectMapper.writeValueAsString(token).toByteArray()) + fun toBase64(token: KomgaSyncToken): String = KOMGA_TOKEN_PREFIX + base64Encoder.encodeToString(objectMapper.writeValueAsString(token).toByteArray()) fun fromRequestHeaders(request: HttpServletRequest): KomgaSyncToken? { val syncTokenB64 = request.getHeader(X_KOBO_SYNCTOKEN) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/ContentDetector.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/ContentDetector.kt index 597ee6b3..4a2c7683 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/ContentDetector.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/ContentDetector.kt @@ -31,11 +31,9 @@ class ContentDetector( * Detects the media type of the content of the stream. * The stream will not be closed. */ - fun detectMediaType(stream: InputStream): String = - tika.detector.detect(stream, Metadata()).toString() + fun detectMediaType(stream: InputStream): String = tika.detector.detect(stream, Metadata()).toString() - fun isImage(mediaType: String): Boolean = - mediaType.startsWith("image/") + fun isImage(mediaType: String): Boolean = mediaType.startsWith("image/") fun mediaTypeToExtension(mediaType: String): String? = try { diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/Rar5Extractor.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/Rar5Extractor.kt index c81503e7..10574eac 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/Rar5Extractor.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/Rar5Extractor.kt @@ -62,14 +62,12 @@ class Rar5Extractor( logger.warn(e) { "Could not analyze entry: ${entry.name}" } MediaContainerEntry(name = entry.name, comment = e.message) } - } - .sortedWith(compareBy(natSortComparator) { it.name }) + }.sortedWith(compareBy(natSortComparator) { it.name }) .toList() } override fun getEntryStream( path: Path, entryName: String, - ): ByteArray = - Archive.getInputStream(path, entryName).use { it?.readBytes() ?: ByteArray(0) } + ): ByteArray = Archive.getInputStream(path, entryName).use { it?.readBytes() ?: ByteArray(0) } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/RarExtractor.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/RarExtractor.kt index 5279f094..cf5f1249 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/RarExtractor.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/RarExtractor.kt @@ -47,8 +47,7 @@ class RarExtractor( logger.warn(e) { "Could not analyze entry: ${entry.fileName}" } MediaContainerEntry(name = entry.fileName, comment = e.message) } - } - .sortedWith(compareBy(natSortComparator) { it.name }) + }.sortedWith(compareBy(natSortComparator) { it.name }) } override fun getEntryStream( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/ZipExtractor.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/ZipExtractor.kt index 40aac828..a4995121 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/ZipExtractor.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/divina/ZipExtractor.kt @@ -29,7 +29,8 @@ class ZipExtractor( analyzeDimensions: Boolean, ): List = ZipFile.builder().setPath(path).use { zip -> - zip.entries.toList() + zip.entries + .toList() .filter { !it.isDirectory } .map { entry -> try { @@ -47,8 +48,7 @@ class ZipExtractor( logger.warn(e) { "Could not analyze entry: ${entry.name}" } MediaContainerEntry(name = entry.name, comment = e.message) } - } - .sortedWith(compareBy(natSortComparator) { it.name }) + }.sortedWith(compareBy(natSortComparator) { it.name }) } override fun getEntryStream( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub.kt index 699cb02f..d2cb8b78 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub.kt @@ -31,7 +31,9 @@ inline fun Path.epub(block: (EpubPackage) -> R): R = fun ZipFile.getPackagePath(): String = getEntryInputStream("META-INF/container.xml") .use { Jsoup.parse(it, null, "") } - .getElementsByTag("rootfile").first()?.attr("full-path") ?: throw MediaUnsupportedException("META-INF/container.xml does not contain rootfile tag") + .getElementsByTag("rootfile") + .first() + ?.attr("full-path") ?: throw MediaUnsupportedException("META-INF/container.xml does not contain rootfile tag") /** * Returns the content of the Epub package file as a [String] diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub2Nav.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub2Nav.kt index 2d62b0fb..d12e8621 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub2Nav.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub2Nav.kt @@ -1,6 +1,9 @@ package org.gotson.komga.infrastructure.mediacontainer.epub -enum class Epub2Nav(val level1: String, val level2: String) { +enum class Epub2Nav( + val level1: String, + val level2: String, +) { TOC("navMap", "navPoint"), PAGELIST("pageList", "pageTarget"), } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub3Nav.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub3Nav.kt index 010981d4..6d4e85b6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub3Nav.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Epub3Nav.kt @@ -1,6 +1,8 @@ package org.gotson.komga.infrastructure.mediacontainer.epub -enum class Epub3Nav(val value: String) { +enum class Epub3Nav( + val value: String, +) { TOC("toc"), LANDMARKS("landmarks"), PAGELIST("page-list"), diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubExtractor.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubExtractor.kt index ef0b11f3..c6f5f910 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubExtractor.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubExtractor.kt @@ -59,7 +59,11 @@ class EpubExtractor( // EPUB 3 - try to get cover from manifest properties 'cover-image' manifest.values.firstOrNull { it.properties.contains("cover-image") } ?: // EPUB 2 - get cover from meta element with name="cover" - opfDoc.selectFirst("metadata > meta[name=cover]")?.attr("content")?.ifBlank { null }?.let { manifest[it] } + opfDoc + .selectFirst("metadata > meta[name=cover]") + ?.attr("content") + ?.ifBlank { null } + ?.let { manifest[it] } if (coverManifestItem != null) { val href = coverManifestItem.href @@ -98,7 +102,11 @@ class EpubExtractor( } private fun getResources(epub: EpubPackage): List { - val spine = epub.opfDoc.select("spine > itemref").map { it.attr("idref") }.mapNotNull { epub.manifest[it] } + val spine = + epub.opfDoc + .select("spine > itemref") + .map { it.attr("idref") } + .mapNotNull { epub.manifest[it] } val pages = spine.map { page -> @@ -134,7 +142,8 @@ class EpubExtractor( try { val pagesWithImages = - epub.opfDoc.select("spine > itemref") + epub.opfDoc + .select("spine > itemref") .map { it.attr("idref") } .mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } } .map { pagePath -> @@ -144,11 +153,13 @@ class EpubExtractor( if (doc.body().text().length > letterCountThreshold) return emptyList() val img = - doc.getElementsByTag("img") + doc + .getElementsByTag("img") .map { it.attr("src") } // get the src, which can be a relative path val svg = - doc.select("svg > image[xlink:href]") + doc + .select("svg > image[xlink:href]") .map { it.attr("xlink:href") } // get the source, which can be a relative path (img + svg).map { (Path(pagePath).parent ?: Path("")).resolve(it).normalize().invariantSeparatorsPathString } // resolve it against the page folder @@ -160,7 +171,10 @@ class EpubExtractor( val divinaPages = imagesPath.mapNotNull { imagePath -> - val mediaType = epub.manifest.values.firstOrNull { normalizeHref(epub.opfDir, it.href) == imagePath }?.mediaType ?: return@mapNotNull null + val mediaType = + epub.manifest.values + .firstOrNull { normalizeHref(epub.opfDir, it.href) == imagePath } + ?.mediaType ?: return@mapNotNull null val zipEntry = epub.zip.getEntry(imagePath) if (!contentDetector.isImage(mediaType)) return@mapNotNull null @@ -200,11 +214,15 @@ class EpubExtractor( private fun computePageCount(epub: EpubPackage): Int { val spine = - epub.opfDoc.select("spine > itemref") + epub.opfDoc + .select("spine > itemref") .map { it.attr("idref") } .mapNotNull { idref -> epub.manifest[idref]?.href?.let { normalizeHref(epub.opfDir, it) } } - return epub.zip.entries.toList().filter { it.name in spine }.sumOf { ceil(it.compressedSize / 1024.0).toInt() } + return epub.zip.entries + .toList() + .filter { it.name in spine } + .sumOf { ceil(it.compressedSize / 1024.0).toInt() } } private fun isFixedLayout(epub: EpubPackage) = @@ -229,7 +247,8 @@ class EpubExtractor( kepubConverter.isAvailable -> { try { val kepub = - kepubConverter.convertEpubToKepubWithoutChecks(path) + kepubConverter + .convertEpubToKepubWithoutChecks(path) ?.also { it.toFile().deleteOnExit() } // if the conversion failed, throw an exception that will be caught in the catch block ?: throw IllegalStateException() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Nav.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Nav.kt index e169700f..c19d5328 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Nav.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Nav.kt @@ -20,7 +20,8 @@ fun processNav( ): List { val doc = Jsoup.parse(document.content) val nav = - doc.select("nav") + doc + .select("nav") // Jsoup selectors cannot find an attribute with namespace .firstOrNull { it.attributes().any { attr -> attr.key.endsWith("type") && attr.value == navElement.value } } return nav?.select(":root > ol > li")?.toList()?.mapNotNull { navLiElementToTocEntry(it, document.path.parent) } ?: emptyList() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Ncx.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Ncx.kt index d0173cbc..d902a3b0 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Ncx.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/Ncx.kt @@ -20,7 +20,8 @@ fun processNcx( document: ResourceContent, navType: Epub2Nav, ): List = - Jsoup.parse(document.content) + Jsoup + .parse(document.content) .select("${navType.level1} > ${navType.level2}") .toList() .mapNotNull { ncxElementToTocEntry(navType, it, document.path.parent) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProvider.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProvider.kt index 8707318f..87235381 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProvider.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProvider.kt @@ -33,7 +33,8 @@ class ComicInfoProvider( @Autowired(required = false) private val mapper: XmlMapper = XmlMapper(), private val bookAnalyzer: BookAnalyzer, private val isbnValidator: ISBNValidator, -) : BookMetadataProvider, SeriesMetadataFromBookProvider { +) : BookMetadataProvider, + SeriesMetadataFromBookProvider { override val capabilities = setOf( BookMetadataPatchCapability.TITLE, @@ -150,7 +151,11 @@ class ComicInfoProvider( language = if (comicInfo.languageISO != null && BCP47TagValidator.isValid(comicInfo.languageISO!!)) BCP47TagValidator.normalize(comicInfo.languageISO!!) else null, genres = if (!genres.isNullOrEmpty()) genres.toSet() else null, totalBookCount = comicInfo.count, - collections = comicInfo.seriesGroup?.split(',')?.mapNotNull { it.trim().ifBlank { null } }?.toSet() ?: emptySet(), + collections = + comicInfo.seriesGroup + ?.split(',') + ?.mapNotNull { it.trim().ifBlank { null } } + ?.toSet() ?: emptySet(), ) } return null diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/AgeRating.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/AgeRating.kt index 985c6d44..e8ef8995 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/AgeRating.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/AgeRating.kt @@ -2,7 +2,10 @@ package org.gotson.komga.infrastructure.metadata.comicrack.dto import com.fasterxml.jackson.annotation.JsonCreator -enum class AgeRating(val value: String, val ageRating: Int? = null) { +enum class AgeRating( + val value: String, + val ageRating: Int? = null, +) { UNKNOWN("Unknown"), ADULTS_ONLY_18("Adults Only 18+", 18), EARLY_CHILDHOOD("Early Childhood", 3), diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/Book.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/Book.kt index 946daefb..56800572 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/Book.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/Book.kt @@ -20,7 +20,5 @@ class Book { @JsonProperty(value = "FileName") var fileName: String? = null - override fun toString(): String { - return "Book(series=$series, number=$number, volume=$volume, year=$year, fileName=$fileName)" - } + override fun toString(): String = "Book(series=$series, number=$number, volume=$volume, year=$year, fileName=$fileName)" } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/Manga.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/Manga.kt index e18ce58c..3c6233a4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/Manga.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/Manga.kt @@ -2,7 +2,9 @@ package org.gotson.komga.infrastructure.metadata.comicrack.dto import com.fasterxml.jackson.annotation.JsonCreator -enum class Manga(private val value: String) { +enum class Manga( + private val value: String, +) { UNKNOWN("Unknown"), NO("No"), YES("Yes"), diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ReadingList.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ReadingList.kt index 84a04f26..575e0d17 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ReadingList.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ReadingList.kt @@ -17,7 +17,5 @@ class ReadingList { @JsonSetter(nulls = Nulls.AS_EMPTY) var books: List = emptyList() - override fun toString(): String { - return "ReadingList(name=$name, books=$books)" - } + override fun toString(): String = "ReadingList(name=$name, books=$books)" } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/YesNo.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/YesNo.kt index 67aaefcd..dc719605 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/YesNo.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/YesNo.kt @@ -2,7 +2,9 @@ package org.gotson.komga.infrastructure.metadata.comicrack.dto import com.fasterxml.jackson.annotation.JsonCreator -enum class YesNo(val value: String) { +enum class YesNo( + val value: String, +) { UNKNOWN("Unknown"), NO("No"), YES("Yes"), diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/epub/EpubMetadataProvider.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/epub/EpubMetadataProvider.kt index 9b2b0cf7..619b142b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/epub/EpubMetadataProvider.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/epub/EpubMetadataProvider.kt @@ -25,7 +25,8 @@ import java.time.format.DateTimeFormatter @Service class EpubMetadataProvider( private val isbnValidator: ISBNValidator, -) : BookMetadataProvider, SeriesMetadataFromBookProvider { +) : BookMetadataProvider, + SeriesMetadataFromBookProvider { private val relators = mapOf( "aut" to "writer", @@ -52,14 +53,21 @@ class EpubMetadataProvider( val opf = Jsoup.parse(packageFile, "", Parser.xmlParser()) val title = opf.selectFirst("metadata > dc|title")?.text()?.ifBlank { null } - val description = opf.selectFirst("metadata > dc|description")?.text()?.let { Jsoup.clean(it, Safelist.none()) }?.ifBlank { null } + val description = + opf + .selectFirst("metadata > dc|description") + ?.text() + ?.let { Jsoup.clean(it, Safelist.none()) } + ?.ifBlank { null } val date = opf.selectFirst("metadata > dc|date")?.text()?.let { parseDate(it) } val authorRoles = - opf.select("metadata > *|meta[property=role][scheme=marc:relators]") + opf + .select("metadata > *|meta[property=role][scheme=marc:relators]") .associate { it.attr("refines").removePrefix("#") to it.text() } val authors = - opf.select("metadata > dc|creator") + opf + .select("metadata > dc|creator") .mapNotNull { el -> val name = el.text().trim() if (name.isBlank()) { @@ -73,14 +81,18 @@ class EpubMetadataProvider( }.ifEmpty { null } val isbn = - opf.select("metadata > dc|identifier") + opf + .select("metadata > dc|identifier") .map { it.text().lowercase().removePrefix("isbn:") } .firstNotNullOfOrNull { isbnValidator.validate(it) } val seriesIndex = - opf.selectFirst("metadata > *|meta[property=belongs-to-collection]")?.attr("id")?.let { id -> - opf.selectFirst("metadata > *|meta[refines=#$id][property=group-position]") - }?.text() + opf + .selectFirst("metadata > *|meta[property=belongs-to-collection]") + ?.attr("id") + ?.let { id -> + opf.selectFirst("metadata > *|meta[refines=#$id][property=group-position]") + }?.text() return BookMetadataPatch( title = title, @@ -109,7 +121,8 @@ class EpubMetadataProvider( val publisher = opf.selectFirst("metadata > dc|publisher")?.text()?.ifBlank { null } val language = opf.selectFirst("metadata > dc|language")?.text()?.ifBlank { null } val genres = - opf.select("metadata > dc|subject") + opf + .select("metadata > dc|subject") .mapNotNull { it.text().trim().ifBlank { null } } .toSet() .ifEmpty { null } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/localartwork/LocalArtworkProvider.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/localartwork/LocalArtworkProvider.kt index d6003bf8..b8c235a6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/localartwork/LocalArtworkProvider.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/localartwork/LocalArtworkProvider.kt @@ -26,7 +26,8 @@ private val logger = KotlinLogging.logger {} class LocalArtworkProvider( private val contentDetector: ContentDetector, private val imageAnalyzer: ImageAnalyzer, -) : SidecarSeriesConsumer, SidecarBookConsumer { +) : SidecarSeriesConsumer, + SidecarBookConsumer { val supportedExtensions = listOf("png", "jpeg", "jpg", "tbn", "webp") val supportedSeriesFiles = listOf("cover", "default", "folder", "poster", "series") @@ -38,7 +39,8 @@ class LocalArtworkProvider( val regex = "${Regex.escape(baseName)}(-\\d+)?".toRegex(RegexOption.IGNORE_CASE) return Files.list(bookPath.parent).use { dirStream -> - dirStream.asSequence() + dirStream + .asSequence() .filter { Files.isRegularFile(it) } .filter { regex.matches(it.nameWithoutExtension) } .filter { supportedExtensions.contains(it.extension.lowercase()) } @@ -67,7 +69,8 @@ class LocalArtworkProvider( logger.info { "Looking for local thumbnails for series: $series" } return Files.list(series.path).use { dirStream -> - dirStream.asSequence() + dirStream + .asSequence() .filter { Files.isRegularFile(it) } .filter { supportedSeriesFiles.contains(it.nameWithoutExtension.lowercase()) } .filter { supportedExtensions.contains(it.extension.lowercase()) } @@ -89,14 +92,12 @@ class LocalArtworkProvider( override fun getSidecarBookType(): Sidecar.Type = Sidecar.Type.ARTWORK - override fun getSidecarBookPrefilter(): List = - supportedExtensions.map { ext -> ".*(-\\d+)?\\.$ext".toRegex(RegexOption.IGNORE_CASE) } + override fun getSidecarBookPrefilter(): List = supportedExtensions.map { ext -> ".*(-\\d+)?\\.$ext".toRegex(RegexOption.IGNORE_CASE) } override fun isSidecarBookMatch( basename: String, sidecar: String, - ): Boolean = - "${Regex.escape(basename)}(-\\d+)?".toRegex(RegexOption.IGNORE_CASE).matches(FilenameUtils.getBaseName(sidecar)) + ): Boolean = "${Regex.escape(basename)}(-\\d+)?".toRegex(RegexOption.IGNORE_CASE).matches(FilenameUtils.getBaseName(sidecar)) override fun getSidecarSeriesType(): Sidecar.Type = Sidecar.Type.ARTWORK diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/mylar/MylarSeriesProvider.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/mylar/MylarSeriesProvider.kt index f1fe632f..7d358711 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/mylar/MylarSeriesProvider.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/mylar/MylarSeriesProvider.kt @@ -23,7 +23,8 @@ private const val SERIES_JSON = "series.json" @Service class MylarSeriesProvider( private val mapper: ObjectMapper, -) : SeriesMetadataProvider, SidecarSeriesConsumer { +) : SeriesMetadataProvider, + SidecarSeriesConsumer { override fun getSeriesMetadata(series: Series): SeriesMetadataPatch? { if (series.oneshot) { logger.debug { "Disabled for oneshot series, skipping" } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/oneshot/OneShotSeriesProvider.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/oneshot/OneShotSeriesProvider.kt index eaf53f9c..4a26e951 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/oneshot/OneShotSeriesProvider.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/oneshot/OneShotSeriesProvider.kt @@ -36,6 +36,5 @@ class OneShotSeriesProvider( override fun shouldLibraryHandlePatch( library: Library, target: MetadataPatchTarget, - ): Boolean = - target == MetadataPatchTarget.SERIES + ): Boolean = target == MetadataPatchTarget.SERIES } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneConfiguration.kt index 94ca9885..9761462d 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneConfiguration.kt @@ -21,16 +21,13 @@ class LuceneConfiguration( } @Bean - fun searchAnalyzer() = - MultiLingualAnalyzer() + fun searchAnalyzer() = MultiLingualAnalyzer() @Bean @Profile("test") - fun memoryDirectory(): Directory = - ByteBuffersDirectory() + fun memoryDirectory(): Directory = ByteBuffersDirectory() @Bean @Profile("!test") - fun diskDirectory(): Directory = - FSDirectory.open(Paths.get(komgaProperties.lucene.dataDirectory), SingleInstanceLockFactory()) + fun diskDirectory(): Directory = FSDirectory.open(Paths.get(komgaProperties.lucene.dataDirectory), SingleInstanceLockFactory()) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneEntity.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneEntity.kt index a6c74779..22ca86c7 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneEntity.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneEntity.kt @@ -11,7 +11,11 @@ import org.gotson.komga.interfaces.api.rest.dto.BookDto import org.gotson.komga.interfaces.api.rest.dto.SeriesDto import org.gotson.komga.language.toDate -enum class LuceneEntity(val type: String, val id: String, val defaultFields: Array) { +enum class LuceneEntity( + val type: String, + val id: String, + val defaultFields: Array, +) { Book("book", "book_id", arrayOf("title", "isbn")), Series("series", "series_id", arrayOf("title")), Collection("collection", "collection_id", arrayOf("name")), diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneHelper.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneHelper.kt index edceb041..058c7fb2 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneHelper.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/LuceneHelper.kt @@ -57,24 +57,29 @@ class LuceneHelper( fun getIndexVersion(): Int { val searcher = searcherManager.acquire() val topDocs = searcher.search(TermQuery(Term("type", "index_version")), 1) - return topDocs.scoreDocs.map { searcher.storedFields().document(it.doc)["index_version"] }.firstOrNull()?.toIntOrNull() ?: 1 + return topDocs.scoreDocs + .map { searcher.storedFields().document(it.doc)["index_version"] } + .firstOrNull() + ?.toIntOrNull() ?: 1 } fun searchEntitiesIds( searchTerm: String?, entity: LuceneEntity, - ): List? { - return if (!searchTerm.isNullOrBlank()) { + ): List? = + if (!searchTerm.isNullOrBlank()) { try { val fieldsQuery = - MultiFieldQueryParser(entity.defaultFields, searchAnalyzer).apply { - defaultOperator = QueryParser.Operator.AND - }.parse("$searchTerm *:*") + MultiFieldQueryParser(entity.defaultFields, searchAnalyzer) + .apply { + defaultOperator = QueryParser.Operator.AND + }.parse("$searchTerm *:*") val typeQuery = TermQuery(Term(LuceneEntity.TYPE, entity.type)) val booleanQuery = - BooleanQuery.Builder() + BooleanQuery + .Builder() .add(fieldsQuery, BooleanClause.Occur.MUST) .add(typeQuery, BooleanClause.Occur.MUST) .build() @@ -91,7 +96,6 @@ class LuceneHelper( } else { null } - } fun upgradeIndex() { IndexUpgrader(directory, IndexWriterConfig(indexAnalyzer), true).upgrade() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/MultiLingualNGramAnalyzer.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/MultiLingualNGramAnalyzer.kt index 74dbef8b..435b511b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/MultiLingualNGramAnalyzer.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/MultiLingualNGramAnalyzer.kt @@ -9,7 +9,11 @@ import org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter import org.apache.lucene.analysis.ngram.NGramTokenFilter import org.apache.lucene.analysis.standard.StandardTokenizer -class MultiLingualNGramAnalyzer(private val minGram: Int, private val maxGram: Int, private val preserveOriginal: Boolean) : MultiLingualAnalyzer() { +class MultiLingualNGramAnalyzer( + private val minGram: Int, + private val maxGram: Int, + private val preserveOriginal: Boolean, +) : MultiLingualAnalyzer() { override fun createComponents(fieldName: String): TokenStreamComponents { val source: Tokenizer = StandardTokenizer() // run the widthfilter first before bigramming, it sometimes combines characters. diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/SearchIndexLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/SearchIndexLifecycle.kt index bfb13536..ef8f0d21 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/SearchIndexLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/search/SearchIndexLifecycle.kt @@ -71,7 +71,8 @@ class SearchIndexLifecycle( (0 until pages).forEach { page -> logger.info { "Processing page ${page + 1} of $pages ($batchSize elements)" } val entityDocs = - provider(PageRequest.of(page, batchSize)).content + provider(PageRequest.of(page, batchSize)) + .content .mapNotNull { toDoc(it) } luceneHelper.addDocuments(entityDocs) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/CorsConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/CorsConfiguration.kt index 485ac04a..78425d25 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/CorsConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/CorsConfiguration.kt @@ -44,7 +44,8 @@ class CorsConfiguration { metadata: AnnotatedTypeMetadata, ): ConditionOutcome { val defined = - Binder.get(context.environment) + Binder + .get(context.environment) .bind(ConfigurationPropertyName.of("komga.cors.allowed-origins"), Bindable.of(List::class.java)) .orElse(Collections.emptyList()) .isNotEmpty() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/KomgaPrincipal.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/KomgaPrincipal.kt index e04c3057..033d83b3 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/KomgaPrincipal.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/KomgaPrincipal.kt @@ -16,7 +16,9 @@ class KomgaPrincipal( val oidcUser: OidcUser? = null, val apiKey: ApiKey? = null, private val name: String = user.email, -) : UserDetails, OAuth2User, OidcUser { +) : UserDetails, + OAuth2User, + OidcUser { override fun getAuthorities(): MutableCollection = user.roles .map { SimpleGrantedAuthority("ROLE_$it") } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/LoginListener.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/LoginListener.kt index 9ab07609..29970485 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/LoginListener.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/LoginListener.kt @@ -65,7 +65,11 @@ class LoginListener( is RememberMeAuthenticationToken -> "RememberMe" else -> null } - val principal = event.authentication?.principal?.toString().orEmpty() + val principal = + event.authentication + ?.principal + ?.toString() + .orEmpty() val activity = AuthenticationActivity( userId = userRepository.findByEmailIgnoreCaseOrNull(principal)?.id, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt index a8ea4796..bf546490 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt @@ -76,53 +76,49 @@ class SecurityConfiguration( "/login/oauth2/code/**", ) it.requestMatchers(EndpointRequest.toAnyEndpoint()) - } - .authorizeHttpRequests { + }.authorizeHttpRequests { // allow unauthorized access to actuator health endpoint // this will only show limited details as `management.endpoint.health.show-details` is set to `when-authorized` it.requestMatchers(EndpointRequest.to(HealthEndpoint::class.java)).permitAll() // restrict all other actuator endpoints to ADMIN only it.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole(ROLE_ADMIN) - it.requestMatchers( - // to claim server before any account is created - "/api/v1/claim", - // used by webui - "/api/v1/oauth2/providers", - // epub resources - fonts are always requested anonymously, so we check for authorization within the controller method directly - "api/v1/books/{bookId}/resource/**", - // OPDS authentication document - "/opds/v2/auth", - ).permitAll() + it + .requestMatchers( + // to claim server before any account is created + "/api/v1/claim", + // used by webui + "/api/v1/oauth2/providers", + // epub resources - fonts are always requested anonymously, so we check for authorization within the controller method directly + "api/v1/books/{bookId}/resource/**", + // OPDS authentication document + "/opds/v2/auth", + ).permitAll() // all other endpoints are restricted to authenticated users - it.requestMatchers( - "/api/**", - "/opds/**", - "/sse/**", - ).hasRole(ROLE_USER) - } - .headers { headersConfigurer -> + it + .requestMatchers( + "/api/**", + "/opds/**", + "/sse/**", + ).hasRole(ROLE_USER) + }.headers { headersConfigurer -> headersConfigurer.cacheControl { it.disable() } // headers are set in WebMvcConfiguration headersConfigurer.frameOptions { it.sameOrigin() } // for epubreader iframes - } - .userDetailsService(komgaUserDetailsService) + }.userDetailsService(komgaUserDetailsService) .httpBasic { it.authenticationDetailsSource(userAgentWebAuthenticationDetailsSource) - } - .logout { + }.logout { it.logoutUrl("/api/logout") it.deleteCookies(sessionCookieName) it.invalidateHttpSession(true) - } - .sessionManagement { session -> + }.sessionManagement { session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) session.sessionConcurrency { it.sessionRegistry(theSessionRegistry) it.maximumSessions(-1) } - } - .exceptionHandling { + }.exceptionHandling { it.defaultAuthenticationEntryPointFor(opdsAuthenticationEntryPoint, AntPathRequestMatcher("/opds/v2/**")) } @@ -133,7 +129,8 @@ class SecurityConfiguration( it.oidcUserService(oidcUserService) } oauth2.authenticationDetailsSource(userAgentWebAuthenticationDetailsSource) - oauth2.loginPage("/login") + oauth2 + .loginPage("/login") .defaultSuccessUrl("/?server_redirect=Y", true) .failureHandler { request, response, exception -> val errorMessage = diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/UserAgentWebAuthenticationDetails.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/UserAgentWebAuthenticationDetails.kt index 9949a379..c3e905f4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/UserAgentWebAuthenticationDetails.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/UserAgentWebAuthenticationDetails.kt @@ -4,6 +4,8 @@ import jakarta.servlet.http.HttpServletRequest import org.springframework.http.HttpHeaders import org.springframework.security.web.authentication.WebAuthenticationDetails -class UserAgentWebAuthenticationDetails(request: HttpServletRequest) : WebAuthenticationDetails(request) { +class UserAgentWebAuthenticationDetails( + request: HttpServletRequest, +) : WebAuthenticationDetails(request) { val userAgent: String = request.getHeader(HttpHeaders.USER_AGENT).orEmpty() } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/UserAgentWebAuthenticationDetailsSource.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/UserAgentWebAuthenticationDetailsSource.kt index da7ffeef..5c211d23 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/UserAgentWebAuthenticationDetailsSource.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/UserAgentWebAuthenticationDetailsSource.kt @@ -6,6 +6,5 @@ import org.springframework.stereotype.Component @Component class UserAgentWebAuthenticationDetailsSource : WebAuthenticationDetailsSource() { - override fun buildDetails(context: HttpServletRequest): UserAgentWebAuthenticationDetails = - UserAgentWebAuthenticationDetails(context) + override fun buildDetails(context: HttpServletRequest): UserAgentWebAuthenticationDetails = UserAgentWebAuthenticationDetails(context) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyAuthenticationProvider.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyAuthenticationProvider.kt index a78b407c..fb072323 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyAuthenticationProvider.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyAuthenticationProvider.kt @@ -34,10 +34,10 @@ class ApiKeyAuthenticationProvider( authentication: Authentication?, user: UserDetails?, ): Authentication = - ApiKeyAuthenticationToken.authenticated(principal, authentication?.credentials, user!!.authorities) + ApiKeyAuthenticationToken + .authenticated(principal, authentication?.credentials, user!!.authorities) .apply { details = authentication?.details } .also { logger.debug("Authenticated user") } - override fun supports(authentication: Class<*>): Boolean = - ApiKeyAuthenticationToken::class.java.isAssignableFrom(authentication) + override fun supports(authentication: Class<*>): Boolean = ApiKeyAuthenticationToken::class.java.isAssignableFrom(authentication) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyAuthenticationToken.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyAuthenticationToken.kt index aea3237d..852843dd 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyAuthenticationToken.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyAuthenticationToken.kt @@ -6,7 +6,11 @@ import org.springframework.security.core.GrantedAuthority /** * A specialization of [UsernamePasswordAuthenticationToken] to store API keys. */ -class ApiKeyAuthenticationToken private constructor(principal: Any?, credentials: Any?, authorities: Collection?) : UsernamePasswordAuthenticationToken(principal, credentials, authorities) { +class ApiKeyAuthenticationToken private constructor( + principal: Any?, + credentials: Any?, + authorities: Collection?, +) : UsernamePasswordAuthenticationToken(principal, credentials, authorities) { private constructor(principal: Any?, credentials: Any?) : this(principal, credentials, null) { isAuthenticated = false } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyGenerator.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyGenerator.kt index c386a2ae..451de9a3 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyGenerator.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/ApiKeyGenerator.kt @@ -9,6 +9,5 @@ import java.util.UUID */ @Component class ApiKeyGenerator { - fun generate() = - UUID.randomUUID().toString().replace("-", "") + fun generate() = UUID.randomUUID().toString().replace("-", "") } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/UriRegexApiKeyAuthenticationConverter.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/UriRegexApiKeyAuthenticationConverter.kt index 3733e58b..6b81742f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/UriRegexApiKeyAuthenticationConverter.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/apikey/UriRegexApiKeyAuthenticationConverter.kt @@ -20,11 +20,13 @@ class UriRegexApiKeyAuthenticationConverter( private val authenticationDetailsSource: AuthenticationDetailsSource, ) : AuthenticationConverter { override fun convert(request: HttpServletRequest): Authentication? = - request.requestURI?.let { - tokenRegex.find(it)?.groupValues?.lastOrNull() - }?.let { - val (maskedToken, hashedToken) = it.take(6) + "*".repeat(6) to tokenEncoder.encode(it) - ApiKeyAuthenticationToken.unauthenticated(maskedToken, hashedToken) - .apply { details = authenticationDetailsSource.buildDetails(request) } - } + request.requestURI + ?.let { + tokenRegex.find(it)?.groupValues?.lastOrNull() + }?.let { + val (maskedToken, hashedToken) = it.take(6) + "*".repeat(6) to tokenEncoder.encode(it) + ApiKeyAuthenticationToken + .unauthenticated(maskedToken, hashedToken) + .apply { details = authenticationDetailsSource.buildDetails(request) } + } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/oauth2/GithubOAuth2UserService.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/oauth2/GithubOAuth2UserService.kt index 54852332..e75fcd0f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/oauth2/GithubOAuth2UserService.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/oauth2/GithubOAuth2UserService.kt @@ -24,20 +24,23 @@ class GithubOAuth2UserService : DefaultOAuth2UserService() { var oAuth2User = super.loadUser(userRequest) - if (userRequest.clientRegistration.scopes.intersect(emailScopes).isNotEmpty() && + if (userRequest.clientRegistration.scopes + .intersect(emailScopes) + .isNotEmpty() && oAuth2User.getAttribute("email") == null ) { try { val email = - RestTemplate().exchange( - RequestEntity( - HttpHeaders().apply { setBearerAuth(userRequest.accessToken.tokenValue) }, - HttpMethod.GET, - UriComponentsBuilder.fromUriString("${userRequest.clientRegistration.providerDetails.userInfoEndpoint.uri}/emails").build().toUri(), - ), - parameterizedResponseType, - ) - .body?.let { emails -> + RestTemplate() + .exchange( + RequestEntity( + HttpHeaders().apply { setBearerAuth(userRequest.accessToken.tokenValue) }, + HttpMethod.GET, + UriComponentsBuilder.fromUriString("${userRequest.clientRegistration.providerDetails.userInfoEndpoint.uri}/emails").build().toUri(), + ), + parameterizedResponseType, + ).body + ?.let { emails -> emails .filter { it["verified"] == true } .filter { it["primary"] == true } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/session/SessionConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/session/SessionConfiguration.kt index af69d08d..792d6975 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/session/SessionConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/session/SessionConfiguration.kt @@ -32,16 +32,17 @@ class SessionConfiguration { fun httpSessionIdResolver( sessionHeaderName: String, cookieSerializer: CookieSerializer, - ): HttpSessionIdResolver = - SmartHttpSessionIdResolver(sessionHeaderName, cookieSerializer) + ): HttpSessionIdResolver = SmartHttpSessionIdResolver(sessionHeaderName, cookieSerializer) @Bean fun customizeSessionRepository(serverProperties: ServerProperties) = SessionRepositoryCustomizer { - it.setDefaultMaxInactiveInterval(serverProperties.servlet.session.timeout.seconds.toInt()) + it.setDefaultMaxInactiveInterval( + serverProperties.servlet.session.timeout.seconds + .toInt(), + ) } @Bean - fun sessionRegistry(sessionRepository: FindByIndexNameSessionRepository<*>): SessionRegistry = - SpringSessionBackedSessionRegistry(sessionRepository) + fun sessionRegistry(sessionRepository: FindByIndexNameSessionRepository<*>): SessionRegistry = SpringSessionBackedSessionRegistry(sessionRepository) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/session/SmartHttpSessionIdResolver.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/session/SmartHttpSessionIdResolver.kt index 83890949..a937c4a5 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/session/SmartHttpSessionIdResolver.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/session/SmartHttpSessionIdResolver.kt @@ -14,8 +14,7 @@ class SmartHttpSessionIdResolver( private val cookie = CookieHttpSessionIdResolver().apply { setCookieSerializer(cookieSerializer) } private val header = HeaderHttpSessionIdResolver(sessionHeaderName) - override fun resolveSessionIds(request: HttpServletRequest): List = - request.getResolver().resolveSessionIds(request) + override fun resolveSessionIds(request: HttpServletRequest): List = request.getResolver().resolveSessionIds(request) override fun setSessionId( request: HttpServletRequest, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/swagger/SwaggerConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/swagger/SwaggerConfiguration.kt index 7f98a320..10239683 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/swagger/SwaggerConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/swagger/SwaggerConfiguration.kt @@ -24,15 +24,12 @@ class SwaggerConfiguration { Both APIs are secured using HTTP Basic Authentication. """.trimIndent(), - ) - .license(License().name("MIT").url("https://github.com/gotson/komga/blob/master/LICENSE")), - ) - .externalDocs( + ).license(License().name("MIT").url("https://github.com/gotson/komga/blob/master/LICENSE")), + ).externalDocs( ExternalDocumentation() .description("Komga documentation") .url("https://komga.org"), - ) - .components( + ).components( Components() .addSecuritySchemes( "basicAuth", diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/transaction/TransactionConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/transaction/TransactionConfiguration.kt index bd5ccd5a..bc01da78 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/transaction/TransactionConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/transaction/TransactionConfiguration.kt @@ -8,6 +8,5 @@ import org.springframework.transaction.support.TransactionTemplate @Configuration class TransactionConfiguration { @Bean - fun transactionTemplate(transactionManager: PlatformTransactionManager) = - TransactionTemplate(transactionManager) + fun transactionTemplate(transactionManager: PlatformTransactionManager) = TransactionTemplate(transactionManager) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/util/ZipFileUtils.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/util/ZipFileUtils.kt index 1a426edd..457e9d6e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/util/ZipFileUtils.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/util/ZipFileUtils.kt @@ -17,7 +17,8 @@ fun getZipEntryBytes( ): ByteArray { // fast path. Only read central directory record and try to find entry in it val zipBuilder = - ZipFile.builder() + ZipFile + .builder() .setPath(path) .setUseUnicodeExtraFields(true) .setIgnoreLocalFileHeader(true) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/AuthorsHandlerMethodArgumentResolver.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/AuthorsHandlerMethodArgumentResolver.kt index 4533226a..1d31a6f8 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/AuthorsHandlerMethodArgumentResolver.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/AuthorsHandlerMethodArgumentResolver.kt @@ -8,8 +8,7 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver import org.springframework.web.method.support.ModelAndViewContainer class AuthorsHandlerMethodArgumentResolver : HandlerMethodArgumentResolver { - override fun supportsParameter(parameter: MethodParameter): Boolean = - parameter.getParameterAnnotation(Authors::class.java) != null + override fun supportsParameter(parameter: MethodParameter): Boolean = parameter.getParameterAnnotation(Authors::class.java) != null override fun resolveArgument( parameter: MethodParameter, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/BracketParamsRequestWrapper.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/BracketParamsRequestWrapper.kt index 040d5a03..c481864b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/BracketParamsRequestWrapper.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/BracketParamsRequestWrapper.kt @@ -5,7 +5,9 @@ import jakarta.servlet.http.HttpServletRequestWrapper import org.gotson.komga.language.toEnumeration import java.util.Enumeration -class BracketParamsRequestWrapper(request: HttpServletRequest) : HttpServletRequestWrapper(request) { +class BracketParamsRequestWrapper( + request: HttpServletRequest, +) : HttpServletRequestWrapper(request) { override fun getParameter(name: String): String? { val nameWithoutSuffix = name.removeSuffix("[]") val values = listOfNotNull(super.getParameter(nameWithoutSuffix), super.getParameter("$nameWithoutSuffix[]")) @@ -27,12 +29,18 @@ class BracketParamsRequestWrapper(request: HttpServletRequest) : HttpServletRequ } override fun getParameterNames(): Enumeration = - super.getParameterNames().toList().map { it.removeSuffix("[]") }.distinct().toEnumeration() + super + .getParameterNames() + .toList() + .map { it.removeSuffix("[]") } + .distinct() + .toEnumeration() - override fun getParameterMap(): MutableMap> { - return super.getParameterMap().asSequence() + override fun getParameterMap(): MutableMap> = + super + .getParameterMap() + .asSequence() .groupBy({ it.key.removeSuffix("[]") }, { it.value }) .mapValues { it.value.reduce { acc, strings -> acc + strings } } .toMutableMap() - } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/DelimitedPairHandlerMethodArgumentResolver.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/DelimitedPairHandlerMethodArgumentResolver.kt index f57c8d49..bea55986 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/DelimitedPairHandlerMethodArgumentResolver.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/DelimitedPairHandlerMethodArgumentResolver.kt @@ -7,8 +7,7 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver import org.springframework.web.method.support.ModelAndViewContainer class DelimitedPairHandlerMethodArgumentResolver : HandlerMethodArgumentResolver { - override fun supportsParameter(parameter: MethodParameter): Boolean = - parameter.getParameterAnnotation(DelimitedPair::class.java) != null + override fun supportsParameter(parameter: MethodParameter): Boolean = parameter.getParameterAnnotation(DelimitedPair::class.java) != null override fun resolveArgument( parameter: MethodParameter, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/KoboMissingPortFilter.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/KoboMissingPortFilter.kt index 3489b5f6..adc19b95 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/KoboMissingPortFilter.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/KoboMissingPortFilter.kt @@ -6,7 +6,9 @@ import jakarta.servlet.http.HttpServletRequestWrapper import jakarta.servlet.http.HttpServletResponse import org.springframework.web.filter.OncePerRequestFilter -class KoboMissingPortFilter(private val koboPortSupplier: () -> Int?) : OncePerRequestFilter() { +class KoboMissingPortFilter( + private val koboPortSupplier: () -> Int?, +) : OncePerRequestFilter() { companion object { private val FORWARDED_HEADER_NAMES = setOf( @@ -56,7 +58,10 @@ class KoboMissingPortFilter(private val koboPortSupplier: () -> Int?) : OncePerR private fun formatRequest(request: HttpServletRequest) = "HTTP ${request.method} \"${request.requestURI}\"" - private class KoboMissingPortRequest(request: HttpServletRequest, val port: () -> Int?) : HttpServletRequestWrapper(request) { + private class KoboMissingPortRequest( + request: HttpServletRequest, + val port: () -> Int?, + ) : HttpServletRequestWrapper(request) { override fun getServerPort() = port() ?: request.serverPort } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/Utils.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/Utils.kt index 965a399b..9a4121fe 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/Utils.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/Utils.kt @@ -12,14 +12,11 @@ import java.util.concurrent.TimeUnit import kotlin.io.path.pathString import kotlin.io.path.toPath -fun URL.toFilePath(): String = - this.toURI().toPath().pathString +fun URL.toFilePath(): String = this.toURI().toPath().pathString -fun filePathToUrl(filePath: String): URL = - Paths.get(filePath).toUri().toURL() +fun filePathToUrl(filePath: String): URL = Paths.get(filePath).toUri().toURL() -fun ResponseEntity.BodyBuilder.setCachePrivate() = - this.cacheControl(cachePrivate) +fun ResponseEntity.BodyBuilder.setCachePrivate() = this.cacheControl(cachePrivate) val cachePrivate = CacheControl diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/WebMvcConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/WebMvcConfiguration.kt index 799be30b..536bb4ae 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/WebMvcConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/WebMvcConfiguration.kt @@ -13,7 +13,8 @@ import java.util.concurrent.TimeUnit class WebMvcConfiguration : WebMvcConfigurer { override fun addResourceHandlers(registry: ResourceHandlerRegistry) { if (!registry.hasMappingForPattern("/webjars/**")) { - registry.addResourceHandler("/webjars/**") + registry + .addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/") } @@ -35,8 +36,7 @@ class WebMvcConfiguration : WebMvcConfigurer { "/android-chrome-192x192.png", "/android-chrome-512x512.png", "/manifest.json", - ) - .addResourceLocations( + ).addResourceLocations( "classpath:public/index.html", "classpath:public/favicon.ico", "classpath:public/favicon-16x16.png", @@ -47,8 +47,7 @@ class WebMvcConfiguration : WebMvcConfigurer { "classpath:public/android-chrome-192x192.png", "classpath:public/android-chrome-512x512.png", "classpath:public/manifest.json", - ) - .setCacheControl(CacheControl.noStore()) + ).setCacheControl(CacheControl.noStore()) registry .addResourceHandler( @@ -56,14 +55,12 @@ class WebMvcConfiguration : WebMvcConfigurer { "/fonts/**", "/img/**", "/js/**", - ) - .addResourceLocations( + ).addResourceLocations( "classpath:public/css/", "classpath:public/fonts/", "classpath:public/img/", "classpath:public/js/", - ) - .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS).cachePublic()) + ).setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS).cachePublic()) } override fun addInterceptors(registry: InterceptorRegistry) { diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/xml/NamespaceXmlFactory.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/xml/NamespaceXmlFactory.kt index d306a31a..7cd7a57c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/xml/NamespaceXmlFactory.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/xml/NamespaceXmlFactory.kt @@ -18,29 +18,23 @@ class NamespaceXmlFactory( override fun _createXmlWriter( ctxt: IOContext?, w: Writer?, - ): XMLStreamWriter = - super._createXmlWriter(ctxt, w).apply { configure() } + ): XMLStreamWriter = super._createXmlWriter(ctxt, w).apply { configure() } override fun createGenerator( out: OutputStream?, enc: JsonEncoding?, - ): ToXmlGenerator = - super.createGenerator(out, enc).apply { staxWriter.configure() } + ): ToXmlGenerator = super.createGenerator(out, enc).apply { staxWriter.configure() } - override fun createGenerator(out: OutputStream?): ToXmlGenerator = - super.createGenerator(out).apply { staxWriter.configure() } + override fun createGenerator(out: OutputStream?): ToXmlGenerator = super.createGenerator(out).apply { staxWriter.configure() } - override fun createGenerator(out: Writer?): ToXmlGenerator = - super.createGenerator(out).apply { staxWriter.configure() } + override fun createGenerator(out: Writer?): ToXmlGenerator = super.createGenerator(out).apply { staxWriter.configure() } override fun createGenerator( f: File?, enc: JsonEncoding?, - ): ToXmlGenerator = - super.createGenerator(f, enc).apply { staxWriter.configure() } + ): ToXmlGenerator = super.createGenerator(f, enc).apply { staxWriter.configure() } - override fun createGenerator(sw: XMLStreamWriter?): ToXmlGenerator = - super.createGenerator(sw).apply { staxWriter.configure() } + override fun createGenerator(sw: XMLStreamWriter?): ToXmlGenerator = super.createGenerator(sw).apply { staxWriter.configure() } private fun XMLStreamWriter.configure() = try { diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/CommonBookController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/CommonBookController.kt index 116b8a80..185ba026 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/CommonBookController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/CommonBookController.kt @@ -74,59 +74,59 @@ class CommonBookController( principal: KomgaPrincipal, bookId: String, webPubGenerator: WebPubGenerator, - ) = - mediaRepository.findByIdOrNull(bookId)?.let { media -> - when (org.gotson.komga.domain.model.MediaType.fromMediaType(media.mediaType)?.profile) { - MediaProfile.DIVINA -> getWebPubManifestDivinaInternal(principal, bookId, webPubGenerator) - MediaProfile.PDF -> getWebPubManifestPdfInternal(principal, bookId, webPubGenerator) - MediaProfile.EPUB -> getWebPubManifestEpubInternal(principal, bookId, webPubGenerator) - null -> throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book analysis failed") - } - } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + ) = mediaRepository.findByIdOrNull(bookId)?.let { media -> + when ( + org.gotson.komga.domain.model.MediaType + .fromMediaType(media.mediaType) + ?.profile + ) { + MediaProfile.DIVINA -> getWebPubManifestDivinaInternal(principal, bookId, webPubGenerator) + MediaProfile.PDF -> getWebPubManifestPdfInternal(principal, bookId, webPubGenerator) + MediaProfile.EPUB -> getWebPubManifestEpubInternal(principal, bookId, webPubGenerator) + null -> throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book analysis failed") + } + } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) fun getWebPubManifestEpubInternal( principal: KomgaPrincipal, bookId: String, webPubGenerator: WebPubGenerator, - ) = - bookDtoRepository.findByIdOrNull(bookId, principal.user.id)?.let { bookDto -> - if (bookDto.media.mediaProfile != MediaProfile.EPUB.name) throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Book media type '${bookDto.media.mediaType}' not compatible with requested profile") - contentRestrictionChecker.checkContentRestriction(principal.user, bookDto) - webPubGenerator.toManifestEpub( - bookDto, - mediaRepository.findById(bookId), - seriesMetadataRepository.findById(bookDto.seriesId), - ) - } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + ) = bookDtoRepository.findByIdOrNull(bookId, principal.user.id)?.let { bookDto -> + if (bookDto.media.mediaProfile != MediaProfile.EPUB.name) throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Book media type '${bookDto.media.mediaType}' not compatible with requested profile") + contentRestrictionChecker.checkContentRestriction(principal.user, bookDto) + webPubGenerator.toManifestEpub( + bookDto, + mediaRepository.findById(bookId), + seriesMetadataRepository.findById(bookDto.seriesId), + ) + } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) fun getWebPubManifestPdfInternal( principal: KomgaPrincipal, bookId: String, webPubGenerator: WebPubGenerator, - ) = - bookDtoRepository.findByIdOrNull(bookId, principal.user.id)?.let { bookDto -> - if (bookDto.media.mediaProfile != MediaProfile.PDF.name) throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Book media type '${bookDto.media.mediaType}' not compatible with requested profile") - contentRestrictionChecker.checkContentRestriction(principal.user, bookDto) - webPubGenerator.toManifestPdf( - bookDto, - mediaRepository.findById(bookDto.id), - seriesMetadataRepository.findById(bookDto.seriesId), - ) - } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + ) = bookDtoRepository.findByIdOrNull(bookId, principal.user.id)?.let { bookDto -> + if (bookDto.media.mediaProfile != MediaProfile.PDF.name) throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Book media type '${bookDto.media.mediaType}' not compatible with requested profile") + contentRestrictionChecker.checkContentRestriction(principal.user, bookDto) + webPubGenerator.toManifestPdf( + bookDto, + mediaRepository.findById(bookDto.id), + seriesMetadataRepository.findById(bookDto.seriesId), + ) + } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) fun getWebPubManifestDivinaInternal( principal: KomgaPrincipal, bookId: String, webPubGenerator: WebPubGenerator, - ) = - bookDtoRepository.findByIdOrNull(bookId, principal.user.id)?.let { bookDto -> - contentRestrictionChecker.checkContentRestriction(principal.user, bookDto) - webPubGenerator.toManifestDivina( - bookDto, - mediaRepository.findById(bookDto.id), - seriesMetadataRepository.findById(bookDto.seriesId), - ) - } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + ) = bookDtoRepository.findByIdOrNull(bookId, principal.user.id)?.let { bookDto -> + contentRestrictionChecker.checkContentRestriction(principal.user, bookDto) + webPubGenerator.toManifestDivina( + bookDto, + mediaRepository.findById(bookDto.id), + seriesMetadataRepository.findById(bookDto.seriesId), + ) + } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) fun getBookPageInternal( bookId: String, @@ -135,62 +135,62 @@ class CommonBookController( request: ServletWebRequest, principal: KomgaPrincipal, acceptHeaders: MutableList?, - ) = - bookRepository.findByIdOrNull((bookId))?.let { book -> - val media = mediaRepository.findById(bookId) - if (request.checkNotModified(getBookLastModified(media))) { - return@let ResponseEntity - .status(HttpStatus.NOT_MODIFIED) - .setNotModified(media) - .body(ByteArray(0)) - } + ) = bookRepository.findByIdOrNull((bookId))?.let { book -> + val media = mediaRepository.findById(bookId) + if (request.checkNotModified(getBookLastModified(media))) { + return@let ResponseEntity + .status(HttpStatus.NOT_MODIFIED) + .setNotModified(media) + .body(ByteArray(0)) + } - contentRestrictionChecker.checkContentRestriction(principal.user, book) + contentRestrictionChecker.checkContentRestriction(principal.user, book) - if (media.profile == MediaProfile.PDF && acceptHeaders != null && acceptHeaders.any { it.isCompatibleWith(MediaType.APPLICATION_PDF) }) { - // keep only pdf and image - acceptHeaders.removeIf { !it.isCompatibleWith(MediaType.APPLICATION_PDF) && !it.isCompatibleWith(MediaType("image")) } - MimeTypeUtils.sortBySpecificity(acceptHeaders) - if (acceptHeaders.first().isCompatibleWith(MediaType.APPLICATION_PDF)) - return getBookPageRawInternal(book, media, pageNumber) - } + if (media.profile == MediaProfile.PDF && acceptHeaders != null && acceptHeaders.any { it.isCompatibleWith(MediaType.APPLICATION_PDF) }) { + // keep only pdf and image + acceptHeaders.removeIf { !it.isCompatibleWith(MediaType.APPLICATION_PDF) && !it.isCompatibleWith(MediaType("image")) } + MimeTypeUtils.sortBySpecificity(acceptHeaders) + if (acceptHeaders.first().isCompatibleWith(MediaType.APPLICATION_PDF)) + return getBookPageRawInternal(book, media, pageNumber) + } - try { - val convertFormat = - when (convertTo?.lowercase()) { - "jpeg" -> ImageType.JPEG - "png" -> ImageType.PNG - "", null -> null - else -> throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid conversion format: $convertTo") - } + try { + val convertFormat = + when (convertTo?.lowercase()) { + "jpeg" -> ImageType.JPEG + "png" -> ImageType.PNG + "", null -> null + else -> throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid conversion format: $convertTo") + } - val pageContent = bookLifecycle.getBookPage(book, pageNumber, convertFormat) + val pageContent = bookLifecycle.getBookPage(book, pageNumber, convertFormat) - ResponseEntity.ok() - .headers( - HttpHeaders().apply { - val extension = contentDetector.mediaTypeToExtension(pageContent.mediaType) ?: "jpeg" - val imageFileName = "${book.name}-$pageNumber$extension" - contentDisposition = - ContentDisposition.builder("inline") - .filename(imageFileName, StandardCharsets.UTF_8) - .build() - }, - ) - .contentType(getMediaTypeOrDefault(pageContent.mediaType)) - .setNotModified(media) - .body(pageContent.bytes) - } catch (ex: IndexOutOfBoundsException) { - throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Page number does not exist") - } catch (ex: ImageConversionException) { - throw ResponseStatusException(HttpStatus.NOT_FOUND, ex.message) - } catch (ex: MediaNotReadyException) { - throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book analysis failed") - } catch (ex: NoSuchFileException) { - logger.warn(ex) { "File not found: $book" } - throw ResponseStatusException(HttpStatus.NOT_FOUND, "File not found, it may have moved") - } - } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + ResponseEntity + .ok() + .headers( + HttpHeaders().apply { + val extension = contentDetector.mediaTypeToExtension(pageContent.mediaType) ?: "jpeg" + val imageFileName = "${book.name}-$pageNumber$extension" + contentDisposition = + ContentDisposition + .builder("inline") + .filename(imageFileName, StandardCharsets.UTF_8) + .build() + }, + ).contentType(getMediaTypeOrDefault(pageContent.mediaType)) + .setNotModified(media) + .body(pageContent.bytes) + } catch (ex: IndexOutOfBoundsException) { + throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Page number does not exist") + } catch (ex: ImageConversionException) { + throw ResponseStatusException(HttpStatus.NOT_FOUND, ex.message) + } catch (ex: MediaNotReadyException) { + throw ResponseStatusException(HttpStatus.NOT_FOUND, "Book analysis failed") + } catch (ex: NoSuchFileException) { + logger.warn(ex) { "File not found: $book" } + throw ResponseStatusException(HttpStatus.NOT_FOUND, "File not found, it may have moved") + } + } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @GetMapping( value = [ @@ -228,18 +228,19 @@ class CommonBookController( try { val pageContent = bookAnalyzer.getPageContentRaw(BookWithMedia(book, media), pageNumber) - ResponseEntity.ok() + ResponseEntity + .ok() .headers( HttpHeaders().apply { val extension = contentDetector.mediaTypeToExtension(pageContent.mediaType) ?: "" val pageFileName = "${book.name}-$pageNumber$extension" contentDisposition = - ContentDisposition.builder("inline") + ContentDisposition + .builder("inline") .filename(pageFileName, StandardCharsets.UTF_8) .build() }, - ) - .contentType(getMediaTypeOrDefault(pageContent.mediaType)) + ).contentType(getMediaTypeOrDefault(pageContent.mediaType)) .setNotModified(media) .body(pageContent.bytes) } catch (ex: IndexOutOfBoundsException) { @@ -292,16 +293,17 @@ class CommonBookController( throw ResponseStatusException(HttpStatus.NOT_FOUND) } - return ResponseEntity.ok() + return ResponseEntity + .ok() .headers( HttpHeaders().apply { contentDisposition = - ContentDisposition.builder("inline") + ContentDisposition + .builder("inline") .filename(FilenameUtils.getName(resourceName), StandardCharsets.UTF_8) .build() }, - ) - .contentType(getMediaTypeOrDefault(res.mediaType)) + ).contentType(getMediaTypeOrDefault(res.mediaType)) .setNotModified(media) .body(bytes) } @@ -340,16 +342,17 @@ class CommonBookController( os.close() } } - ResponseEntity.ok() + ResponseEntity + .ok() .headers( HttpHeaders().apply { contentDisposition = - ContentDisposition.builder("attachment") + ContentDisposition + .builder("attachment") .filename(book.path.name, StandardCharsets.UTF_8) .build() }, - ) - .contentType(getMediaTypeOrDefault(media.mediaType)) + ).contentType(getMediaTypeOrDefault(media.mediaType)) .contentLength(this.contentLength()) .body(stream) } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/OpdsGenerator.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/OpdsGenerator.kt index d77832ed..fae1f9dc 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/OpdsGenerator.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/OpdsGenerator.kt @@ -31,15 +31,19 @@ class OpdsGenerator( ) : WebPubGenerator(thumbnailType, imageConverter, bookAnalyzer, mediaRepository) { override val pathSegments = listOf("opds", "v2") - fun toOpdsPublicationDto(bookDto: BookDto): WPPublicationDto = - toBasePublicationDto(bookDto).copy(images = buildThumbnailLinkDtos(bookDto.id)) + fun toOpdsPublicationDto(bookDto: BookDto): WPPublicationDto = toBasePublicationDto(bookDto).copy(images = buildThumbnailLinkDtos(bookDto.id)) override fun getDefaultMediaType(): MediaType = MEDIATYPE_OPDS_PUBLICATION_JSON override fun getBookSeriesLink(bookDto: BookDto): List = listOf( WPLinkDto( - href = ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment(*pathSegments.toTypedArray()).path("series/${bookDto.seriesId}").toUriString(), + href = + ServletUriComponentsBuilder + .fromCurrentContextPath() + .pathSegment(*pathSegments.toTypedArray()) + .path("series/${bookDto.seriesId}") + .toUriString(), type = MEDIATYPE_OPDS_JSON_VALUE, ), ) @@ -48,27 +52,41 @@ class OpdsGenerator( mapOf( "authenticate" to mapOf( - "href" to ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment(*pathSegments.toTypedArray()).path(ROUTE_AUTH).toUriString(), + "href" to + ServletUriComponentsBuilder + .fromCurrentContextPath() + .pathSegment(*pathSegments.toTypedArray()) + .path(ROUTE_AUTH) + .toUriString(), "type" to MEDIATYPE_OPDS_AUTHENTICATION_JSON_VALUE, ), ) - override fun getExtraLinks(bookId: String): List { - return buildList { + override fun getExtraLinks(bookId: String): List = + buildList { add( WPLinkDto( type = MEDIATYPE_PROGRESSION_JSON_VALUE, rel = REL_PROGRESSION_API, - href = ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment(*pathSegments.toTypedArray()).path("books/$bookId/progression").toUriString(), + href = + ServletUriComponentsBuilder + .fromCurrentContextPath() + .pathSegment(*pathSegments.toTypedArray()) + .path("books/$bookId/progression") + .toUriString(), properties = getExtraLinkProperties(), ), ) } - } fun generateOpdsAuthDocument() = AuthenticationDocumentDto( - id = ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment(*pathSegments.toTypedArray()).path(ROUTE_AUTH).toUriString(), + id = + ServletUriComponentsBuilder + .fromCurrentContextPath() + .pathSegment(*pathSegments.toTypedArray()) + .path(ROUTE_AUTH) + .toUriString(), title = "Komga", description = "Enter your email and password to authenticate.", links = diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/Utils.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/Utils.kt index d8d00af9..c87156bb 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/Utils.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/Utils.kt @@ -5,8 +5,6 @@ import org.gotson.komga.infrastructure.web.setCachePrivate import org.springframework.http.ResponseEntity import java.time.ZoneOffset -fun getBookLastModified(media: Media) = - media.lastModifiedDate.toInstant(ZoneOffset.UTC).toEpochMilli() +fun getBookLastModified(media: Media) = media.lastModifiedDate.toInstant(ZoneOffset.UTC).toEpochMilli() -fun ResponseEntity.BodyBuilder.setNotModified(media: Media): ResponseEntity.BodyBuilder = - this.setCachePrivate().lastModified(getBookLastModified(media)) +fun ResponseEntity.BodyBuilder.setNotModified(media: Media): ResponseEntity.BodyBuilder = this.setCachePrivate().lastModified(getBookLastModified(media)) diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/WebPubGenerator.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/WebPubGenerator.kt index 160d4cbc..6b6260b6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/WebPubGenerator.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/WebPubGenerator.kt @@ -60,7 +60,12 @@ class WebPubGenerator( protected fun buildThumbnailLinkDtos(bookId: String) = listOf( WPLinkDto( - href = ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment(*pathSegments.toTypedArray()).path("books/$bookId/thumbnail").toUriString(), + href = + ServletUriComponentsBuilder + .fromCurrentContextPath() + .pathSegment(*pathSegments.toTypedArray()) + .path("books/$bookId/thumbnail") + .toUriString(), type = thumbnailType.mediaType, properties = getExtraLinkProperties(), ), @@ -80,7 +85,12 @@ class WebPubGenerator( readingOrder = pages.mapIndexed { index: Int, page: BookPage -> WPLinkDto( - href = uriBuilder.cloneBuilder().path("books/${bookDto.id}/pages/${index + 1}").queryParam("contentNegotiation", "false").toUriString(), + href = + uriBuilder + .cloneBuilder() + .path("books/${bookDto.id}/pages/${index + 1}") + .queryParam("contentNegotiation", "false") + .toUriString(), type = page.mediaType, width = page.dimension?.width, height = page.dimension?.height, @@ -88,7 +98,13 @@ class WebPubGenerator( if (!recommendedImageMediaTypes.contains(page.mediaType) && imageConverter.canConvertMediaType(page.mediaType, MediaType.IMAGE_JPEG_VALUE)) listOf( WPLinkDto( - href = uriBuilder.cloneBuilder().path("books/${bookDto.id}/pages/${index + 1}").queryParam("contentNegotiation", "false").queryParam("convert", "jpeg").toUriString(), + href = + uriBuilder + .cloneBuilder() + .path("books/${bookDto.id}/pages/${index + 1}") + .queryParam("contentNegotiation", "false") + .queryParam("convert", "jpeg") + .toUriString(), type = MediaType.IMAGE_JPEG_VALUE, width = page.dimension?.width, height = page.dimension?.height, @@ -153,7 +169,12 @@ class WebPubGenerator( readingOrder = media.files.filter { it.subType == MediaFile.SubType.EPUB_PAGE }.map { WPLinkDto( - href = uriBuilder.cloneBuilder().path("books/${bookDto.id}/resource/").path(it.fileName).toUriString(), + href = + uriBuilder + .cloneBuilder() + .path("books/${bookDto.id}/resource/") + .path(it.fileName) + .toUriString(), type = it.mediaType, ) }, @@ -161,7 +182,12 @@ class WebPubGenerator( buildThumbnailLinkDtos(bookDto.id) + media.files.filter { it.subType == MediaFile.SubType.EPUB_ASSET }.map { WPLinkDto( - href = uriBuilder.cloneBuilder().path("books/${bookDto.id}/resource/").path(it.fileName).toUriString(), + href = + uriBuilder + .cloneBuilder() + .path("books/${bookDto.id}/resource/") + .path(it.fileName) + .toUriString(), type = it.mediaType, ) }, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt index a1601f0b..943a0f74 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt @@ -177,12 +177,12 @@ class KoboController( private val contentRestrictionChecker: ContentRestrictionChecker, ) { private val cachedKepub = - Caffeine.newBuilder() + Caffeine + .newBuilder() .expireAfterAccess(5, TimeUnit.MINUTES) .removalListener { _, value, _ -> if (value?.deleteIfExists() == true) logger.debug { "Deleted cached kepub: $value" } - } - .build() + }.build() @GetMapping("ping") fun ping() = "pong" @@ -201,11 +201,26 @@ class KoboController( with(resources as ObjectNode) { put("image_host", ServletUriComponentsBuilder.fromCurrentContextPath().toUriString()) - put("image_url_template", ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment("kobo", authToken, "v1", "books", "{ImageId}", "thumbnail", "{Width}", "{Height}", "false", "image.jpg").build().toUriString()) - put("image_url_quality_template", ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment("kobo", authToken, "v1", "books", "{ImageId}", "thumbnail", "{Width}", "{Height}", "{Quality}", "{IsGreyscale}", "image.jpg").build().toUriString()) + put( + "image_url_template", + ServletUriComponentsBuilder + .fromCurrentContextPath() + .pathSegment("kobo", authToken, "v1", "books", "{ImageId}", "thumbnail", "{Width}", "{Height}", "false", "image.jpg") + .build() + .toUriString(), + ) + put( + "image_url_quality_template", + ServletUriComponentsBuilder + .fromCurrentContextPath() + .pathSegment("kobo", authToken, "v1", "books", "{ImageId}", "thumbnail", "{Width}", "{Height}", "{Quality}", "{IsGreyscale}", "image.jpg") + .build() + .toUriString(), + ) } - return ResponseEntity.ok() + return ResponseEntity + .ok() .header("x-kobo-apitoken", "e30=") .body(ResourcesDto(resources)) } @@ -333,7 +348,9 @@ class KoboController( logger.debug { "Library sync: ${booksAdded.numberOfElements} books added, ${booksChanged.numberOfElements} books changed, ${booksRemoved.numberOfElements} books removed, ${changedReadingState.numberOfElements} books with changed reading state, $readListsAdded readlists added, $readListsChanged readlists changed, $readListsRemoved removed" } val metadata = - koboDtoRepository.findBookMetadataByIds((booksAdded.content + booksChanged.content).map { it.bookId }).associateBy { it.entitlementId } + koboDtoRepository + .findBookMetadataByIds((booksAdded.content + booksChanged.content).map { it.bookId }) + .associateBy { it.entitlementId } .mapValues { it.value.withDownloadUrls(downloadUriBuilder) } val readProgress = readProgressRepository.findAllByBookIdsAndUserId((booksAdded.content + booksChanged.content + changedReadingState.content).map { it.bookId }, principal.user.id).associateBy { it.bookId } val readListsBooks = syncPointRepository.findBookIdsByReadListIds(toSyncPoint.id, (readListsAdded.content + readListsChanged.content).map { it.readListId }).groupBy { it.readListId } @@ -426,7 +443,9 @@ class KoboController( logger.debug { "Library sync: ${books.numberOfElements} books, ${readLists.numberOfElements} readlists" } val metadata = - koboDtoRepository.findBookMetadataByIds(books.content.map { it.bookId }).associateBy { it.entitlementId } + koboDtoRepository + .findBookMetadataByIds(books.content.map { it.bookId }) + .associateBy { it.entitlementId } .mapValues { it.value.withDownloadUrls(downloadUriBuilder) } val readProgress = readProgressRepository.findAllByBookIdsAndUserId(books.content.map { it.bookId }, principal.user.id).associateBy { it.bookId } val readListsBooks = syncPointRepository.findBookIdsByReadListIds(toSyncPoint.id, readLists.content.map { it.readListId }).groupBy { it.readListId } @@ -485,8 +504,7 @@ class KoboController( .headers { if (shouldContinueSyncMerged) it.set(X_KOBO_SYNC, "continue") it.set(X_KOBO_SYNCTOKEN, komgaSyncTokenGenerator.toBase64(syncTokenUpdated)) - } - .body(syncResultMerged) + }.body(syncResultMerged) } /** @@ -560,7 +578,13 @@ class KoboController( href = koboUpdate.currentBookmark.location.source, // assume default, will be overwritten by the correct type when saved type = "application/xhtml+xml", - koboSpan = if (koboUpdate.currentBookmark.location.type.contentEquals("kobospan", true)) koboUpdate.currentBookmark.location.value else null, + koboSpan = + if (koboUpdate.currentBookmark.location.type + .contentEquals("kobospan", true) + ) + koboUpdate.currentBookmark.location.value + else + null, locations = R2Locator.Location( progression = koboUpdate.currentBookmark.contentSourceProgressPercent / 100, @@ -645,16 +669,17 @@ class KoboController( os.close() } } - return ResponseEntity.ok() + return ResponseEntity + .ok() .headers( HttpHeaders().apply { contentDisposition = - ContentDisposition.builder("attachment") + ContentDisposition + .builder("attachment") .filename("${book.path.nameWithoutExtension}.kepub.epub", StandardCharsets.UTF_8) .build() }, - ) - .contentType(getMediaTypeOrDefault(EPUB.type)) + ).contentType(getMediaTypeOrDefault(EPUB.type)) .contentLength(contentLength()) .body(stream) } @@ -706,12 +731,11 @@ class KoboController( ) fun catchAll( @RequestBody body: Any?, - ): ResponseEntity { - return if (koboProxy.isEnabled()) + ): ResponseEntity = + if (koboProxy.isEnabled()) koboProxy.proxyCurrentRequest(body) else ResponseEntity.ok().body(mapper.createObjectNode()) - } private fun getDownloadUrlBuilder(token: String): UriBuilder = ServletUriComponentsBuilder @@ -791,8 +815,8 @@ class KoboController( private fun getEmptyReadProgressForBook( bookId: String, createdDate: ZonedDateTime, - ): ReadingStateDto { - return ReadingStateDto( + ): ReadingStateDto = + ReadingStateDto( created = createdDate, lastModified = createdDate, priorityTimestamp = createdDate, @@ -806,5 +830,4 @@ class KoboController( timesStartedReading = 0, ), ) - } } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateDto.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateDto.kt index f57d6ed5..1a7ee2d0 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateDto.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateDto.kt @@ -34,8 +34,16 @@ fun ReadProgress.toDto() = currentBookmark = BookmarkDto( lastModified = this.lastModifiedDate.toUTCZoned(), - progressPercent = this.locator?.locations?.totalProgression?.times(100), - contentSourceProgressPercent = this.locator?.locations?.progression?.times(100), + progressPercent = + this.locator + ?.locations + ?.totalProgression + ?.times(100), + contentSourceProgressPercent = + this.locator + ?.locations + ?.progression + ?.times(100), location = this.locator?.let { LocationDto(source = it.href, value = it.koboSpan) }, ), statistics = diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/OpdsController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/OpdsController.kt index 92c1908e..26772e90 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/OpdsController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/OpdsController.kt @@ -129,14 +129,13 @@ class OpdsController( private fun linkStart() = OpdsLinkFeedNavigation(OpdsLinkRel.START, uriBuilder(ROUTE_CATALOG).toUriString()) - private fun uriBuilder(path: String) = - ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment("opds", "v1.2").path(path) + private fun uriBuilder(path: String) = ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment("opds", "v1.2").path(path) private fun linkPage( uriBuilder: UriComponentsBuilder, page: Page, - ): List { - return listOfNotNull( + ): List = + listOfNotNull( if (!page.isFirst) OpdsLinkFeedNavigation( OpdsLinkRel.PREVIOUS, @@ -152,7 +151,6 @@ class OpdsController( else null, ) - } @GetMapping(ROUTE_CATALOG) fun getCatalog(): OpdsFeed = @@ -558,7 +556,8 @@ class OpdsController( val pageable = PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.asc("metadata.numberSort"))) val entries = - bookDtoRepository.findAll(bookSearch, SearchContext(principal.user), pageable) + bookDtoRepository + .findAll(bookSearch, SearchContext(principal.user), pageable) .map { it.toOpdsEntry(mediaRepository.findById(it.id)) } val uriBuilder = uriBuilder("series/$id") @@ -599,7 +598,8 @@ class OpdsController( val pageable = PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.asc("metadata.titleSort"))) val entries = - seriesDtoRepository.findAll(seriesSearch, SearchContext(principal.user), pageable) + seriesDtoRepository + .findAll(seriesSearch, SearchContext(principal.user), pageable) .map { it.toOpdsEntry() } val uriBuilder = uriBuilder("libraries/$id") @@ -643,7 +643,8 @@ class OpdsController( ) val entries = - seriesDtoRepository.findAll(seriesSearch, SearchContext(principal.user), pageable) + seriesDtoRepository + .findAll(seriesSearch, SearchContext(principal.user), pageable) .map { it.toOpdsEntry() } val uriBuilder = uriBuilder("collections/$id") @@ -740,8 +741,7 @@ class OpdsController( ) @RequestParam(value = "convert", required = false) convertTo: String?, - ): ResponseEntity = - commonBookController.getBookPageInternal(bookId, pageNumber + 1, convertTo, request, principal, null) + ): ResponseEntity = commonBookController.getBookPageInternal(bookId, pageNumber + 1, convertTo, request, principal, null) private fun SeriesDto.toOpdsEntry(prepend: Int? = null): OpdsEntryNavigation { val pre = prepend?.let { decimalFormat.format(it) + " - " } ?: "" @@ -833,6 +833,5 @@ class OpdsController( bookDto.toOpdsEntry(mediaRepository.findById(bookDto.id)) { "${it.seriesTitle} ${it.metadata.number}: " } } - private fun sanitize(fileName: String): String = - fileName.replace(";", "") + private fun sanitize(fileName: String): String = fileName.replace(";", "") } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/dto/OpdsLink.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/dto/OpdsLink.kt index 9847cc02..d8f9cfdb 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/dto/OpdsLink.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/dto/OpdsLink.kt @@ -15,46 +15,63 @@ open class OpdsLink( ) @JsonSerialize(`as` = OpdsLink::class) -class OpdsLinkFeedNavigation(rel: String, href: String) : OpdsLink( - type = "application/atom+xml;profile=opds-catalog;kind=navigation", - rel = rel, - href = href, -) +class OpdsLinkFeedNavigation( + rel: String, + href: String, +) : OpdsLink( + type = "application/atom+xml;profile=opds-catalog;kind=navigation", + rel = rel, + href = href, + ) @JsonSerialize(`as` = OpdsLink::class) -class OpdsLinkFeedAcquisition(rel: String, href: String) : OpdsLink( - type = "application/atom+xml;profile=opds-catalog;kind=acquisition", - rel = rel, - href = href, -) +class OpdsLinkFeedAcquisition( + rel: String, + href: String, +) : OpdsLink( + type = "application/atom+xml;profile=opds-catalog;kind=acquisition", + rel = rel, + href = href, + ) @JsonSerialize(`as` = OpdsLink::class) -class OpdsLinkImage(mediaType: String, href: String) : OpdsLink( - type = mediaType, - rel = "http://opds-spec.org/image", - href = href, -) +class OpdsLinkImage( + mediaType: String, + href: String, +) : OpdsLink( + type = mediaType, + rel = "http://opds-spec.org/image", + href = href, + ) @JsonSerialize(`as` = OpdsLink::class) -class OpdsLinkImageThumbnail(mediaType: String, href: String) : OpdsLink( - type = mediaType, - rel = "http://opds-spec.org/image/thumbnail", - href = href, -) +class OpdsLinkImageThumbnail( + mediaType: String, + href: String, +) : OpdsLink( + type = mediaType, + rel = "http://opds-spec.org/image/thumbnail", + href = href, + ) @JsonSerialize(`as` = OpdsLink::class) -class OpdsLinkFileAcquisition(mediaType: String?, href: String) : OpdsLink( - type = mediaType ?: "application/octet-stream", - rel = "http://opds-spec.org/acquisition", - href = href, -) +class OpdsLinkFileAcquisition( + mediaType: String?, + href: String, +) : OpdsLink( + type = mediaType ?: "application/octet-stream", + rel = "http://opds-spec.org/acquisition", + href = href, + ) @JsonSerialize(`as` = OpdsLink::class) -class OpdsLinkSearch(href: String) : OpdsLink( - type = "application/opensearchdescription+xml", - rel = "search", - href = href, -) +class OpdsLinkSearch( + href: String, +) : OpdsLink( + type = "application/opensearchdescription+xml", + rel = "search", + href = href, + ) class OpdsLinkPageStreaming( mediaType: String, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v2/Opds2Controller.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v2/Opds2Controller.kt index 792f0b36..5770133f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v2/Opds2Controller.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v2/Opds2Controller.kt @@ -100,8 +100,8 @@ class Opds2Controller( private fun linkPage( uriBuilder: UriComponentsBuilder, page: Page<*>, - ): List { - return listOfNotNull( + ): List = + listOfNotNull( if (!page.isFirst) WPLinkDto( rel = OpdsLinkRel.PREVIOUS, @@ -117,7 +117,6 @@ class Opds2Controller( else null, ) - } private fun linkSelf( path: String, @@ -183,57 +182,61 @@ class Opds2Controller( val (library, authorizedLibraryIds) = checkLibraryAccess(libraryId, principal) val keepReading = - bookDtoRepository.findAll( - BookSearch( - SearchCondition.AllOfBook( - buildList { - if (library != null) add(SearchCondition.LibraryId(SearchOperator.Is(library.id))) - add(SearchCondition.MediaStatus(SearchOperator.Is(Media.Status.READY))) - add(SearchCondition.Deleted(SearchOperator.IsFalse)) - }, + bookDtoRepository + .findAll( + BookSearch( + SearchCondition.AllOfBook( + buildList { + if (library != null) add(SearchCondition.LibraryId(SearchOperator.Is(library.id))) + add(SearchCondition.MediaStatus(SearchOperator.Is(Media.Status.READY))) + add(SearchCondition.Deleted(SearchOperator.IsFalse)) + }, + ), ), - ), - SearchContext(principal.user), - PageRequest.of(0, RECOMMENDED_ITEMS_NUMBER, Sort.by(Sort.Order.desc("readProgress.readDate"))), - ).map { opdsGenerator.toOpdsPublicationDto(it) } + SearchContext(principal.user), + PageRequest.of(0, RECOMMENDED_ITEMS_NUMBER, Sort.by(Sort.Order.desc("readProgress.readDate"))), + ).map { opdsGenerator.toOpdsPublicationDto(it) } val onDeck = - bookDtoRepository.findAllOnDeck( - principal.user.id, - authorizedLibraryIds, - Pageable.ofSize(RECOMMENDED_ITEMS_NUMBER), - principal.user.restrictions, - ).map { opdsGenerator.toOpdsPublicationDto(it) } + bookDtoRepository + .findAllOnDeck( + principal.user.id, + authorizedLibraryIds, + Pageable.ofSize(RECOMMENDED_ITEMS_NUMBER), + principal.user.restrictions, + ).map { opdsGenerator.toOpdsPublicationDto(it) } val latestBooks = - bookDtoRepository.findAll( - BookSearch( - SearchCondition.AllOfBook( - buildList { - if (library != null) add(SearchCondition.LibraryId(SearchOperator.Is(library.id))) - add(SearchCondition.MediaStatus(SearchOperator.Is(Media.Status.READY))) - add(SearchCondition.Deleted(SearchOperator.IsFalse)) - }, + bookDtoRepository + .findAll( + BookSearch( + SearchCondition.AllOfBook( + buildList { + if (library != null) add(SearchCondition.LibraryId(SearchOperator.Is(library.id))) + add(SearchCondition.MediaStatus(SearchOperator.Is(Media.Status.READY))) + add(SearchCondition.Deleted(SearchOperator.IsFalse)) + }, + ), ), - ), - SearchContext(principal.user), - PageRequest.of(0, RECOMMENDED_ITEMS_NUMBER, Sort.by(Sort.Order.desc("createdDate"))), - ).map { opdsGenerator.toOpdsPublicationDto(it) } + SearchContext(principal.user), + PageRequest.of(0, RECOMMENDED_ITEMS_NUMBER, Sort.by(Sort.Order.desc("createdDate"))), + ).map { opdsGenerator.toOpdsPublicationDto(it) } val latestSeries = - seriesDtoRepository.findAll( - SeriesSearch( - SearchCondition.AllOfSeries( - buildList { - if (library != null) add(SearchCondition.LibraryId(SearchOperator.Is(library.id))) - add(SearchCondition.Deleted(SearchOperator.IsFalse)) - add(SearchCondition.OneShot(SearchOperator.IsFalse)) - }, + seriesDtoRepository + .findAll( + SeriesSearch( + SearchCondition.AllOfSeries( + buildList { + if (library != null) add(SearchCondition.LibraryId(SearchOperator.Is(library.id))) + add(SearchCondition.Deleted(SearchOperator.IsFalse)) + add(SearchCondition.OneShot(SearchOperator.IsFalse)) + }, + ), ), - ), - SearchContext(principal.user), - PageRequest.of(0, RECOMMENDED_ITEMS_NUMBER, Sort.by(Sort.Order.desc("lastModified"))), - ).map { it.toWPLinkDto() } + SearchContext(principal.user), + PageRequest.of(0, RECOMMENDED_ITEMS_NUMBER, Sort.by(Sort.Order.desc("lastModified"))), + ).map { it.toWPLinkDto() } val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}") @@ -299,17 +302,18 @@ class Opds2Controller( val (library, _) = checkLibraryAccess(libraryId, principal) val entries = - bookDtoRepository.findAll( - BookSearch( - SearchCondition.AllOfBook( - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS)), - SearchCondition.MediaStatus(SearchOperator.Is(Media.Status.READY)), - SearchCondition.Deleted(SearchOperator.IsFalse), + bookDtoRepository + .findAll( + BookSearch( + SearchCondition.AllOfBook( + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS)), + SearchCondition.MediaStatus(SearchOperator.Is(Media.Status.READY)), + SearchCondition.Deleted(SearchOperator.IsFalse), + ), ), - ), - SearchContext(principal.user), - PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.desc("readProgress.readDate"))), - ).map { opdsGenerator.toOpdsPublicationDto(it) } + SearchContext(principal.user), + PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.desc("readProgress.readDate"))), + ).map { opdsGenerator.toOpdsPublicationDto(it) } val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/keep-reading") @@ -341,12 +345,13 @@ class Opds2Controller( val (library, authorizedLibraryIds) = checkLibraryAccess(libraryId, principal) val entries = - bookDtoRepository.findAllOnDeck( - principal.user.id, - authorizedLibraryIds, - page, - principal.user.restrictions, - ).map { opdsGenerator.toOpdsPublicationDto(it) } + bookDtoRepository + .findAllOnDeck( + principal.user.id, + authorizedLibraryIds, + page, + principal.user.restrictions, + ).map { opdsGenerator.toOpdsPublicationDto(it) } val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/on-deck") @@ -378,16 +383,17 @@ class Opds2Controller( val (library, _) = checkLibraryAccess(libraryId, principal) val entries = - bookDtoRepository.findAll( - BookSearch( - SearchCondition.AllOfBook( - SearchCondition.MediaStatus(SearchOperator.Is(Media.Status.READY)), - SearchCondition.Deleted(SearchOperator.IsFalse), + bookDtoRepository + .findAll( + BookSearch( + SearchCondition.AllOfBook( + SearchCondition.MediaStatus(SearchOperator.Is(Media.Status.READY)), + SearchCondition.Deleted(SearchOperator.IsFalse), + ), ), - ), - SearchContext(principal.user), - PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.desc("createdDate"))), - ).map { opdsGenerator.toOpdsPublicationDto(it) } + SearchContext(principal.user), + PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.desc("createdDate"))), + ).map { opdsGenerator.toOpdsPublicationDto(it) } val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/books/latest") @@ -419,19 +425,20 @@ class Opds2Controller( val (library, _) = checkLibraryAccess(libraryId, principal) val entries = - seriesDtoRepository.findAll( - SeriesSearch( - SearchCondition.AllOfSeries( - buildList { - if (library != null) add(SearchCondition.LibraryId(SearchOperator.Is(library.id))) - add(SearchCondition.Deleted(SearchOperator.IsFalse)) - add(SearchCondition.OneShot(SearchOperator.IsFalse)) - }, + seriesDtoRepository + .findAll( + SeriesSearch( + SearchCondition.AllOfSeries( + buildList { + if (library != null) add(SearchCondition.LibraryId(SearchOperator.Is(library.id))) + add(SearchCondition.Deleted(SearchOperator.IsFalse)) + add(SearchCondition.OneShot(SearchOperator.IsFalse)) + }, + ), ), - ), - SearchContext(principal.user), - PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.desc("lastModified"))), - ).map { it.toWPLinkDto() } + SearchContext(principal.user), + PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.desc("lastModified"))), + ).map { it.toWPLinkDto() } val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/books/latest") @@ -525,11 +532,12 @@ class Opds2Controller( val pageable = PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.asc("name"))) val entries = - collectionRepository.findAll( - authorizedLibraryIds, - authorizedLibraryIds, - pageable = pageable, - ).map { it.toWPLinkDto() } + collectionRepository + .findAll( + authorizedLibraryIds, + authorizedLibraryIds, + pageable = pageable, + ).map { it.toWPLinkDto() } val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/collections") @@ -610,11 +618,12 @@ class Opds2Controller( val pageable = PageRequest.of(page.pageNumber, page.pageSize, Sort.by(Sort.Order.asc("name"))) val entries = - readListRepository.findAll( - authorizedLibraryIds, - authorizedLibraryIds, - pageable = pageable, - ).map { it.toWPLinkDto() } + readListRepository + .findAll( + authorizedLibraryIds, + authorizedLibraryIds, + pageable = pageable, + ).map { it.toWPLinkDto() } val uriBuilder = uriBuilder("libraries${if (library != null) "/${library.id}" else ""}/readlists") @@ -773,55 +782,59 @@ class Opds2Controller( val queryTerms = query?.split("\\s+".toRegex()) val resultsSeries = - seriesDtoRepository.findAll( - SeriesSearch( - SearchCondition.AllOfSeries( - buildList { - add(SearchCondition.OneShot(SearchOperator.IsFalse)) - add(SearchCondition.Deleted(SearchOperator.IsFalse)) - if (!queryTerms.isNullOrEmpty()) { - add(SearchCondition.AllOfSeries(queryTerms.map { SearchCondition.Title(SearchOperator.Contains(it)) })) - } - }, + seriesDtoRepository + .findAll( + SeriesSearch( + SearchCondition.AllOfSeries( + buildList { + add(SearchCondition.OneShot(SearchOperator.IsFalse)) + add(SearchCondition.Deleted(SearchOperator.IsFalse)) + if (!queryTerms.isNullOrEmpty()) { + add(SearchCondition.AllOfSeries(queryTerms.map { SearchCondition.Title(SearchOperator.Contains(it)) })) + } + }, + ), ), - ), - SearchContext(principal.user), - pageable, - ).map { it.toWPLinkDto() } + SearchContext(principal.user), + pageable, + ).map { it.toWPLinkDto() } val resultsBooks = - bookDtoRepository.findAll( - BookSearch( - SearchCondition.AllOfBook( - buildList { - add(SearchCondition.Deleted(SearchOperator.IsFalse)) - if (!queryTerms.isNullOrEmpty()) { - add(SearchCondition.AllOfBook(queryTerms.map { SearchCondition.Title(SearchOperator.Contains(it)) })) - } - }, + bookDtoRepository + .findAll( + BookSearch( + SearchCondition.AllOfBook( + buildList { + add(SearchCondition.Deleted(SearchOperator.IsFalse)) + if (!queryTerms.isNullOrEmpty()) { + add(SearchCondition.AllOfBook(queryTerms.map { SearchCondition.Title(SearchOperator.Contains(it)) })) + } + }, + ), ), - ), - SearchContext(principal.user), - pageable, - ).map { opdsGenerator.toOpdsPublicationDto(it) } + SearchContext(principal.user), + pageable, + ).map { opdsGenerator.toOpdsPublicationDto(it) } val resultsCollections = - collectionRepository.findAll( - principal.user.getAuthorizedLibraryIds(null), - principal.user.getAuthorizedLibraryIds(null), - query, - pageable, - principal.user.restrictions, - ).map { it.toWPLinkDto() } + collectionRepository + .findAll( + principal.user.getAuthorizedLibraryIds(null), + principal.user.getAuthorizedLibraryIds(null), + query, + pageable, + principal.user.restrictions, + ).map { it.toWPLinkDto() } val resultsReadLists = - readListRepository.findAll( - principal.user.getAuthorizedLibraryIds(null), - principal.user.getAuthorizedLibraryIds(null), - query, - pageable, - principal.user.restrictions, - ).map { it.toWPLinkDto() } + readListRepository + .findAll( + principal.user.getAuthorizedLibraryIds(null), + principal.user.getAuthorizedLibraryIds(null), + query, + pageable, + principal.user.restrictions, + ).map { it.toWPLinkDto() } return FeedDto( metadata = @@ -864,8 +877,7 @@ class Opds2Controller( ) @RequestParam(value = "convert", required = false) convertTo: String?, - ): ResponseEntity = - commonBookController.getBookPageInternal(bookId, pageNumber, convertTo, request, principal, null) + ): ResponseEntity = commonBookController.getBookPageInternal(bookId, pageNumber, convertTo, request, principal, null) @GetMapping( value = ["books/{bookId}/manifest"], @@ -874,8 +886,7 @@ class Opds2Controller( fun getWebPubManifest( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, - ): WPPublicationDto = - commonBookController.getWebPubManifestInternal(principal, bookId, opdsGenerator) + ): WPPublicationDto = commonBookController.getWebPubManifestInternal(principal, bookId, opdsGenerator) @GetMapping( value = ["books/{bookId}/manifest/epub"], @@ -884,8 +895,7 @@ class Opds2Controller( fun getWebPubManifestEpub( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, - ): WPPublicationDto = - commonBookController.getWebPubManifestEpubInternal(principal, bookId, opdsGenerator) + ): WPPublicationDto = commonBookController.getWebPubManifestEpubInternal(principal, bookId, opdsGenerator) @GetMapping( value = ["books/{bookId}/manifest/pdf"], @@ -894,8 +904,7 @@ class Opds2Controller( fun getWebPubManifestPdf( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, - ): WPPublicationDto = - commonBookController.getWebPubManifestPdfInternal(principal, bookId, opdsGenerator) + ): WPPublicationDto = commonBookController.getWebPubManifestPdfInternal(principal, bookId, opdsGenerator) @GetMapping( value = ["books/{bookId}/manifest/divina"], @@ -904,8 +913,7 @@ class Opds2Controller( fun getWebPubManifestDivina( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, - ): WPPublicationDto = - commonBookController.getWebPubManifestDivinaInternal(principal, bookId, opdsGenerator) + ): WPPublicationDto = commonBookController.getWebPubManifestDivinaInternal(principal, bookId, opdsGenerator) private fun Library.toWPLinkDto(): WPLinkDto = WPLinkDto( diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementController.kt index 85d851b3..c57fb79f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementController.kt @@ -29,7 +29,8 @@ class AnnouncementController( private val webClient = WebClient.create("$WEBSITE/blog/feed.json") private val cache = - Caffeine.newBuilder() + Caffeine + .newBuilder() .expireAfterAccess(1, TimeUnit.DAYS) .build() @@ -37,14 +38,14 @@ class AnnouncementController( @PreAuthorize("hasRole('$ROLE_ADMIN')") fun getAnnouncements( @AuthenticationPrincipal principal: KomgaPrincipal, - ): JsonFeedDto { - return cache.get("announcements") { fetchWebsiteAnnouncements() } + ): JsonFeedDto = + cache + .get("announcements") { fetchWebsiteAnnouncements() } ?.let { feed -> val read = userRepository.findAnnouncementIdsReadByUserId(principal.user.id) feed.copy(items = feed.items.map { item -> item.copy(komgaExtension = JsonFeedDto.KomgaExtensionDto(read.contains(item.id))) }) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) - } @PreAuthorize("hasRole('$ROLE_ADMIN')") @PutMapping @@ -58,7 +59,8 @@ class AnnouncementController( fun fetchWebsiteAnnouncements(): JsonFeedDto? { val response = - webClient.get() + webClient + .get() .retrieve() .toEntity(JsonFeedDto::class.java) .block() diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/BookController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/BookController.kt index 43ddaad1..691f3b66 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/BookController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/BookController.kt @@ -165,7 +165,8 @@ class BookController( searchTerm, ) - return bookDtoRepository.findAll(bookSearch, SearchContext(principal.user), pageRequest) + return bookDtoRepository + .findAll(bookSearch, SearchContext(principal.user), pageRequest) .map { it.restrictUrl(!principal.user.roleAdmin) } } @@ -189,10 +190,11 @@ class BookController( sort, ) - return bookDtoRepository.findAll( - SearchContext(principal.user), - pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + return bookDtoRepository + .findAll( + SearchContext(principal.user), + pageRequest, + ).map { it.restrictUrl(!principal.user.roleAdmin) } } @Operation(description = "Return first unread book of series with at least one book read and no books in progress.") @@ -203,12 +205,13 @@ class BookController( @RequestParam(name = "library_id", required = false) libraryIds: List? = null, @Parameter(hidden = true) page: Pageable, ): Page = - bookDtoRepository.findAllOnDeck( - principal.user.id, - principal.user.getAuthorizedLibraryIds(libraryIds), - page, - principal.user.restrictions, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + bookDtoRepository + .findAllOnDeck( + principal.user.id, + principal.user.getAuthorizedLibraryIds(libraryIds), + page, + principal.user.restrictions, + ).map { it.restrictUrl(!principal.user.roleAdmin) } @PageableAsQueryParam @GetMapping("api/v1/books/duplicates") @@ -255,7 +258,8 @@ class BookController( ): BookDto { contentRestrictionChecker.checkContentRestriction(principal.user, bookId) - return bookDtoRepository.findPreviousInSeriesOrNull(bookId, principal.user.id) + return bookDtoRepository + .findPreviousInSeriesOrNull(bookId, principal.user.id) ?.restrictUrl(!principal.user.roleAdmin) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } @@ -267,7 +271,8 @@ class BookController( ): BookDto { contentRestrictionChecker.checkContentRestriction(principal.user, bookId) - return bookDtoRepository.findNextInSeriesOrNull(bookId, principal.user.id) + return bookDtoRepository + .findNextInSeriesOrNull(bookId, principal.user.id) ?.restrictUrl(!principal.user.roleAdmin) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } @@ -279,7 +284,8 @@ class BookController( ): List { contentRestrictionChecker.checkContentRestriction(principal.user, bookId) - return readListRepository.findAllContainingBookId(bookId, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions) + return readListRepository + .findAllContainingBookId(bookId, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions) .map { it.toDto() } } @@ -317,7 +323,8 @@ class BookController( ): Collection { contentRestrictionChecker.checkContentRestriction(principal.user, bookId) - return thumbnailBookRepository.findAllByBookId(bookId) + return thumbnailBookRepository + .findAllByBookId(bookId) .map { it.toDto() } } @@ -335,18 +342,19 @@ class BookController( if (!contentDetector.isImage(mediaType)) throw ResponseStatusException(HttpStatus.UNSUPPORTED_MEDIA_TYPE) - return bookLifecycle.addThumbnailForBook( - ThumbnailBook( - bookId = book.id, - thumbnail = file.bytes, - type = ThumbnailBook.Type.USER_UPLOADED, - selected = selected, - fileSize = file.bytes.size.toLong(), - mediaType = mediaType, - dimension = imageAnalyzer.getDimension(file.inputStream.buffered()) ?: Dimension(0, 0), - ), - if (selected) MarkSelectedPreference.YES else MarkSelectedPreference.NO, - ).toDto() + return bookLifecycle + .addThumbnailForBook( + ThumbnailBook( + bookId = book.id, + thumbnail = file.bytes, + type = ThumbnailBook.Type.USER_UPLOADED, + selected = selected, + fileSize = file.bytes.size.toLong(), + mediaType = mediaType, + dimension = imageAnalyzer.getDimension(file.inputStream.buffered()) ?: Dimension(0, 0), + ), + if (selected) MarkSelectedPreference.YES else MarkSelectedPreference.NO, + ).toDto() } @PutMapping("api/v1/books/{bookId}/thumbnails/{thumbnailId}/selected") @@ -439,8 +447,7 @@ class BookController( acceptHeaders: MutableList?, @RequestParam(value = "contentNegotiation", defaultValue = "true") contentNegotiation: Boolean, - ): ResponseEntity = - commonBookController.getBookPageInternal(bookId, if (zeroBasedIndex) pageNumber + 1 else pageNumber, convertTo, request, principal, if (contentNegotiation) acceptHeaders else null) + ): ResponseEntity = commonBookController.getBookPageInternal(bookId, if (zeroBasedIndex) pageNumber + 1 else pageNumber, convertTo, request, principal, if (contentNegotiation) acceptHeaders else null) @ApiResponse(content = [Content(schema = Schema(type = "string", format = "binary"))]) @GetMapping( @@ -467,7 +474,8 @@ class BookController( try { val pageContent = bookLifecycle.getBookPage(book, pageNumber, resizeTo = 300) - ResponseEntity.ok() + ResponseEntity + .ok() .contentType(getMediaTypeOrDefault(pageContent.mediaType)) .setNotModified(media) .body(pageContent.bytes) @@ -492,7 +500,8 @@ class BookController( @PathVariable bookId: String, ): ResponseEntity { val manifest = commonBookController.getWebPubManifestInternal(principal, bookId, webPubGenerator) - return ResponseEntity.ok() + return ResponseEntity + .ok() .contentType(manifest.mediaType) .body(manifest) } @@ -522,7 +531,8 @@ class BookController( mediaRepository.findExtensionByIdOrNull(book.id) as? MediaExtensionEpub ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) - ResponseEntity.ok() + ResponseEntity + .ok() .contentType(MEDIATYPE_POSITION_LIST_JSON) .setNotModified(media) .body(R2Positions(extension.positions.size, extension.positions)) @@ -535,8 +545,7 @@ class BookController( fun getWebPubManifestEpub( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, - ): WPPublicationDto = - commonBookController.getWebPubManifestEpubInternal(principal, bookId, webPubGenerator) + ): WPPublicationDto = commonBookController.getWebPubManifestEpubInternal(principal, bookId, webPubGenerator) @GetMapping( value = ["api/v1/books/{bookId}/manifest/pdf"], @@ -545,8 +554,7 @@ class BookController( fun getWebPubManifestPdf( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, - ): WPPublicationDto = - commonBookController.getWebPubManifestPdfInternal(principal, bookId, webPubGenerator) + ): WPPublicationDto = commonBookController.getWebPubManifestPdfInternal(principal, bookId, webPubGenerator) @GetMapping( value = ["api/v1/books/{bookId}/manifest/divina"], @@ -555,8 +563,7 @@ class BookController( fun getWebPubManifestDivina( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, - ): WPPublicationDto = - commonBookController.getWebPubManifestDivinaInternal(principal, bookId, webPubGenerator) + ): WPPublicationDto = commonBookController.getWebPubManifestDivinaInternal(principal, bookId, webPubGenerator) @PostMapping("api/v1/books/{bookId}/analyze") @PreAuthorize("hasRole('$ROLE_ADMIN')") @@ -590,16 +597,15 @@ class BookController( @Valid @RequestBody newMetadata: BookMetadataUpdateDto, - ) = - bookMetadataRepository.findByIdOrNull(bookId)?.let { existing -> - val updated = existing.patch(newMetadata) - bookMetadataRepository.update(updated) + ) = bookMetadataRepository.findByIdOrNull(bookId)?.let { existing -> + val updated = existing.patch(newMetadata) + bookMetadataRepository.update(updated) - bookRepository.findByIdOrNull(bookId)?.let { updatedBook -> - taskEmitter.aggregateSeriesMetadata(updatedBook.seriesId) - updatedBook.let { eventPublisher.publishEvent(DomainEvent.BookUpdated(it)) } - } - } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + bookRepository.findByIdOrNull(bookId)?.let { updatedBook -> + taskEmitter.aggregateSeriesMetadata(updatedBook.seriesId) + updatedBook.let { eventPublisher.publishEvent(DomainEvent.BookUpdated(it)) } + } + } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @PatchMapping("api/v1/books/metadata") @PreAuthorize("hasRole('$ROLE_ADMIN')") diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ClaimController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ClaimController.kt index a767505f..1f7ce0ad 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ClaimController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ClaimController.kt @@ -37,16 +37,17 @@ class ClaimController( if (userDetailsLifecycle.countUsers() > 0) throw ResponseStatusException(HttpStatus.BAD_REQUEST, "This server has already been claimed") - return userDetailsLifecycle.createUser( - KomgaUser( - email = email, - password = password, - roleAdmin = true, - roleFileDownload = true, - rolePageStreaming = true, - roleKoboSync = true, - ), - ).toDto() + return userDetailsLifecycle + .createUser( + KomgaUser( + email = email, + password = password, + roleAdmin = true, + roleFileDownload = true, + rolePageStreaming = true, + roleKoboSync = true, + ), + ).toDto() } data class ClaimStatus( diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemController.kt index bde964c8..8af454c2 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemController.kt @@ -37,7 +37,8 @@ class FileSystemController { try { val (directories, files) = Files.list(directory).use { dirStream -> - dirStream.asSequence() + dirStream + .asSequence() .filter { !Files.isHidden(it) && (if (!request.showFiles) Files.isDirectory(it) else true) } .sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.toString() }) .map { it.toDto() } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/LibraryController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/LibraryController.kt index 9b4c5b13..a81869af 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/LibraryController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/LibraryController.kt @@ -80,37 +80,38 @@ class LibraryController( library: LibraryCreationDto, ): LibraryDto = try { - libraryLifecycle.addLibrary( - Library( - name = library.name, - root = filePathToUrl(library.root), - importComicInfoBook = library.importComicInfoBook, - importComicInfoSeries = library.importComicInfoSeries, - importComicInfoCollection = library.importComicInfoCollection, - importComicInfoReadList = library.importComicInfoReadList, - importComicInfoSeriesAppendVolume = library.importComicInfoSeriesAppendVolume, - importEpubBook = library.importEpubBook, - importEpubSeries = library.importEpubSeries, - importMylarSeries = library.importMylarSeries, - importLocalArtwork = library.importLocalArtwork, - importBarcodeIsbn = library.importBarcodeIsbn, - scanForceModifiedTime = library.scanForceModifiedTime, - scanInterval = library.scanInterval.toDomain(), - scanOnStartup = library.scanOnStartup, - scanCbx = library.scanCbx, - scanPdf = library.scanPdf, - scanEpub = library.scanEpub, - scanDirectoryExclusions = library.scanDirectoryExclusions, - repairExtensions = library.repairExtensions, - convertToCbz = library.convertToCbz, - emptyTrashAfterScan = library.emptyTrashAfterScan, - seriesCover = library.seriesCover.toDomain(), - hashFiles = library.hashFiles, - hashPages = library.hashPages, - analyzeDimensions = library.analyzeDimensions, - oneshotsDirectory = library.oneshotsDirectory?.ifBlank { null }, - ), - ).toDto(includeRoot = principal.user.roleAdmin) + libraryLifecycle + .addLibrary( + Library( + name = library.name, + root = filePathToUrl(library.root), + importComicInfoBook = library.importComicInfoBook, + importComicInfoSeries = library.importComicInfoSeries, + importComicInfoCollection = library.importComicInfoCollection, + importComicInfoReadList = library.importComicInfoReadList, + importComicInfoSeriesAppendVolume = library.importComicInfoSeriesAppendVolume, + importEpubBook = library.importEpubBook, + importEpubSeries = library.importEpubSeries, + importMylarSeries = library.importMylarSeries, + importLocalArtwork = library.importLocalArtwork, + importBarcodeIsbn = library.importBarcodeIsbn, + scanForceModifiedTime = library.scanForceModifiedTime, + scanInterval = library.scanInterval.toDomain(), + scanOnStartup = library.scanOnStartup, + scanCbx = library.scanCbx, + scanPdf = library.scanPdf, + scanEpub = library.scanEpub, + scanDirectoryExclusions = library.scanDirectoryExclusions, + repairExtensions = library.repairExtensions, + convertToCbz = library.convertToCbz, + emptyTrashAfterScan = library.emptyTrashAfterScan, + seriesCover = library.seriesCover.toDomain(), + hashFiles = library.hashFiles, + hashPages = library.hashPages, + analyzeDimensions = library.analyzeDimensions, + oneshotsDirectory = library.oneshotsDirectory?.ifBlank { null }, + ), + ).toDto(includeRoot = principal.user.roleAdmin) } catch (e: Exception) { when (e) { is FileNotFoundException, @@ -227,11 +228,12 @@ class LibraryController( @PathVariable libraryId: String, ) { val books = - bookRepository.findAll( - SearchCondition.LibraryId(SearchOperator.Is(libraryId)), - SearchContext.empty(), - Pageable.unpaged(), - ).content + bookRepository + .findAll( + SearchCondition.LibraryId(SearchOperator.Is(libraryId)), + SearchContext.empty(), + Pageable.unpaged(), + ).content taskEmitter.analyzeBook(books, HIGH_PRIORITY) } @@ -242,11 +244,12 @@ class LibraryController( @PathVariable libraryId: String, ) { val books = - bookRepository.findAll( - SearchCondition.LibraryId(SearchOperator.Is(libraryId)), - SearchContext.empty(), - Pageable.unpaged(), - ).content + bookRepository + .findAll( + SearchCondition.LibraryId(SearchOperator.Is(libraryId)), + SearchContext.empty(), + Pageable.unpaged(), + ).content taskEmitter.refreshBookMetadata(books, priority = HIGH_PRIORITY) taskEmitter.refreshBookLocalArtwork(books, priority = HIGH_PRIORITY) taskEmitter.refreshSeriesLocalArtwork(seriesRepository.findAllIdsByLibraryId(libraryId), priority = HIGH_PRIORITY) diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/PageHashController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/PageHashController.kt index ad1ca57e..2a65c52e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/PageHashController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/PageHashController.kt @@ -48,8 +48,7 @@ class PageHashController( fun getKnownPageHashes( @RequestParam(name = "action", required = false) actions: List?, @Parameter(hidden = true) page: Pageable, - ): Page = - pageHashRepository.findAllKnown(actions, page).map { it.toDto() } + ): Page = pageHashRepository.findAllKnown(actions, page).map { it.toDto() } @GetMapping("/{pageHash}/thumbnail", produces = [MediaType.IMAGE_JPEG_VALUE]) @ApiResponse(content = [Content(schema = Schema(type = "string", format = "binary"))]) @@ -63,8 +62,7 @@ class PageHashController( @PageableAsQueryParam fun getUnknownPageHashes( @Parameter(hidden = true) page: Pageable, - ): Page = - pageHashRepository.findAllUnknown(page).map { it.toDto() } + ): Page = pageHashRepository.findAllUnknown(page).map { it.toDto() } @GetMapping("{pageHash}") @PageableAsQueryParam @@ -72,10 +70,11 @@ class PageHashController( @PathVariable pageHash: String, @Parameter(hidden = true) page: Pageable, ): Page = - pageHashRepository.findMatchesByHash( - pageHash, - page, - ).map { it.toDto() } + pageHashRepository + .findMatchesByHash( + pageHash, + page, + ).map { it.toDto() } @GetMapping("unknown/{pageHash}/thumbnail", produces = [MediaType.IMAGE_JPEG_VALUE]) @ApiResponse(content = [Content(schema = Schema(type = "string", format = "binary"))]) @@ -84,7 +83,8 @@ class PageHashController( @RequestParam("resize") resize: Int? = null, ): ResponseEntity = pageHashLifecycle.getPage(pageHash, resize)?.let { - ResponseEntity.ok() + ResponseEntity + .ok() .contentType(getMediaTypeOrDefault(it.mediaType)) .body(it.bytes) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @@ -114,7 +114,8 @@ class PageHashController( @PathVariable pageHash: String, ) { val toRemove = - pageHashRepository.findMatchesByHash(pageHash, Pageable.unpaged()) + pageHashRepository + .findMatchesByHash(pageHash, Pageable.unpaged()) .groupBy( { it.bookId }, { diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReadListController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReadListController.kt index 743bbe54..34f2f116 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReadListController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReadListController.kt @@ -126,7 +126,8 @@ class ReadListController( sort, ) - return readListRepository.findAll(principal.user.getAuthorizedLibraryIds(libraryIds), principal.user.getAuthorizedLibraryIds(null), searchTerm, pageRequest, principal.user.restrictions) + return readListRepository + .findAll(principal.user.getAuthorizedLibraryIds(libraryIds), principal.user.getAuthorizedLibraryIds(null), searchTerm, pageRequest, principal.user.restrictions) .map { it.toDto() } } @@ -135,7 +136,8 @@ class ReadListController( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable id: String, ): ReadListDto = - readListRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions) + readListRepository + .findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions) ?.toDto() ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @@ -146,7 +148,8 @@ class ReadListController( @PathVariable id: String, ): ResponseEntity { readListRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions)?.let { - return ResponseEntity.ok() + return ResponseEntity + .ok() .cacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePrivate()) .body(readListLifecycle.getThumbnailBytes(it)) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @@ -189,17 +192,18 @@ class ReadListController( if (!contentDetector.isImage(mediaType)) throw ResponseStatusException(HttpStatus.UNSUPPORTED_MEDIA_TYPE) - return readListLifecycle.addThumbnail( - ThumbnailReadList( - readListId = readList.id, - thumbnail = file.bytes, - type = ThumbnailReadList.Type.USER_UPLOADED, - selected = selected, - fileSize = file.bytes.size.toLong(), - mediaType = mediaType, - dimension = imageAnalyzer.getDimension(file.inputStream.buffered()) ?: Dimension(0, 0), - ), - ).toDto() + return readListLifecycle + .addThumbnail( + ThumbnailReadList( + readListId = readList.id, + thumbnail = file.bytes, + type = ThumbnailReadList.Type.USER_UPLOADED, + selected = selected, + fileSize = file.bytes.size.toLong(), + mediaType = mediaType, + dimension = imageAnalyzer.getDimension(file.inputStream.buffered()) ?: Dimension(0, 0), + ), + ).toDto() } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } @@ -241,14 +245,15 @@ class ReadListController( readList: ReadListCreationDto, ): ReadListDto = try { - readListLifecycle.addReadList( - ReadList( - name = readList.name, - summary = readList.summary, - ordered = readList.ordered, - bookIds = readList.bookIds.toIndexedMap(), - ), - ).toDto() + readListLifecycle + .addReadList( + ReadList( + name = readList.name, + summary = readList.summary, + ordered = readList.ordered, + bookIds = readList.bookIds.toIndexedMap(), + ), + ).toDto() } catch (e: DuplicateNameException) { throw ResponseStatusException(HttpStatus.BAD_REQUEST, e.message) } @@ -345,7 +350,8 @@ class ReadListController( }, ), ) - bookDtoRepository.findAll(bookSearch, SearchContext(principal.user), pageRequest) + bookDtoRepository + .findAll(bookSearch, SearchContext(principal.user), pageRequest) .map { it.restrictUrl(!principal.user.roleAdmin) } } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @@ -356,14 +362,14 @@ class ReadListController( @PathVariable bookId: String, ): BookDto = readListRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null))?.let { - bookDtoRepository.findPreviousInReadListOrNull( - it, - bookId, - principal.user.id, - principal.user.getAuthorizedLibraryIds(null), - principal.user.restrictions, - ) - ?.restrictUrl(!principal.user.roleAdmin) + bookDtoRepository + .findPreviousInReadListOrNull( + it, + bookId, + principal.user.id, + principal.user.getAuthorizedLibraryIds(null), + principal.user.restrictions, + )?.restrictUrl(!principal.user.roleAdmin) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @GetMapping("{id}/books/{bookId}/next") @@ -373,14 +379,14 @@ class ReadListController( @PathVariable bookId: String, ): BookDto = readListRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null))?.let { - bookDtoRepository.findNextInReadListOrNull( - it, - bookId, - principal.user.id, - principal.user.getAuthorizedLibraryIds(null), - principal.user.restrictions, - ) - ?.restrictUrl(!principal.user.roleAdmin) + bookDtoRepository + .findNextInReadListOrNull( + it, + bookId, + principal.user.id, + principal.user.getAuthorizedLibraryIds(null), + principal.user.restrictions, + )?.restrictUrl(!principal.user.roleAdmin) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @GetMapping("{id}/read-progress/tachiyomi") @@ -401,7 +407,8 @@ class ReadListController( @AuthenticationPrincipal principal: KomgaPrincipal, ) { readListRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null))?.let { readList -> - bookDtoRepository.findAll(BookSearch(SearchCondition.ReadListId(SearchOperator.Is(readList.id))), SearchContext(principal.user), UnpagedSorted(Sort.by(Sort.Order.asc("readList.number")))) + bookDtoRepository + .findAll(BookSearch(SearchCondition.ReadListId(SearchOperator.Is(readList.id))), SearchContext(principal.user), UnpagedSorted(Sort.by(Sort.Order.asc("readList.number")))) .filterIndexed { index, _ -> index < readProgress.lastBookRead } .forEach { book -> if (book.readProgress?.completed != true) @@ -446,16 +453,17 @@ class ReadListController( } } - return ResponseEntity.ok() + return ResponseEntity + .ok() .headers( HttpHeaders().apply { contentDisposition = - ContentDisposition.builder("attachment") + ContentDisposition + .builder("attachment") .filename(readList.name + ".zip", UTF_8) .build() }, - ) - .contentType(MediaType.parseMediaType(ZIP.type)) + ).contentType(MediaType.parseMediaType(ZIP.type)) .body(streamingResponse) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReferentialController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReferentialController.kt index f74a2bca..84c5c5d1 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReferentialController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReferentialController.kt @@ -72,14 +72,12 @@ class ReferentialController( fun getAuthorsNames( @AuthenticationPrincipal principal: KomgaPrincipal, @RequestParam(name = "search", defaultValue = "") search: String, - ): List = - referentialRepository.findAllAuthorsNamesByName(search, principal.user.getAuthorizedLibraryIds(null)) + ): List = referentialRepository.findAllAuthorsNamesByName(search, principal.user.getAuthorizedLibraryIds(null)) @GetMapping("v1/authors/roles") fun getAuthorsRoles( @AuthenticationPrincipal principal: KomgaPrincipal, - ): List = - referentialRepository.findAllAuthorsRoles(principal.user.getAuthorizedLibraryIds(null)) + ): List = referentialRepository.findAllAuthorsRoles(principal.user.getAuthorizedLibraryIds(null)) @GetMapping("v1/genres") fun getGenres( diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionController.kt index c0baa2ba..51327bd6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionController.kt @@ -103,7 +103,8 @@ class SeriesCollectionController( sort, ) - return collectionRepository.findAll(principal.user.getAuthorizedLibraryIds(libraryIds), principal.user.getAuthorizedLibraryIds(null), searchTerm, pageRequest, principal.user.restrictions) + return collectionRepository + .findAll(principal.user.getAuthorizedLibraryIds(libraryIds), principal.user.getAuthorizedLibraryIds(null), searchTerm, pageRequest, principal.user.restrictions) .map { it.toDto() } } @@ -112,7 +113,8 @@ class SeriesCollectionController( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable id: String, ): CollectionDto = - collectionRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions) + collectionRepository + .findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions) ?.toDto() ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @@ -123,7 +125,8 @@ class SeriesCollectionController( @PathVariable id: String, ): ResponseEntity { collectionRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions)?.let { - return ResponseEntity.ok() + return ResponseEntity + .ok() .cacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePrivate()) .body(collectionLifecycle.getThumbnailBytes(it, principal.user.id)) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @@ -166,17 +169,18 @@ class SeriesCollectionController( if (!contentDetector.isImage(mediaType)) throw ResponseStatusException(HttpStatus.UNSUPPORTED_MEDIA_TYPE) - return collectionLifecycle.addThumbnail( - ThumbnailSeriesCollection( - collectionId = collection.id, - thumbnail = file.bytes, - type = ThumbnailSeriesCollection.Type.USER_UPLOADED, - selected = selected, - fileSize = file.bytes.size.toLong(), - mediaType = mediaType, - dimension = imageAnalyzer.getDimension(file.inputStream.buffered()) ?: Dimension(0, 0), - ), - ).toDto() + return collectionLifecycle + .addThumbnail( + ThumbnailSeriesCollection( + collectionId = collection.id, + thumbnail = file.bytes, + type = ThumbnailSeriesCollection.Type.USER_UPLOADED, + selected = selected, + fileSize = file.bytes.size.toLong(), + mediaType = mediaType, + dimension = imageAnalyzer.getDimension(file.inputStream.buffered()) ?: Dimension(0, 0), + ), + ).toDto() } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } @@ -218,13 +222,14 @@ class SeriesCollectionController( collection: CollectionCreationDto, ): CollectionDto = try { - collectionLifecycle.addCollection( - SeriesCollection( - name = collection.name, - ordered = collection.ordered, - seriesIds = collection.seriesIds, - ), - ).toDto() + collectionLifecycle + .addCollection( + SeriesCollection( + name = collection.name, + ordered = collection.ordered, + seriesIds = collection.seriesIds, + ), + ).toDto() } catch (e: DuplicateNameException) { throw ResponseStatusException(HttpStatus.BAD_REQUEST, e.message) } @@ -332,7 +337,8 @@ class SeriesCollectionController( ), ) - seriesDtoRepository.findAll(search, SearchContext(principal.user), pageRequest) + seriesDtoRepository + .findAll(search, SearchContext(principal.user), pageRequest) .map { it.restrictUrl(!principal.user.roleAdmin) } } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesController.kt index 3dcc457a..976a431c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesController.kt @@ -218,7 +218,8 @@ class SeriesController( }, ) - return seriesDtoRepository.findAll(seriesSearch, SearchContext(principal.user), pageRequest) + return seriesDtoRepository + .findAll(seriesSearch, SearchContext(principal.user), pageRequest) .map { it.restrictUrl(!principal.user.roleAdmin) } } @@ -247,7 +248,8 @@ class SeriesController( sort, ) - return seriesDtoRepository.findAll(search, SearchContext(principal.user), pageRequest) + return seriesDtoRepository + .findAll(search, SearchContext(principal.user), pageRequest) .map { it.restrictUrl(!principal.user.roleAdmin) } } @@ -361,19 +363,20 @@ class SeriesController( sort, ) - return seriesDtoRepository.findAll( - SeriesSearch( - SearchCondition.AllOfSeries( - buildList { - if (!libraryIds.isNullOrEmpty()) add(SearchCondition.AnyOfSeries(libraryIds.map { SearchCondition.LibraryId(SearchOperator.Is(it)) })) - deleted?.let { add(SearchCondition.Deleted(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } - oneshot?.let { add(SearchCondition.OneShot(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } - }, + return seriesDtoRepository + .findAll( + SeriesSearch( + SearchCondition.AllOfSeries( + buildList { + if (!libraryIds.isNullOrEmpty()) add(SearchCondition.AnyOfSeries(libraryIds.map { SearchCondition.LibraryId(SearchOperator.Is(it)) })) + deleted?.let { add(SearchCondition.Deleted(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } + oneshot?.let { add(SearchCondition.OneShot(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } + }, + ), ), - ), - SearchContext(principal.user), - pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + SearchContext(principal.user), + pageRequest, + ).map { it.restrictUrl(!principal.user.roleAdmin) } } @Operation(description = "Return newly added series.") @@ -399,19 +402,20 @@ class SeriesController( sort, ) - return seriesDtoRepository.findAll( - SeriesSearch( - SearchCondition.AllOfSeries( - buildList { - if (!libraryIds.isNullOrEmpty()) add(SearchCondition.AnyOfSeries(libraryIds.map { SearchCondition.LibraryId(SearchOperator.Is(it)) })) - deleted?.let { add(SearchCondition.Deleted(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } - oneshot?.let { add(SearchCondition.OneShot(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } - }, + return seriesDtoRepository + .findAll( + SeriesSearch( + SearchCondition.AllOfSeries( + buildList { + if (!libraryIds.isNullOrEmpty()) add(SearchCondition.AnyOfSeries(libraryIds.map { SearchCondition.LibraryId(SearchOperator.Is(it)) })) + deleted?.let { add(SearchCondition.Deleted(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } + oneshot?.let { add(SearchCondition.OneShot(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } + }, + ), ), - ), - SearchContext(principal.user), - pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + SearchContext(principal.user), + pageRequest, + ).map { it.restrictUrl(!principal.user.roleAdmin) } } @Operation(description = "Return recently updated series, but not newly added ones.") @@ -437,19 +441,20 @@ class SeriesController( sort, ) - return seriesDtoRepository.findAllRecentlyUpdated( - SeriesSearch( - SearchCondition.AllOfSeries( - buildList { - if (!libraryIds.isNullOrEmpty()) add(SearchCondition.AnyOfSeries(libraryIds.map { SearchCondition.LibraryId(SearchOperator.Is(it)) })) - deleted?.let { add(SearchCondition.Deleted(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } - oneshot?.let { add(SearchCondition.OneShot(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } - }, + return seriesDtoRepository + .findAllRecentlyUpdated( + SeriesSearch( + SearchCondition.AllOfSeries( + buildList { + if (!libraryIds.isNullOrEmpty()) add(SearchCondition.AnyOfSeries(libraryIds.map { SearchCondition.LibraryId(SearchOperator.Is(it)) })) + deleted?.let { add(SearchCondition.Deleted(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } + oneshot?.let { add(SearchCondition.OneShot(if (it) SearchOperator.IsTrue else SearchOperator.IsFalse)) } + }, + ), ), - ), - SearchContext(principal.user), - pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + SearchContext(principal.user), + pageRequest, + ).map { it.restrictUrl(!principal.user.roleAdmin) } } @GetMapping("v1/series/{seriesId}") @@ -494,7 +499,8 @@ class SeriesController( ): Collection { principal.user.checkContentRestriction(seriesId) - return thumbnailsSeriesRepository.findAllBySeriesId(seriesId) + return thumbnailsSeriesRepository + .findAllBySeriesId(seriesId) .map { it.toDto() } } @@ -512,17 +518,18 @@ class SeriesController( if (!contentDetector.isImage(mediaType)) throw ResponseStatusException(HttpStatus.UNSUPPORTED_MEDIA_TYPE) - return seriesLifecycle.addThumbnailForSeries( - ThumbnailSeries( - seriesId = series.id, - thumbnail = file.bytes, - type = ThumbnailSeries.Type.USER_UPLOADED, - fileSize = file.bytes.size.toLong(), - mediaType = mediaType, - dimension = imageAnalyzer.getDimension(file.inputStream.buffered()) ?: Dimension(0, 0), - ), - if (selected) MarkSelectedPreference.YES else MarkSelectedPreference.NO, - ).toDto() + return seriesLifecycle + .addThumbnailForSeries( + ThumbnailSeries( + seriesId = series.id, + thumbnail = file.bytes, + type = ThumbnailSeries.Type.USER_UPLOADED, + fileSize = file.bytes.size.toLong(), + mediaType = mediaType, + dimension = imageAnalyzer.getDimension(file.inputStream.buffered()) ?: Dimension(0, 0), + ), + if (selected) MarkSelectedPreference.YES else MarkSelectedPreference.NO, + ).toDto() } @PutMapping("v1/series/{seriesId}/thumbnails/{thumbnailId}/selected") @@ -601,11 +608,12 @@ class SeriesController( }, ), ) - return bookDtoRepository.findAll( - search, - SearchContext(principal.user), - pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + return bookDtoRepository + .findAll( + search, + SearchContext(principal.user), + pageRequest, + ).map { it.restrictUrl(!principal.user.roleAdmin) } } @GetMapping("v1/series/{seriesId}/collections") @@ -615,7 +623,8 @@ class SeriesController( ): List { principal.user.checkContentRestriction(seriesId) - return collectionRepository.findAllContainingSeriesId(seriesId, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions) + return collectionRepository + .findAllContainingSeriesId(seriesId, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions) .map { it.toDto() } } @@ -650,70 +659,69 @@ class SeriesController( @RequestBody newMetadata: SeriesMetadataUpdateDto, @AuthenticationPrincipal principal: KomgaPrincipal, - ) = - seriesMetadataRepository.findByIdOrNull(seriesId)?.let { existing -> - val updated = - with(newMetadata) { - existing.copy( - status = status ?: existing.status, - statusLock = statusLock ?: existing.statusLock, - title = title ?: existing.title, - titleLock = titleLock ?: existing.titleLock, - titleSort = titleSort ?: existing.titleSort, - titleSortLock = titleSortLock ?: existing.titleSortLock, - summary = summary ?: existing.summary, - summaryLock = summaryLock ?: existing.summaryLock, - language = language ?: existing.language, - languageLock = languageLock ?: existing.languageLock, - readingDirection = if (isSet("readingDirection")) readingDirection else existing.readingDirection, - readingDirectionLock = readingDirectionLock ?: existing.readingDirectionLock, - publisher = publisher ?: existing.publisher, - publisherLock = publisherLock ?: existing.publisherLock, - ageRating = if (isSet("ageRating")) ageRating else existing.ageRating, - ageRatingLock = ageRatingLock ?: existing.ageRatingLock, - genres = - if (isSet("genres")) { - if (genres != null) genres!! else emptySet() - } else { - existing.genres - }, - genresLock = genresLock ?: existing.genresLock, - tags = - if (isSet("tags")) { - if (tags != null) tags!! else emptySet() - } else { - existing.tags - }, - tagsLock = tagsLock ?: existing.tagsLock, - totalBookCount = if (isSet("totalBookCount")) totalBookCount else existing.totalBookCount, - totalBookCountLock = totalBookCountLock ?: existing.totalBookCountLock, - sharingLabels = - if (isSet("sharingLabels")) { - if (sharingLabels != null) sharingLabels!! else emptySet() - } else { - existing.sharingLabels - }, - sharingLabelsLock = sharingLabelsLock ?: existing.sharingLabelsLock, - links = - if (isSet("links")) { - if (links != null) links!!.map { WebLink(it.label!!, URI(it.url!!)) } else emptyList() - } else { - existing.links - }, - linksLock = linksLock ?: existing.linksLock, - alternateTitles = - if (isSet("alternateTitles")) { - if (alternateTitles != null) alternateTitles!!.map { AlternateTitle(it.label!!, it.title!!) } else emptyList() - } else { - existing.alternateTitles - }, - alternateTitlesLock = alternateTitlesLock ?: existing.alternateTitlesLock, - ) - } - seriesMetadataRepository.update(updated) + ) = seriesMetadataRepository.findByIdOrNull(seriesId)?.let { existing -> + val updated = + with(newMetadata) { + existing.copy( + status = status ?: existing.status, + statusLock = statusLock ?: existing.statusLock, + title = title ?: existing.title, + titleLock = titleLock ?: existing.titleLock, + titleSort = titleSort ?: existing.titleSort, + titleSortLock = titleSortLock ?: existing.titleSortLock, + summary = summary ?: existing.summary, + summaryLock = summaryLock ?: existing.summaryLock, + language = language ?: existing.language, + languageLock = languageLock ?: existing.languageLock, + readingDirection = if (isSet("readingDirection")) readingDirection else existing.readingDirection, + readingDirectionLock = readingDirectionLock ?: existing.readingDirectionLock, + publisher = publisher ?: existing.publisher, + publisherLock = publisherLock ?: existing.publisherLock, + ageRating = if (isSet("ageRating")) ageRating else existing.ageRating, + ageRatingLock = ageRatingLock ?: existing.ageRatingLock, + genres = + if (isSet("genres")) { + if (genres != null) genres!! else emptySet() + } else { + existing.genres + }, + genresLock = genresLock ?: existing.genresLock, + tags = + if (isSet("tags")) { + if (tags != null) tags!! else emptySet() + } else { + existing.tags + }, + tagsLock = tagsLock ?: existing.tagsLock, + totalBookCount = if (isSet("totalBookCount")) totalBookCount else existing.totalBookCount, + totalBookCountLock = totalBookCountLock ?: existing.totalBookCountLock, + sharingLabels = + if (isSet("sharingLabels")) { + if (sharingLabels != null) sharingLabels!! else emptySet() + } else { + existing.sharingLabels + }, + sharingLabelsLock = sharingLabelsLock ?: existing.sharingLabelsLock, + links = + if (isSet("links")) { + if (links != null) links!!.map { WebLink(it.label!!, URI(it.url!!)) } else emptyList() + } else { + existing.links + }, + linksLock = linksLock ?: existing.linksLock, + alternateTitles = + if (isSet("alternateTitles")) { + if (alternateTitles != null) alternateTitles!!.map { AlternateTitle(it.label!!, it.title!!) } else emptyList() + } else { + existing.alternateTitles + }, + alternateTitlesLock = alternateTitlesLock ?: existing.alternateTitlesLock, + ) + } + seriesMetadataRepository.update(updated) - seriesRepository.findByIdOrNull(seriesId)?.let { eventPublisher.publishEvent(DomainEvent.SeriesUpdated(it)) } - } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + seriesRepository.findByIdOrNull(seriesId)?.let { eventPublisher.publishEvent(DomainEvent.SeriesUpdated(it)) } + } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @Operation(description = "Mark all book for series as read") @PostMapping("v1/series/{seriesId}/read-progress") @@ -758,11 +766,13 @@ class SeriesController( ) { principal.user.checkContentRestriction(seriesId) - bookDtoRepository.findAll( - BookSearch(SearchCondition.SeriesId(SearchOperator.Is(seriesId))), - SearchContext(principal.user), - UnpagedSorted(Sort.by(Sort.Order.asc("metadata.numberSort"))), - ).toList().filter { book -> book.metadata.numberSort <= readProgress.lastBookNumberSortRead } + bookDtoRepository + .findAll( + BookSearch(SearchCondition.SeriesId(SearchOperator.Is(seriesId))), + SearchContext(principal.user), + UnpagedSorted(Sort.by(Sort.Order.asc("metadata.numberSort"))), + ).toList() + .filter { book -> book.metadata.numberSort <= readProgress.lastBookNumberSortRead } .forEach { book -> if (book.readProgress?.completed != true) bookLifecycle.markReadProgressCompleted(book.id, principal.user) @@ -802,16 +812,17 @@ class SeriesController( } } - return ResponseEntity.ok() + return ResponseEntity + .ok() .headers( HttpHeaders().apply { contentDisposition = - ContentDisposition.builder("attachment") + ContentDisposition + .builder("attachment") .filename(seriesMetadataRepository.findById(seriesId).title + ".zip", UTF_8) .build() }, - ) - .contentType(MediaType.parseMediaType(ZIP.type)) + ).contentType(MediaType.parseMediaType(ZIP.type)) .body(streamingResponse) } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TaskController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TaskController.kt index 25747515..4415cfe9 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TaskController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TaskController.kt @@ -18,6 +18,5 @@ class TaskController( @DeleteMapping("api/v1/tasks") @ResponseStatus(HttpStatus.OK) @PreAuthorize("hasRole('$ROLE_ADMIN')") - fun emptyTaskQueue(): Int = - tasksRepository.deleteAllWithoutOwner() + fun emptyTaskQueue(): Int = tasksRepository.deleteAllWithoutOwner() } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TransientBooksController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TransientBooksController.kt index 402efa01..2f2cfc93 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TransientBooksController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TransientBooksController.kt @@ -42,7 +42,8 @@ class TransientBooksController( @RequestBody request: ScanRequestDto, ): List = try { - transientBookLifecycle.scanAndPersist(request.path) + transientBookLifecycle + .scanAndPersist(request.path) .sortedBy { it.book.path } .map { it.toDto() } } catch (e: CodedException) { @@ -69,7 +70,8 @@ class TransientBooksController( try { val pageContent = transientBookLifecycle.getBookPage(it, pageNumber) - ResponseEntity.ok() + ResponseEntity + .ok() .contentType(getMediaTypeOrDefault(pageContent.mediaType)) .body(pageContent.bytes) } catch (ex: IndexOutOfBoundsException) { diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/UserController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/UserController.kt index 87172fee..ef38f30d 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/UserController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/UserController.kt @@ -64,8 +64,7 @@ class UserController( @GetMapping("me") fun getMe( @AuthenticationPrincipal principal: KomgaPrincipal, - ): UserDto = - principal.toDto() + ): UserDto = principal.toDto() @PatchMapping("me/password") @ResponseStatus(HttpStatus.NO_CONTENT) @@ -82,8 +81,7 @@ class UserController( @GetMapping @PreAuthorize("hasRole('$ROLE_ADMIN')") - fun getAll(): List = - userRepository.findAll().map { it.toDto() } + fun getAll(): List = userRepository.findAll().map { it.toDto() } @PostMapping @ResponseStatus(HttpStatus.CREATED) diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/BookDto.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/BookDto.kt index 4bec50e1..1b451e70 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/BookDto.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/BookDto.kt @@ -31,8 +31,7 @@ data class BookDto( val oneshot: Boolean, ) -fun BookDto.restrictUrl(restrict: Boolean) = - if (restrict) copy(url = FilenameUtils.getName(url)) else this +fun BookDto.restrictUrl(restrict: Boolean) = if (restrict) copy(url = FilenameUtils.getName(url)) else this data class MediaDto( val status: String, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/ReadProgressUpdateDto.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/ReadProgressUpdateDto.kt index 84f428be..253387a5 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/ReadProgressUpdateDto.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/ReadProgressUpdateDto.kt @@ -26,7 +26,8 @@ class ReadProgressUpdateDtoValidator : ConstraintValidator - MultiGauge.builder("komga.$entity") + MultiGauge + .builder("komga.$entity") .description("The number of $entity") .baseUnit("count") .register(meterRegistry) @@ -70,7 +73,8 @@ class MetricsPublisherController( val noTagGauges = entitiesNoTags.associateWith { entity -> AtomicLong(0).also { value -> - Gauge.builder("komga.$entity", value) { value.get().toDouble() } + Gauge + .builder("komga.$entity", value) { value.get().toDouble() } .description("The number of $entity") .baseUnit("count") .register(meterRegistry) @@ -78,7 +82,8 @@ class MetricsPublisherController( } val bookFileSizeGauge = - MultiGauge.builder("komga.$BOOKS_FILESIZE") + MultiGauge + .builder("komga.$BOOKS_FILESIZE") .description("The cumulated filesize of books") .baseUnit("bytes") .register(meterRegistry) diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/scheduler/PeriodicScannerController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/scheduler/PeriodicScannerController.kt index 4abc0ee5..14b46b05 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/scheduler/PeriodicScannerController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/scheduler/PeriodicScannerController.kt @@ -20,7 +20,8 @@ class PeriodicScannerController( ) { @EventListener(classes = [ApplicationReadyEvent::class]) fun scanOnStartup() { - libraryRepository.findAll() + libraryRepository + .findAll() .filter { it.scanOnStartup } .forEach { logger.info { "Scan on startup for library: ${it.name}" } @@ -30,7 +31,8 @@ class PeriodicScannerController( @EventListener(classes = [ApplicationReadyEvent::class]) fun scheduleScans() { - libraryRepository.findAll() + libraryRepository + .findAll() .forEach { libraryScanScheduler.scheduleScan(it) } } } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/sse/SseController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/sse/SseController.kt index f1811c66..c00e42de 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/sse/SseController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/sse/SseController.kt @@ -122,7 +122,8 @@ class SseController( .forEach { (emitter, _) -> try { emitter.send( - SseEmitter.event() + SseEmitter + .event() .name(name) .data(data, MediaType.APPLICATION_JSON), ) diff --git a/komga/src/main/kotlin/org/gotson/komga/language/LanguageUtils.kt b/komga/src/main/kotlin/org/gotson/komga/language/LanguageUtils.kt index e19de966..4ab22e9e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/language/LanguageUtils.kt +++ b/komga/src/main/kotlin/org/gotson/komga/language/LanguageUtils.kt @@ -12,16 +12,13 @@ import java.util.Date import java.util.Enumeration import java.util.SortedMap -fun List.toIndexedMap(): SortedMap = - mapIndexed { i, e -> i to e }.toMap().toSortedMap() +fun List.toIndexedMap(): SortedMap = mapIndexed { i, e -> i to e }.toMap().toSortedMap() fun List.toEnumeration(): Enumeration { return object : Enumeration { var count = 0 - override fun hasMoreElements(): Boolean { - return this.count < size - } + override fun hasMoreElements(): Boolean = this.count < size override fun nextElement(): T { if (this.count < size) { @@ -32,25 +29,22 @@ fun List.toEnumeration(): Enumeration { } } -fun Iterable.mostFrequent(transform: (T) -> R?): R? { - return this +fun Iterable.mostFrequent(transform: (T) -> R?): R? = + this .mapNotNull(transform) .groupingBy { it } .eachCount() - .maxByOrNull { it.value }?.key -} + .maxByOrNull { it.value } + ?.key -fun Iterable.lowerNotBlank() = - this.map { it.lowercase().trim() }.filter { it.isNotBlank() } +fun Iterable.lowerNotBlank() = this.map { it.lowercase().trim() }.filter { it.isNotBlank() } -fun Iterable.toSetOrNull() = - this.toSet().ifEmpty { null } +fun Iterable.toSetOrNull() = this.toSet().ifEmpty { null } fun LocalDateTime.notEquals( other: LocalDateTime, precision: TemporalUnit = ChronoUnit.MILLIS, -) = - this.truncatedTo(precision) != other.truncatedTo(precision) +) = this.truncatedTo(precision) != other.truncatedTo(precision) fun String.stripAccents(): String = StringUtils.stripAccents(this) @@ -60,29 +54,24 @@ fun LocalDate.toDate(): Date = Date.from(this.atStartOfDay(ZoneId.of("Z")).toIns * Converts a LocalDateTime (current timezone) to a LocalDateTime (UTC) * Warning: this is not idempotent */ -fun LocalDateTime.toUTC(): LocalDateTime = - atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime() +fun LocalDateTime.toUTC(): LocalDateTime = atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime() /** * Converts a LocalDateTime (current timezone) to a ZonedDateTime */ -fun LocalDateTime.toUTCZoned(): ZonedDateTime = - atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC) +fun LocalDateTime.toUTCZoned(): ZonedDateTime = atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC) /** * Converts a LocalDateTime (UTC) to a ZonedDateTime */ -fun LocalDateTime.toZonedDateTime(): ZonedDateTime = - this.atZone(ZoneId.of("Z")).withZoneSameInstant(ZoneId.systemDefault()) +fun LocalDateTime.toZonedDateTime(): ZonedDateTime = this.atZone(ZoneId.of("Z")).withZoneSameInstant(ZoneId.systemDefault()) /** * Converts a LocalDateTime (UTC) to a LocalDateTime (current timezone) */ -fun LocalDateTime.toCurrentTimeZone(): LocalDateTime = - this.atZone(ZoneId.of("Z")).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime() +fun LocalDateTime.toCurrentTimeZone(): LocalDateTime = this.atZone(ZoneId.of("Z")).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime() fun Iterable.contains( s: String, ignoreCase: Boolean = false, -): Boolean = - any { it.equals(s, ignoreCase) } +): Boolean = any { it.equals(s, ignoreCase) } diff --git a/komga/src/test/kotlin/org/gotson/komga/Utils.kt b/komga/src/test/kotlin/org/gotson/komga/Utils.kt index 5f11a53a..ccdc1440 100644 --- a/komga/src/test/kotlin/org/gotson/komga/Utils.kt +++ b/komga/src/test/kotlin/org/gotson/komga/Utils.kt @@ -4,5 +4,4 @@ import org.gotson.komga.domain.model.Book import org.gotson.komga.domain.model.ScanResult import org.gotson.komga.domain.model.Series -fun Map>.toScanResult() = - ScanResult(this, emptyList()) +fun Map>.toScanResult() = ScanResult(this, emptyList()) diff --git a/komga/src/test/kotlin/org/gotson/komga/architecture/DomainDrivenDesignRulesTest.kt b/komga/src/test/kotlin/org/gotson/komga/architecture/DomainDrivenDesignRulesTest.kt index e5a62dd1..221d5a4d 100644 --- a/komga/src/test/kotlin/org/gotson/komga/architecture/DomainDrivenDesignRulesTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/architecture/DomainDrivenDesignRulesTest.kt @@ -13,8 +13,11 @@ class DomainDrivenDesignRulesTest { @ArchTest val domainModelShouldNotAccessOtherPackages: ArchRule = noClasses() - .that().resideInAPackage("..domain..model..") - .should().dependOnClassesThat().resideInAnyPackage( + .that() + .resideInAPackage("..domain..model..") + .should() + .dependOnClassesThat() + .resideInAnyPackage( "..infrastructure..", "..interfaces..", "..domain.persistence..", @@ -24,6 +27,8 @@ class DomainDrivenDesignRulesTest { @ArchTest var classesNamedControllerShouldBeInAnInterfacesPackage: ArchRule = classes() - .that().haveSimpleNameContaining("Controller") - .should().resideInAPackage("..interfaces..") + .that() + .haveSimpleNameContaining("Controller") + .should() + .resideInAPackage("..interfaces..") } diff --git a/komga/src/test/kotlin/org/gotson/komga/architecture/NamingConventionTest.kt b/komga/src/test/kotlin/org/gotson/komga/architecture/NamingConventionTest.kt index 34c48efc..ab2dc9c3 100644 --- a/komga/src/test/kotlin/org/gotson/komga/architecture/NamingConventionTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/architecture/NamingConventionTest.kt @@ -15,17 +15,25 @@ class NamingConventionTest { @ArchTest val servicesShouldNotHaveNamesContainingServiceOrManager: ArchRule = noClasses() - .that().resideInAnyPackage("..domain..service..", "..application..service..") - .should().haveSimpleNameContaining("service") - .orShould().haveSimpleNameContaining("Service") - .orShould().haveSimpleNameContaining("manager") - .orShould().haveSimpleNameContaining("Manager") + .that() + .resideInAnyPackage("..domain..service..", "..application..service..") + .should() + .haveSimpleNameContaining("service") + .orShould() + .haveSimpleNameContaining("Service") + .orShould() + .haveSimpleNameContaining("manager") + .orShould() + .haveSimpleNameContaining("Manager") .because("it doesn't bear any intent") @ArchTest val controllersShouldBeSuffixed: ArchRule = classes() - .that().areAnnotatedWith(RestController::class.java) - .or().areAnnotatedWith(Controller::class.java) - .should().haveSimpleNameEndingWith("Controller") + .that() + .areAnnotatedWith(RestController::class.java) + .or() + .areAnnotatedWith(Controller::class.java) + .should() + .haveSimpleNameEndingWith("Controller") } diff --git a/komga/src/test/kotlin/org/gotson/komga/architecture/SlicesIsolationRulesTest.kt b/komga/src/test/kotlin/org/gotson/komga/architecture/SlicesIsolationRulesTest.kt index a272f774..8d405ab8 100644 --- a/komga/src/test/kotlin/org/gotson/komga/architecture/SlicesIsolationRulesTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/architecture/SlicesIsolationRulesTest.kt @@ -12,6 +12,9 @@ class SlicesIsolationRulesTest { @ArchTest val interfacesShouldOnlyUseTheirOwnSlice: ArchRule = slices() - .matching("..interfaces.(*)..").namingSlices("Interface $1") - .`as`("Interfaces").should().notDependOnEachOther() + .matching("..interfaces.(*)..") + .namingSlices("Interface $1") + .`as`("Interfaces") + .should() + .notDependOnEachOther() } diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/model/Utils.kt b/komga/src/test/kotlin/org/gotson/komga/domain/model/Utils.kt index 7e2088a2..a3bd9839 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/model/Utils.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/model/Utils.kt @@ -42,13 +42,11 @@ fun makeLibrary( path: String = "file:/${name.replace(" ", "_")}", id: String = TsidCreator.getTsid256().toString(), url: URL? = null, -): Library { - return Library( +): Library = + Library( name = name, root = url ?: URL(path), id = id, ) -} -fun makeBookPage(name: String) = - BookPage(name, "image/png") +fun makeBookPage(name: String) = BookPage(name, "image/png") diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookAnalyzerTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookAnalyzerTest.kt index 7b635b85..366dfaa1 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookAnalyzerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookAnalyzerTest.kt @@ -177,8 +177,12 @@ class BookAnalyzerTest( assertThat(hashedMedia.pages.takeLast(komgaProperties.pageHashing).map { it.fileHash }) .hasSize(komgaProperties.pageHashing) .containsOnly("hashed") - assertThat(hashedMedia.pages.drop(komgaProperties.pageHashing).dropLast(komgaProperties.pageHashing).map { it.fileHash }) - .hasSize(30 - (komgaProperties.pageHashing * 2)) + assertThat( + hashedMedia.pages + .drop(komgaProperties.pageHashing) + .dropLast(komgaProperties.pageHashing) + .map { it.fileHash }, + ).hasSize(30 - (komgaProperties.pageHashing * 2)) .containsOnly("") } diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/service/LibraryLifecycleTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/service/LibraryLifecycleTest.kt index 8c5b3d0c..df4c96d6 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/service/LibraryLifecycleTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/service/LibraryLifecycleTest.kt @@ -48,9 +48,11 @@ class LibraryLifecycleTest( libraryLifecycle.addLibrary( Library( "test", - Files.createTempFile(null, null) + Files + .createTempFile(null, null) .also { it.toFile().deleteOnExit() } - .toUri().toURL(), + .toUri() + .toURL(), ), ) } @@ -154,8 +156,11 @@ class LibraryLifecycleTest( existing.copy( name = "test", root = - Files.createTempFile(null, null) - .also { it.toFile().deleteOnExit() }.toUri().toURL(), + Files + .createTempFile(null, null) + .also { it.toFile().deleteOnExit() } + .toUri() + .toURL(), ) val thrown = catchThrowable { diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDaoTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDaoTest.kt index fa778e9a..1a288f8a 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDaoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDaoTest.kt @@ -451,11 +451,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "batman"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "batman"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(3) @@ -479,11 +480,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "book"), - SearchContext(user), - UnpagedSorted(Sort.by("name")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "book"), + SearchContext(user), + UnpagedSorted(Sort.by("name")), + ).content val pages = (0..2).map { bookDtoDao.findAll( @@ -544,11 +546,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "eric"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "eric"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -578,11 +581,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "9782413016878"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "9782413016878"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -609,11 +613,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "tag:tag1"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "tag:tag1"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -640,23 +645,26 @@ class BookDtoDaoTest( // when val foundGeneric = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "author:bob"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "author:bob"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content val foundByRole = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "writer:bob"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "writer:bob"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content val notFound = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "penciller:bob"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "penciller:bob"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(foundGeneric).hasSize(1) @@ -681,11 +689,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "release_date:1999"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "release_date:1999"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -711,11 +720,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "release_date:[1990 TO 2010]"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "release_date:[1990 TO 2010]"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(2) @@ -737,11 +747,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "status:error"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "status:error"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -767,11 +778,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "deleted:true"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "deleted:true"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -794,11 +806,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "s.w.o.r.d"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "s.w.o.r.d"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -823,11 +836,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "batman robin"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "batman robin"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(2) @@ -851,11 +865,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "x-men"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "x-men"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(2) @@ -867,11 +882,12 @@ class BookDtoDaoTest( assertThatCode { // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "publisher:batman"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "publisher:batman"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(0) @@ -893,11 +909,12 @@ class BookDtoDaoTest( // when val found = - bookDtoDao.findAll( - BookSearch(fullTextSearch = "不道德"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + bookDtoDao + .findAll( + BookSearch(fullTextSearch = "不道德"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDaoTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDaoTest.kt index f41fd314..ceff3c08 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDaoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDaoTest.kt @@ -98,7 +98,10 @@ class ReadListDaoTest( readList.copy( name = "UpdatedReadList", summary = "summary", - bookIds = readList.bookIds.values.take(5).toIndexedMap(), + bookIds = + readList.bookIds.values + .take(5) + .toIndexedMap(), ) val now = LocalDateTime.now() diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDaoTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDaoTest.kt index 07ec41eb..215af7a5 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDaoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDaoTest.kt @@ -96,7 +96,8 @@ class SeriesDtoDaoTest( } private fun setupSeries() { - (1..4).map { makeSeries("$it", library.id) } + (1..4) + .map { makeSeries("$it", library.id) } .forEach { series -> val created = seriesLifecycle.createSeries(series) seriesLifecycle.addBooks( @@ -135,11 +136,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.READ))), - SearchContext(user), - PageRequest.of(0, 20), - ).sortedBy { it.name } + seriesDtoDao + .findAll( + SeriesSearch(SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.READ))), + SearchContext(user), + PageRequest.of(0, 20), + ).sortedBy { it.name } // then assertThat(found).hasSize(1) @@ -155,11 +157,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.UNREAD))), - SearchContext(user), - PageRequest.of(0, 20), - ).sortedBy { it.name } + seriesDtoDao + .findAll( + SeriesSearch(SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.UNREAD))), + SearchContext(user), + PageRequest.of(0, 20), + ).sortedBy { it.name } // then assertThat(found).hasSize(1) @@ -175,11 +178,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS))), - SearchContext(user), - PageRequest.of(0, 20), - ).sortedBy { it.name } + seriesDtoDao + .findAll( + SeriesSearch(SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS))), + SearchContext(user), + PageRequest.of(0, 20), + ).sortedBy { it.name } // then assertThat(found).hasSize(2) @@ -198,16 +202,17 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch( - SearchCondition.AnyOfSeries( - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.READ)), - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.UNREAD)), + seriesDtoDao + .findAll( + SeriesSearch( + SearchCondition.AnyOfSeries( + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.READ)), + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.UNREAD)), + ), ), - ), - SearchContext(user), - PageRequest.of(0, 20), - ).sortedBy { it.name } + SearchContext(user), + PageRequest.of(0, 20), + ).sortedBy { it.name } // then assertThat(found).hasSize(2) @@ -221,16 +226,17 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch( - SearchCondition.AnyOfSeries( - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.READ)), - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS)), + seriesDtoDao + .findAll( + SeriesSearch( + SearchCondition.AnyOfSeries( + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.READ)), + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS)), + ), ), - ), - SearchContext(user), - PageRequest.of(0, 20), - ).sortedBy { it.name } + SearchContext(user), + PageRequest.of(0, 20), + ).sortedBy { it.name } // then assertThat(found).hasSize(3) @@ -244,16 +250,17 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch( - SearchCondition.AnyOfSeries( - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.UNREAD)), - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS)), + seriesDtoDao + .findAll( + SeriesSearch( + SearchCondition.AnyOfSeries( + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.UNREAD)), + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS)), + ), ), - ), - SearchContext(user), - PageRequest.of(0, 20), - ).sortedBy { it.name } + SearchContext(user), + PageRequest.of(0, 20), + ).sortedBy { it.name } // then assertThat(found).hasSize(3) @@ -267,17 +274,18 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch( - SearchCondition.AnyOfSeries( - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.READ)), - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS)), - SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.UNREAD)), + seriesDtoDao + .findAll( + SeriesSearch( + SearchCondition.AnyOfSeries( + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.READ)), + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.IN_PROGRESS)), + SearchCondition.ReadStatus(SearchOperator.Is(ReadStatus.UNREAD)), + ), ), - ), - SearchContext(user), - PageRequest.of(0, 20), - ).sortedBy { it.name } + SearchContext(user), + PageRequest.of(0, 20), + ).sortedBy { it.name } // then assertThat(found).hasSize(4) @@ -291,10 +299,11 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SearchContext(user), - PageRequest.of(0, 20), - ).sortedBy { it.name } + seriesDtoDao + .findAll( + SearchContext(user), + PageRequest.of(0, 20), + ).sortedBy { it.name } // then assertThat(found).hasSize(4) @@ -316,11 +325,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "batman"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "batman"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(3) @@ -342,11 +352,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "publisher:vertigo"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "publisher:vertigo"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -368,11 +379,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "status:hiatus"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "status:hiatus"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -394,11 +406,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "reading_direction:left_to_right"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "reading_direction:left_to_right"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -420,11 +433,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "age_rating:12"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "age_rating:12"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -446,11 +460,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "language:en-us"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "language:en-us"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -478,46 +493,52 @@ class SeriesDtoDaoTest( // when val foundByBookTag = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "book_tag:booktag"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "book_tag:booktag"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content val notFoundByBookTag = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "book_tag:seriestag"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "book_tag:seriestag"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content val foundBySeriesTag = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "series_tag:seriestag"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "series_tag:seriestag"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content val notFoundBySeriesTag = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "series_tag:booktag"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "series_tag:booktag"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content val foundByTagFromBook = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "tag:booktag"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "tag:booktag"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content val foundByTagFromSeries = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "tag:seriestag"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "tag:seriestag"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(foundByBookTag).hasSize(1) @@ -552,11 +573,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "genre:action"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "genre:action"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -578,11 +600,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "total_book_count:5"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "total_book_count:5"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -612,11 +635,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "book_count:2"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "book_count:2"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -648,25 +672,28 @@ class SeriesDtoDaoTest( // when val foundGeneric = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "author:david"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "author:david"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content val foundByRole = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "penciller:david"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "penciller:david"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content val notFoundByRole = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "writer:david"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "writer:david"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(foundGeneric).hasSize(1) @@ -696,11 +723,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "release_date:1999"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "release_date:1999"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) @@ -718,11 +746,12 @@ class SeriesDtoDaoTest( // when val found = - seriesDtoDao.findAll( - SeriesSearch(fullTextSearch = "deleted:true"), - SearchContext(user), - UnpagedSorted(Sort.by("relevance")), - ).content + seriesDtoDao + .findAll( + SeriesSearch(fullTextSearch = "deleted:true"), + SearchContext(user), + UnpagedSorted(Sort.by("relevance")), + ).content // then assertThat(found).hasSize(1) diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDaoTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDaoTest.kt index 70c9f7f7..c67a97ca 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDaoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDaoTest.kt @@ -260,7 +260,8 @@ class TasksDaoTest( // when val disownCount = tasksDao.disown() val disownedTasks = - tasksDao.findAll() + tasksDao + .findAll() .filter { task -> ownedTasks.map { it.uniqueId }.contains(task.uniqueId) } val groupedByOwner = tasksDao.findAllGroupedByOwner() diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/NavTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/NavTest.kt index 2de79d31..2bd792c1 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/NavTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/NavTest.kt @@ -30,8 +30,8 @@ class NavTest { assertThat(nav).isEqualTo(expectedNav) } - private fun paramSource(): Stream { - return Stream.of( + private fun paramSource(): Stream = + Stream.of( Arguments.of(Epub3Nav.TOC, null, ::getExpectedNavToc), Arguments.of(Epub3Nav.TOC, "PREFIX", ::getExpectedNavToc), Arguments.of(Epub3Nav.LANDMARKS, null, ::getExpectedNavLandmarks), @@ -39,7 +39,6 @@ class NavTest { Arguments.of(Epub3Nav.PAGELIST, null, ::getExpectedNavPageList), Arguments.of(Epub3Nav.PAGELIST, "PREFIX", ::getExpectedNavPageList), ) - } private fun getExpectedNavToc(prefix: String = "") = listOf( diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/NcxTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/NcxTest.kt index e7698cac..5b907f01 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/NcxTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/NcxTest.kt @@ -30,14 +30,13 @@ class NcxTest { assertThat(ncxNav).isEqualTo(expectedNav) } - private fun paramSource(): Stream { - return Stream.of( + private fun paramSource(): Stream = + Stream.of( Arguments.of(Epub2Nav.TOC, null, ::getExpectedNcxToc), Arguments.of(Epub2Nav.TOC, "PREFIX", ::getExpectedNcxToc), Arguments.of(Epub2Nav.PAGELIST, null, ::getExpectedNcxPageList), Arguments.of(Epub2Nav.PAGELIST, "PREFIX", ::getExpectedNcxPageList), ) - } private fun getExpectedNcxToc(prefix: String = "") = listOf( diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/SessionTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/SessionTest.kt index 0413371a..3856990b 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/SessionTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/SessionTest.kt @@ -42,74 +42,84 @@ class SessionTest( @Test fun `given valid basic credentials when hitting an endpoint then session cookie is returned`() { - mockMvc.get("/api/v2/users/me") { - with(httpBasic(user.email, user.password)) - }.andExpect { - header { - string(HttpHeaders.SET_COOKIE, containsString("$sessionCookieName=")) + mockMvc + .get("/api/v2/users/me") { + with(httpBasic(user.email, user.password)) + }.andExpect { + header { + string(HttpHeaders.SET_COOKIE, containsString("$sessionCookieName=")) + } + cookie { + exists(sessionCookieName) + httpOnly(sessionCookieName, true) + } } - cookie { - exists(sessionCookieName) - httpOnly(sessionCookieName, true) - } - } } @Test fun `given valid basic credentials when providing the auth header then session is returned in headers`() { - mockMvc.get("/api/v2/users/me") { - with(httpBasic(user.email, user.password)) - header(sessionHeaderName, "") - }.andExpect { - header { - exists(sessionHeaderName) + mockMvc + .get("/api/v2/users/me") { + with(httpBasic(user.email, user.password)) + header(sessionHeaderName, "") + }.andExpect { + header { + exists(sessionHeaderName) + } } - } } @Test fun `given existing session when exchanging for cookies then session is returned in cookies`() { val sessionId = - mockMvc.get("/api/v2/users/me") { - with(httpBasic(user.email, user.password)) - header(sessionHeaderName, "") - }.andReturn().response.getHeader(this.sessionHeaderName) + mockMvc + .get("/api/v2/users/me") { + with(httpBasic(user.email, user.password)) + header(sessionHeaderName, "") + }.andReturn() + .response + .getHeader(this.sessionHeaderName) assertThat(sessionId).isNotNull - mockMvc.get("/api/v1/login/set-cookie") { - header(sessionHeaderName, sessionId!!) - }.andExpect { - header { - string(HttpHeaders.SET_COOKIE, containsString("$sessionCookieName=")) - doesNotExist(sessionHeaderName) + mockMvc + .get("/api/v1/login/set-cookie") { + header(sessionHeaderName, sessionId!!) + }.andExpect { + header { + string(HttpHeaders.SET_COOKIE, containsString("$sessionCookieName=")) + doesNotExist(sessionHeaderName) + } + cookie { + exists(sessionCookieName) + httpOnly(sessionCookieName, true) + } } - cookie { - exists(sessionCookieName) - httpOnly(sessionCookieName, true) - } - } } @Test fun `given existing session when logging out then session cookie is cleared`() { val sessionId = - mockMvc.get("/api/v2/users/me") { - with(httpBasic(user.email, user.password)) - header(sessionHeaderName, "") - }.andReturn().response.getHeader(this.sessionHeaderName) + mockMvc + .get("/api/v2/users/me") { + with(httpBasic(user.email, user.password)) + header(sessionHeaderName, "") + }.andReturn() + .response + .getHeader(this.sessionHeaderName) assertThat(sessionId).isNotNull - mockMvc.get("/api/logout") { - header(sessionHeaderName, sessionId!!) - }.andExpect { - header { - string(HttpHeaders.SET_COOKIE, containsString("$sessionCookieName=;")) + mockMvc + .get("/api/logout") { + header(sessionHeaderName, sessionId!!) + }.andExpect { + header { + string(HttpHeaders.SET_COOKIE, containsString("$sessionCookieName=;")) + } + cookie { + maxAge(sessionCookieName, 0) + } } - cookie { - maxAge(sessionCookieName, 0) - } - } } } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/kobo/KoboControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/kobo/KoboControllerTest.kt index 5b7df0da..d4fd8559 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/kobo/KoboControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/kobo/KoboControllerTest.kt @@ -93,7 +93,8 @@ class KoboControllerTest( // first sync val mvcResult1 = - mockMvc.get("/kobo/$apiKey/v1/library/sync") + mockMvc + .get("/kobo/$apiKey/v1/library/sync") .andExpect { status { isOk() } jsonPath("$.length()") { value(1) } @@ -107,10 +108,10 @@ class KoboControllerTest( // second sync val mvcResult2 = - mockMvc.get("/kobo/$apiKey/v1/library/sync") { - header(KoboHeaders.X_KOBO_SYNCTOKEN, syncToken1Base64) - } - .andExpect { + mockMvc + .get("/kobo/$apiKey/v1/library/sync") { + header(KoboHeaders.X_KOBO_SYNCTOKEN, syncToken1Base64) + }.andExpect { status { isOk() } jsonPath("$.length()") { value(1) } header { doesNotExist(KoboHeaders.X_KOBO_SYNC) } @@ -126,7 +127,8 @@ class KoboControllerTest( komgaSettingsProvider.koboProxy = true try { - mockMvc.get("/kobo/$apiKey/v1/books/nonexistent/thumbnail/800/800/false/image.jpg") + mockMvc + .get("/kobo/$apiKey/v1/books/nonexistent/thumbnail/800/800/false/image.jpg") .andExpect { status { isTemporaryRedirect() } header { string(HttpHeaders.LOCATION, "https://cdn.kobo.com/book-images/nonexistent/800/800/false/image.jpg") } @@ -155,11 +157,11 @@ class KoboControllerTest( koboPort?.let { komgaSettingsProvider.koboPort = it } try { - mockMvc.get("/kobo/$apiKey/v1/initialization") { - header(HttpHeaders.HOST, hostHeader) - extraHeaders?.forEach { (h, v) -> header(h, v) } - } - .andExpect { + mockMvc + .get("/kobo/$apiKey/v1/initialization") { + header(HttpHeaders.HOST, hostHeader) + extraHeaders?.forEach { (h, v) -> header(h, v) } + }.andExpect { jsonPath("Resources.image_host") { value(expected) } }.andReturn() } finally { diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/opds/OpdsControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/opds/OpdsControllerTest.kt index e1d76278..a47cee67 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/opds/OpdsControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/opds/OpdsControllerTest.kt @@ -91,7 +91,8 @@ class OpdsControllerTest( } } - mockMvc.get("/opds/v1.2/series") + mockMvc + .get("/opds/v1.2/series") .andExpect { status { isOk() } xpath("/feed/entry/id") { @@ -153,7 +154,8 @@ class OpdsControllerTest( mockMvc.get("/opds/v1.2/series/${series15.id}").andExpect { status { isForbidden() } } mockMvc.get("/opds/v1.2/series/${series.id}").andExpect { status { isForbidden() } } - mockMvc.get("/opds/v1.2/series") + mockMvc + .get("/opds/v1.2/series") .andExpect { status { isOk() } xpath("/feed/entry/id") { nodeCount(2) } @@ -211,7 +213,8 @@ class OpdsControllerTest( mockMvc.get("/opds/v1.2/series/${series16.id}").andExpect { status { isForbidden() } } mockMvc.get("/opds/v1.2/series/${series18.id}").andExpect { status { isForbidden() } } - mockMvc.get("/opds/v1.2/series") + mockMvc + .get("/opds/v1.2/series") .andExpect { status { isOk() } xpath("/feed/entry/id") { nodeCount(2) } @@ -232,7 +235,8 @@ class OpdsControllerTest( } seriesLifecycle.createSeries(makeSeries("Beta", libraryId = library.id)) - mockMvc.get("/opds/v1.2/series") + mockMvc + .get("/opds/v1.2/series") .andExpect { status { isOk() } xpath("/feed/entry[1]/title") { string("TheAlpha") } @@ -249,7 +253,8 @@ class OpdsControllerTest( seriesLifecycle.createSeries(it) } - mockMvc.get("/opds/v1.2/series") + mockMvc + .get("/opds/v1.2/series") .andExpect { status { isOk() } xpath("/feed/entry[1]/title") { string("a") } @@ -270,7 +275,8 @@ class OpdsControllerTest( } seriesLifecycle.createSeries(makeSeries("Beta", libraryId = library.id)) - mockMvc.get("/opds/v1.2/series") + mockMvc + .get("/opds/v1.2/series") .andExpect { status { isOk() } xpath("/feed/entry") { nodeCount(1) } @@ -302,7 +308,8 @@ class OpdsControllerTest( } } - mockMvc.get("/opds/v1.2/series/${createdSeries.id}") + mockMvc + .get("/opds/v1.2/series/${createdSeries.id}") .andExpect { status { isOk() } xpath("/feed/entry[1]/title") { string("1") } @@ -335,7 +342,8 @@ class OpdsControllerTest( seriesLifecycle.addBooks(createdSeries, listOf(addedBook)) seriesLifecycle.sortBooks(createdSeries) - mockMvc.get("/opds/v1.2/series/${createdSeries.id}") + mockMvc + .get("/opds/v1.2/series/${createdSeries.id}") .andExpect { status { isOk() } xpath("/feed/entry") { nodeCount(2) } @@ -367,7 +375,8 @@ class OpdsControllerTest( bookRepository.update(it.copy(deletedDate = LocalDateTime.now())) } - mockMvc.get("/opds/v1.2/series/${createdSeries.id}") + mockMvc + .get("/opds/v1.2/series/${createdSeries.id}") .andExpect { status { isOk() } xpath("/feed/entry") { nodeCount(2) } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ActuatorTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ActuatorTest.kt index f412a075..55f780e8 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ActuatorTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ActuatorTest.kt @@ -21,12 +21,14 @@ class ActuatorTest( @Test @WithAnonymousUser fun `given anonymous user when getting actuator endpoints then returns unauthorized`() { - mockMvc.get("/actuator") + mockMvc + .get("/actuator") .andExpect { status { isUnauthorized() } } - mockMvc.get("/actuator/beans") + mockMvc + .get("/actuator/beans") .andExpect { status { isUnauthorized() } } @@ -35,7 +37,8 @@ class ActuatorTest( @Test @WithAnonymousUser fun `given anonymous user when getting actuator health endpoint then returns ok`() { - mockMvc.get("/actuator/health") + mockMvc + .get("/actuator/health") .andExpect { status { isOk() } } @@ -44,12 +47,14 @@ class ActuatorTest( @Test @WithMockUser(roles = [ROLE_USER]) fun `given regular user when getting actuator endpoints then returns forbidden`() { - mockMvc.get("/actuator") + mockMvc + .get("/actuator") .andExpect { status { isForbidden() } } - mockMvc.get("/actuator/beans") + mockMvc + .get("/actuator/beans") .andExpect { status { isForbidden() } } @@ -58,12 +63,14 @@ class ActuatorTest( @Test @WithMockUser(roles = [ROLE_ADMIN]) fun `given admin user when getting actuator endpoints then returns ok`() { - mockMvc.get("/actuator") + mockMvc + .get("/actuator") .andExpect { status { isOk() } } - mockMvc.get("/actuator/beans") + mockMvc + .get("/actuator/beans") .andExpect { status { isOk() } } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementControllerTest.kt index a84cd94d..15ce1ee9 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementControllerTest.kt @@ -61,7 +61,8 @@ class AnnouncementControllerTest( every { announcementController.fetchWebsiteAnnouncements() } returns mockFeed repeat(2) { - mockMvc.get("/api/v1/announcements") + mockMvc + .get("/api/v1/announcements") .andExpect { status { isOk() } jsonPath("$.items.length()") { value(1) } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerPageTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerPageTest.kt index 8942215f..022db288 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerPageTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerPageTest.kt @@ -102,10 +102,10 @@ class BookControllerPageTest( every { mockAnalyzer.getPageContentRaw(any(), 1) } returns TypedBytes(ByteArray(0), "application/pdf") every { bookLifecycle.getBookPage(any(), 1, any(), any()) } returns TypedBytes(ByteArray(0), "image/jpeg") - mockMvc.get("/api/v1/books/${book.id}/pages/1") { - if (acceptTypes.isNotEmpty()) accept(*acceptTypes.toTypedArray()) - } - .andExpect { + mockMvc + .get("/api/v1/books/${book.id}/pages/1") { + if (acceptTypes.isNotEmpty()) accept(*acceptTypes.toTypedArray()) + }.andExpect { status { if (success) isOk() else isBadRequest() } if (resultType != null) header { string(HttpHeaders.CONTENT_TYPE, resultType) } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerTest.kt index 34857d59..827c9b5e 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerTest.kt @@ -117,7 +117,8 @@ class BookControllerTest( } } - mockMvc.get("/api/v1/books") + mockMvc + .get("/api/v1/books") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(1) } @@ -177,7 +178,8 @@ class BookControllerTest( mockMvc.get("/api/v1/books/${book15.id}").andExpect { status { isForbidden() } } mockMvc.get("/api/v1/books/${book.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/books?sort=metadata.title") + mockMvc + .get("/api/v1/books?sort=metadata.title") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -235,7 +237,8 @@ class BookControllerTest( mockMvc.get("/api/v1/books/${book10.id}").andExpect { status { isForbidden() } } mockMvc.get("/api/v1/books/${book15.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/books?sort=metadata.title") + mockMvc + .get("/api/v1/books?sort=metadata.title") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -293,7 +296,8 @@ class BookControllerTest( mockMvc.get("/api/v1/books/${bookAdult.id}").andExpect { status { isForbidden() } } mockMvc.get("/api/v1/books/${book.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/books?sort=metadata.title") + mockMvc + .get("/api/v1/books?sort=metadata.title") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -351,7 +355,8 @@ class BookControllerTest( mockMvc.get("/api/v1/books/${bookAdult.id}").andExpect { status { isOk() } } mockMvc.get("/api/v1/books/${book.id}").andExpect { status { isOk() } } - mockMvc.get("/api/v1/books?sort=metadata.title") + mockMvc + .get("/api/v1/books?sort=metadata.title") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -409,7 +414,8 @@ class BookControllerTest( mockMvc.get("/api/v1/books/${bookAdult.id}").andExpect { status { isForbidden() } } mockMvc.get("/api/v1/books/${book.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/books?sort=metadata.title") + mockMvc + .get("/api/v1/books?sort=metadata.title") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -434,7 +440,8 @@ class BookControllerTest( mockMvc.get("/api/v1/books/${bookTeen16.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/books") + mockMvc + .get("/api/v1/books") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(0) } @@ -456,7 +463,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}") + mockMvc + .get("/api/v1/books/${book.id}") .andExpect { status { isForbidden() } } } @@ -472,7 +480,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}/thumbnail") + mockMvc + .get("/api/v1/books/${book.id}/thumbnail") .andExpect { status { isForbidden() } } } @@ -488,7 +497,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}/file") + mockMvc + .get("/api/v1/books/${book.id}/file") .andExpect { status { isForbidden() } } } @@ -504,7 +514,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}/pages") + mockMvc + .get("/api/v1/books/${book.id}/pages") .andExpect { status { isForbidden() } } } @@ -520,7 +531,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}/pages/1") + mockMvc + .get("/api/v1/books/${book.id}/pages/1") .andExpect { status { isForbidden() } } } } @@ -539,7 +551,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}/pages/1") + mockMvc + .get("/api/v1/books/${book.id}/pages/1") .andExpect { status { isForbidden() } } } @@ -555,7 +568,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}/file") + mockMvc + .get("/api/v1/books/${book.id}/file") .andExpect { status { isForbidden() } } } } @@ -574,7 +588,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}/thumbnail") + mockMvc + .get("/api/v1/books/${book.id}/thumbnail") .andExpect { status { isNotFound() } } } @@ -590,7 +605,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}/file") + mockMvc + .get("/api/v1/books/${book.id}/file") .andExpect { status { isNotFound() } } } @@ -610,7 +626,8 @@ class BookControllerTest( mediaRepository.update(it.copy(status = status)) } - mockMvc.get("/api/v1/books/${book.id}/pages") + mockMvc + .get("/api/v1/books/${book.id}/pages") .andExpect { status { isNotFound() } } } @@ -630,7 +647,8 @@ class BookControllerTest( mediaRepository.update(it.copy(status = status)) } - mockMvc.get("/api/v1/books/${book.id}/pages/1") + mockMvc + .get("/api/v1/books/${book.id}/pages/1") .andExpect { status { isNotFound() } } } } @@ -656,7 +674,8 @@ class BookControllerTest( ) } - mockMvc.get("/api/v1/books/${book.id}/pages/$page") + mockMvc + .get("/api/v1/books/${book.id}/pages/$page") .andExpect { status { isBadRequest() } } } @@ -676,31 +695,37 @@ class BookControllerTest( } } - mockMvc.get("/api/v1/books/${book1.id}/previous") + mockMvc + .get("/api/v1/books/${book1.id}/previous") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/books/${book1.id}/next") + mockMvc + .get("/api/v1/books/${book1.id}/next") .andExpect { status { isOk() } jsonPath("$.name") { value("2") } } - mockMvc.get("/api/v1/books/${book2.id}/previous") + mockMvc + .get("/api/v1/books/${book2.id}/previous") .andExpect { status { isOk() } jsonPath("$.name") { value("1") } } - mockMvc.get("/api/v1/books/${book2.id}/next") + mockMvc + .get("/api/v1/books/${book2.id}/next") .andExpect { status { isOk() } jsonPath("$.name") { value("3") } } - mockMvc.get("/api/v1/books/${book3.id}/previous") + mockMvc + .get("/api/v1/books/${book3.id}/previous") .andExpect { status { isOk() } jsonPath("$.name") { value("2") } } - mockMvc.get("/api/v1/books/${book3.id}/next") + mockMvc + .get("/api/v1/books/${book3.id}/next") .andExpect { status { isNotFound() } } } } @@ -725,16 +750,20 @@ class BookControllerTest( jsonPath("$.content[0].url") { value("1.cbr") } } - mockMvc.get("/api/v1/books") + mockMvc + .get("/api/v1/books") .andExpect(validation) - mockMvc.get("/api/v1/books/latest") + mockMvc + .get("/api/v1/books/latest") .andExpect(validation) - mockMvc.get("/api/v1/series/${createdSeries.id}/books") + mockMvc + .get("/api/v1/series/${createdSeries.id}/books") .andExpect(validation) - mockMvc.get("/api/v1/books/${book.id}") + mockMvc + .get("/api/v1/books/${book.id}") .andExpect { status { isOk() } jsonPath("$.url") { value("1.cbr") } @@ -759,16 +788,20 @@ class BookControllerTest( jsonPath("$.content[0].url") { value(containsString("1.cbr")) } } - mockMvc.get("/api/v1/books") + mockMvc + .get("/api/v1/books") .andExpect(validation) - mockMvc.get("/api/v1/books/latest") + mockMvc + .get("/api/v1/books/latest") .andExpect(validation) - mockMvc.get("/api/v1/series/${createdSeries.id}/books") + mockMvc + .get("/api/v1/series/${createdSeries.id}/books") .andExpect(validation) - mockMvc.get("/api/v1/books/${book.id}") + mockMvc + .get("/api/v1/books/${book.id}") .andExpect { status { isOk() } jsonPath("$.url") { value(containsString("1.cbr")) } @@ -804,16 +837,19 @@ class BookControllerTest( val url = "/api/v1/books/${book.id}/thumbnail" val response = - mockMvc.get(url) - .andReturn().response + mockMvc + .get(url) + .andReturn() + .response - mockMvc.get(url) { - headers { - ifNoneMatch = listOf(response.getHeader(HttpHeaders.ETAG)!!) + mockMvc + .get(url) { + headers { + ifNoneMatch = listOf(response.getHeader(HttpHeaders.ETAG)!!) + } + }.andExpect { + status { isNotModified() } } - }.andExpect { - status { isNotModified() } - } } @Test @@ -831,16 +867,20 @@ class BookControllerTest( val url = "/api/v1/books/${book.id}/pages/1" val lastModified = - mockMvc.get(url) - .andReturn().response.getHeader(HttpHeaders.LAST_MODIFIED) + mockMvc + .get(url) + .andReturn() + .response + .getHeader(HttpHeaders.LAST_MODIFIED) - mockMvc.get(url) { - headers { - set(HttpHeaders.IF_MODIFIED_SINCE, lastModified!!) + mockMvc + .get(url) { + headers { + set(HttpHeaders.IF_MODIFIED_SINCE, lastModified!!) + } + }.andExpect { + status { isNotModified() } } - }.andExpect { - status { isNotModified() } - } } @Test @@ -883,13 +923,14 @@ class BookControllerTest( MarkSelectedPreference.YES, ) - mockMvc.get(url) { - headers { - ifNoneMatch = listOf(response.getHeader(HttpHeaders.ETAG)!!) + mockMvc + .get(url) { + headers { + ifNoneMatch = listOf(response.getHeader(HttpHeaders.ETAG)!!) + } + }.andExpect { + status { isOk() } } - }.andExpect { - status { isOk() } - } } } @@ -898,12 +939,13 @@ class BookControllerTest( @Test @WithMockCustomUser fun `given non-admin user when updating metadata then raise forbidden`() { - mockMvc.patch("/api/v1/books/1/metadata") { - contentType = MediaType.APPLICATION_JSON - content = "{}" - }.andExpect { - status { isForbidden() } - } + mockMvc + .patch("/api/v1/books/1/metadata") { + contentType = MediaType.APPLICATION_JSON + content = "{}" + }.andExpect { + status { isForbidden() } + } } @ParameterizedTest @@ -918,12 +960,13 @@ class BookControllerTest( ) @WithMockCustomUser(roles = [ROLE_ADMIN]) fun `given invalid json when updating metadata then raise validation error`(jsonString: String) { - mockMvc.patch("/api/v1/books/1/metadata") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .patch("/api/v1/books/1/metadata") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -970,12 +1013,13 @@ class BookControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/books/$bookId/metadata") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/books/$bookId/metadata") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } val metadata = bookMetadataRepository.findById(bookId) with(metadata) { @@ -1035,12 +1079,13 @@ class BookControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/books/$bookId/metadata") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/books/$bookId/metadata") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } val updatedMetadata = bookMetadataRepository.findById(bookId) with(updatedMetadata) { @@ -1093,12 +1138,13 @@ class BookControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/books/$bookId/metadata") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/books/$bookId/metadata") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } val updatedMetadata = bookMetadataRepository.findById(bookId) with(updatedMetadata) { @@ -1147,12 +1193,13 @@ class BookControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/books/$bookId/metadata") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/books/$bookId/metadata") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } val metadata = bookMetadataRepository.findById(bookId) with(metadata) { @@ -1179,12 +1226,13 @@ class BookControllerTest( ) @WithMockCustomUser fun `given invalid payload when marking book in progress then validation error is returned`(jsonString: String) { - mockMvc.patch("/api/v1/books/1/read-progress") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .patch("/api/v1/books/1/read-progress") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -1216,14 +1264,16 @@ class BookControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/books/${book.id}/read-progress") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/books/${book.id}/read-progress") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } - mockMvc.get("/api/v1/books/${book.id}") + mockMvc + .get("/api/v1/books/${book.id}") .andExpect { status { isOk() } jsonPath("$.readProgress.page") { value(5) } @@ -1260,14 +1310,16 @@ class BookControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/books/${book.id}/read-progress") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/books/${book.id}/read-progress") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } - mockMvc.get("/api/v1/books/${book.id}") + mockMvc + .get("/api/v1/books/${book.id}") .andExpect { status { isOk() } jsonPath("$.readProgress.page") { value(10) } @@ -1305,20 +1357,23 @@ class BookControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/books/${book.id}/read-progress") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/books/${book.id}/read-progress") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } - mockMvc.delete("/api/v1/books/${book.id}/read-progress") { - contentType = MediaType.APPLICATION_JSON - }.andExpect { - status { isNoContent() } - } + mockMvc + .delete("/api/v1/books/${book.id}/read-progress") { + contentType = MediaType.APPLICATION_JSON + }.andExpect { + status { isNoContent() } + } - mockMvc.get("/api/v1/books/${book.id}") + mockMvc + .get("/api/v1/books/${book.id}") .andExpect { status { isOk() } jsonPath("$.readProgress") { value(IsNull.nullValue()) } @@ -1361,23 +1416,25 @@ class BookControllerTest( .content(jsonString), ) - mockMvc.perform( - MockMvcRequestBuilders - .get("/api/v1/books") - .with(user(KomgaPrincipal(user))) - .contentType(MediaType.APPLICATION_JSON), - ).andExpect( - jsonPath("$.totalElements").value(2), - ) + mockMvc + .perform( + MockMvcRequestBuilders + .get("/api/v1/books") + .with(user(KomgaPrincipal(user))) + .contentType(MediaType.APPLICATION_JSON), + ).andExpect( + jsonPath("$.totalElements").value(2), + ) - mockMvc.perform( - MockMvcRequestBuilders - .get("/api/v1/books") - .with(user(KomgaPrincipal(user2))) - .contentType(MediaType.APPLICATION_JSON), - ).andExpect( - jsonPath("$.totalElements").value(2), - ) + mockMvc + .perform( + MockMvcRequestBuilders + .get("/api/v1/books") + .with(user(KomgaPrincipal(user2))) + .contentType(MediaType.APPLICATION_JSON), + ).andExpect( + jsonPath("$.totalElements").value(2), + ) } @Test @@ -1385,7 +1442,8 @@ class BookControllerTest( fun `given book with Unicode name when getting book file then attachment name is correct`() { val bookName = "アキラ" val tempFile = - Files.createTempFile(bookName, ".cbz") + Files + .createTempFile(bookName, ".cbz") .also { it.toFile().deleteOnExit() } makeSeries(name = "series", libraryId = library.id).let { series -> seriesLifecycle.createSeries(series).let { created -> @@ -1396,7 +1454,8 @@ class BookControllerTest( val book = bookRepository.findAll().first() - mockMvc.get("/api/v1/books/${book.id}/file") + mockMvc + .get("/api/v1/books/${book.id}/file") .andExpect { status { isOk() } header { string("Content-Disposition", containsString(URLEncoder.encode(bookName, StandardCharsets.UTF_8.name()))) } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ClaimControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ClaimControllerTest.kt index 3812ff02..99ceba84 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ClaimControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ClaimControllerTest.kt @@ -23,18 +23,20 @@ class ClaimControllerTest( fun `given unclaimed server when claiming with invalid email address then returns bad request`(email: String) { val password = "password" - mockMvc.post("/api/v1/claim") { - header("X-Komga-Email", email) - header("X-Komga-Password", password) - }.andExpect { - status { isBadRequest() } - } + mockMvc + .post("/api/v1/claim") { + header("X-Komga-Email", email) + header("X-Komga-Password", password) + }.andExpect { + status { isBadRequest() } + } } @Test @WithAnonymousUser fun `given anonymous user when getting claim status then returns OK`() { - mockMvc.get("/api/v1/claim") + mockMvc + .get("/api/v1/claim") .andExpect { status { isOk() } } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemControllerTest.kt index 7d5a2a5c..29b76a91 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemControllerTest.kt @@ -25,24 +25,27 @@ class FileSystemControllerTest( @Test @WithAnonymousUser fun `given anonymous user when getDirectoryListing then return unauthorized`() { - mockMvc.post(route) + mockMvc + .post(route) .andExpect { status { isUnauthorized() } } } @Test @WithMockUser fun `given regular user when getDirectoryListing then return forbidden`() { - mockMvc.post(route) + mockMvc + .post(route) .andExpect { status { isForbidden() } } } @Test @WithMockUser(roles = [ROLE_USER, ROLE_ADMIN]) fun `given relative path param when getDirectoryListing then return bad request`() { - mockMvc.post(route) { - contentType = MediaType.APPLICATION_JSON - content = "." - }.andExpect { status { isBadRequest() } } + mockMvc + .post(route) { + contentType = MediaType.APPLICATION_JSON + content = "." + }.andExpect { status { isBadRequest() } } } @Test @@ -52,9 +55,10 @@ class FileSystemControllerTest( ) { Files.delete(parent) - mockMvc.post(route) { - contentType = MediaType.APPLICATION_JSON - content = parent.toString() - }.andExpect { status { isBadRequest() } } + mockMvc + .post(route) { + contentType = MediaType.APPLICATION_JSON + content = parent.toString() + }.andExpect { status { isBadRequest() } } } } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/LibraryControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/LibraryControllerTest.kt index 971875a2..1f2bf53f 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/LibraryControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/LibraryControllerTest.kt @@ -48,7 +48,8 @@ class LibraryControllerTest( @Test @WithAnonymousUser fun `given anonymous user when getAll then return unauthorized`() { - mockMvc.get(route) + mockMvc + .get(route) .andExpect { status { isUnauthorized() } } } @@ -58,10 +59,11 @@ class LibraryControllerTest( // language=JSON val jsonString = """{"name":"test", "root": "C:\\Temp"}""" - mockMvc.post(route) { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { status { isUnauthorized() } } + mockMvc + .post(route) { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { status { isUnauthorized() } } } } @@ -70,7 +72,8 @@ class LibraryControllerTest( @Test @WithMockCustomUser fun `given user with access to all libraries when getAll then return ok`() { - mockMvc.get(route) + mockMvc + .get(route) .andExpect { status { isOk() } } } @@ -80,10 +83,11 @@ class LibraryControllerTest( // language=JSON val jsonString = """{"name":"test", "root": "C:\\Temp"}""" - mockMvc.post(route) { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { status { isForbidden() } } + mockMvc + .post(route) { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { status { isForbidden() } } } } @@ -92,7 +96,8 @@ class LibraryControllerTest( @Test @WithMockCustomUser(sharedAllLibraries = false, sharedLibraries = ["1"]) fun `given user with access to a single library when getAll then only gets this library`() { - mockMvc.get(route) + mockMvc + .get(route) .andExpect { status { isOk() } jsonPath("$.length()") { value(1) } @@ -106,13 +111,15 @@ class LibraryControllerTest( @Test @WithMockCustomUser fun `given regular user when getting libraries then root is hidden`() { - mockMvc.get(route) + mockMvc + .get(route) .andExpect { status { isOk() } jsonPath("$[0].root") { value("") } } - mockMvc.get("$route/${library.id}") + mockMvc + .get("$route/${library.id}") .andExpect { status { isOk() } jsonPath("$.root") { value("") } @@ -122,13 +129,15 @@ class LibraryControllerTest( @Test @WithMockCustomUser(roles = [ROLE_ADMIN]) fun `given admin user when getting books then root is available`() { - mockMvc.get(route) + mockMvc + .get(route) .andExpect { status { isOk() } jsonPath("$[0].root") { value(Matchers.containsString("library1")) } } - mockMvc.get("$route/${library.id}") + mockMvc + .get("$route/${library.id}") .andExpect { status { isOk() } jsonPath("$.root") { value(Matchers.containsString("library1")) } @@ -143,14 +152,16 @@ class LibraryControllerTest( fun `given library with exclusions when getting libraries then exclusions are present`() { libraryRepository.update(library.copy(scanDirectoryExclusions = setOf("test", "value"))) - mockMvc.get(route) + mockMvc + .get(route) .andExpect { status { isOk() } jsonPath("$[0].scanDirectoryExclusions.length()") { value(2) } jsonPath("$[0].scanDirectoryExclusions") { hasItems("test", "value") } } - mockMvc.get("$route/${library.id}") + mockMvc + .get("$route/${library.id}") .andExpect { status { isOk() } jsonPath("$.scanDirectoryExclusions.length()") { value(2) } @@ -173,15 +184,16 @@ class LibraryControllerTest( } """.trimIndent() - mockMvc.patch("$route/${library.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - } - .andExpect { + mockMvc + .patch("$route/${library.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { status { isNoContent() } } - mockMvc.get("$route/${library.id}") + mockMvc + .get("$route/${library.id}") .andExpect { status { isOk() } jsonPath("$.scanDirectoryExclusions.length()") { value(1) } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/OAuth2ControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/OAuth2ControllerTest.kt index bd9a2bef..8d22c7e4 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/OAuth2ControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/OAuth2ControllerTest.kt @@ -18,7 +18,8 @@ class OAuth2ControllerTest( @Test @WithAnonymousUser fun `given anonymous user when getting oauth2 providers then returns OK`() { - mockMvc.get("/api/v1/oauth2/providers") + mockMvc + .get("/api/v1/oauth2/providers") .andExpect { status { isOk() } } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ReadListControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ReadListControllerTest.kt index e845b90e..a0d089cd 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ReadListControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ReadListControllerTest.kt @@ -119,7 +119,8 @@ class ReadListControllerTest( fun `given user with access to all libraries when getting read lists then get all read lists`() { makeReadLists() - mockMvc.get("/api/v1/readlists") + mockMvc + .get("/api/v1/readlists") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(3) } @@ -134,7 +135,8 @@ class ReadListControllerTest( fun `given user with access to a single library when getting read lists then only get read lists from this library`() { makeReadLists() - mockMvc.get("/api/v1/readlists") + mockMvc + .get("/api/v1/readlists") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -148,7 +150,8 @@ class ReadListControllerTest( fun `given user with access to all libraries when getting single read list then it is not filtered`() { makeReadLists() - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(10) } @@ -161,7 +164,8 @@ class ReadListControllerTest( fun `given user with access to a single library when getting single read list with items from 2 libraries then it is filtered`() { makeReadLists() - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(5) } @@ -174,7 +178,8 @@ class ReadListControllerTest( fun `given user with access to a single library when getting single read list from another library then return not found`() { makeReadLists() - mockMvc.get("/api/v1/readlists/${rlLib2.id}") + mockMvc + .get("/api/v1/readlists/${rlLib2.id}") .andExpect { status { isNotFound() } } @@ -229,7 +234,8 @@ class ReadListControllerTest( ), ) - mockMvc.get("/api/v1/readlists") + mockMvc + .get("/api/v1/readlists") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -237,26 +243,30 @@ class ReadListControllerTest( jsonPath("$.content[?(@.name == '${rlFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlAllowed.id}") + mockMvc + .get("/api/v1/readlists/${rlAllowed.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(1) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(1) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlDenied.id}") + mockMvc + .get("/api/v1/readlists/${rlDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/books/${book10.id}/readlists") + mockMvc + .get("/api/v1/books/${book10.id}/readlists") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -264,19 +274,22 @@ class ReadListControllerTest( jsonPath("$[?(@.name == '${rlFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}/books") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}/books") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(1) } jsonPath("$.content[0].id") { value(book10.id) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}/books/${book10.id}/previous") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}/books/${book10.id}/previous") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}/books/${book10.id}/next") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}/books/${book10.id}/next") .andExpect { status { isNotFound() } } @@ -356,7 +369,8 @@ class ReadListControllerTest( ), ) - mockMvc.get("/api/v1/readlists") + mockMvc + .get("/api/v1/readlists") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -364,26 +378,30 @@ class ReadListControllerTest( jsonPath("$.content[?(@.name == '${rlFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlAllowed.id}") + mockMvc + .get("/api/v1/readlists/${rlAllowed.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(2) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(2) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlDenied.id}") + mockMvc + .get("/api/v1/readlists/${rlDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/books/${book10.id}/readlists") + mockMvc + .get("/api/v1/books/${book10.id}/readlists") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -391,31 +409,36 @@ class ReadListControllerTest( jsonPath("$[?(@.name == '${rlFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}/books") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}/books") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } jsonPath("$.content.[*].['id']") { contains(listOf(book10, book).map { it.id }) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}/books/${book10.id}/previous") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}/books/${book10.id}/previous") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}/books/${book10.id}/next") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}/books/${book10.id}/next") .andExpect { status { isOk() } jsonPath("$.id") { value(book.id) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}/books/${book.id}/previous") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}/books/${book.id}/previous") .andExpect { status { isOk() } jsonPath("$.id") { value(book10.id) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}/books/${book.id}/next") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}/books/${book.id}/next") .andExpect { status { isNotFound() } } @@ -489,7 +512,8 @@ class ReadListControllerTest( ), ) - mockMvc.get("/api/v1/readlists") + mockMvc + .get("/api/v1/readlists") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -497,26 +521,30 @@ class ReadListControllerTest( jsonPath("$.content[?(@.name == '${rlFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlAllowed.id}") + mockMvc + .get("/api/v1/readlists/${rlAllowed.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(2) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(2) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlDenied.id}") + mockMvc + .get("/api/v1/readlists/${rlDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/books/${bookAdult.id}/readlists") + mockMvc + .get("/api/v1/books/${bookAdult.id}/readlists") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -593,7 +621,8 @@ class ReadListControllerTest( ), ) - mockMvc.get("/api/v1/readlists") + mockMvc + .get("/api/v1/readlists") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -601,26 +630,30 @@ class ReadListControllerTest( jsonPath("$.content[?(@.name == '${rlFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlAllowed.id}") + mockMvc + .get("/api/v1/readlists/${rlAllowed.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(2) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(2) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlDenied.id}") + mockMvc + .get("/api/v1/readlists/${rlDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/books/${bookKids.id}/readlists") + mockMvc + .get("/api/v1/books/${bookKids.id}/readlists") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -678,7 +711,8 @@ class ReadListControllerTest( ), ) - mockMvc.get("/api/v1/readlists") + mockMvc + .get("/api/v1/readlists") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -686,26 +720,30 @@ class ReadListControllerTest( jsonPath("$.content[?(@.name == '${rlFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlAllowed.id}") + mockMvc + .get("/api/v1/readlists/${rlAllowed.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(1) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/readlists/${rlFiltered.id}") + mockMvc + .get("/api/v1/readlists/${rlFiltered.id}") .andExpect { status { isOk() } jsonPath("$.bookIds.length()") { value(1) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/readlists/${rlDenied.id}") + mockMvc + .get("/api/v1/readlists/${rlDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/books/${bookTeen.id}/readlists") + mockMvc + .get("/api/v1/books/${bookTeen.id}/readlists") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -722,7 +760,8 @@ class ReadListControllerTest( fun `given user with access to all libraries when getting books from single read list then it is not filtered`() { makeReadLists() - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(10) } @@ -734,7 +773,8 @@ class ReadListControllerTest( fun `given user with access to a single library when getting books from single read list with items from 2 libraries then it is filtered`() { makeReadLists() - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(5) } @@ -746,7 +786,8 @@ class ReadListControllerTest( fun `given user with access to a single library when getting books from single read list from another library then return not found`() { makeReadLists() - mockMvc.get("/api/v1/readlists/${rlLib2.id}/books") + mockMvc + .get("/api/v1/readlists/${rlLib2.id}/books") .andExpect { status { isNotFound() } } @@ -764,31 +805,37 @@ class ReadListControllerTest( val second = booksLibrary1[1].id // Book_2 val last = booksLibrary2.last().id // Book_10 - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$first/previous") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$first/previous") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$first/next") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$first/next") .andExpect { status { isOk() } jsonPath("$.name") { value("Book_2") } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$second/previous") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$second/previous") .andExpect { status { isOk() } jsonPath("$.name") { value("Book_1") } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$second/next") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$second/next") .andExpect { status { isOk() } jsonPath("$.name") { value("Book_3") } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$last/previous") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$last/previous") .andExpect { status { isOk() } jsonPath("$.name") { value("Book_9") } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$last/next") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$last/next") .andExpect { status { isNotFound() } } } @@ -801,31 +848,37 @@ class ReadListControllerTest( val second = booksLibrary1[1].id // Book_2 val last = booksLibrary1.last().id // Book_5 - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$first/previous") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$first/previous") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$first/next") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$first/next") .andExpect { status { isOk() } jsonPath("$.name") { value("Book_2") } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$second/previous") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$second/previous") .andExpect { status { isOk() } jsonPath("$.name") { value("Book_1") } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$second/next") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$second/next") .andExpect { status { isOk() } jsonPath("$.name") { value("Book_3") } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$last/previous") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$last/previous") .andExpect { status { isOk() } jsonPath("$.name") { value("Book_4") } } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}/books/$last/next") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}/books/$last/next") .andExpect { status { isNotFound() } } } @@ -834,7 +887,8 @@ class ReadListControllerTest( fun `given user with access to a single library when getting books from single read list from another library then return not found`() { makeReadLists() - mockMvc.get("/api/v1/readlists/${rlLib2.id}/books") + mockMvc + .get("/api/v1/readlists/${rlLib2.id}/books") .andExpect { status { isNotFound() } } @@ -852,12 +906,13 @@ class ReadListControllerTest( {"name":"readlist","bookIds":["3"]} """.trimIndent() - mockMvc.post("/api/v1/readlists") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isForbidden() } - } + mockMvc + .post("/api/v1/readlists") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isForbidden() } + } } @Test @@ -869,15 +924,16 @@ class ReadListControllerTest( {"name":"readlist","summary":"summary","bookIds":["${booksLibrary1.first().id}"]} """.trimIndent() - mockMvc.post("/api/v1/readlists") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isOk() } - jsonPath("$.bookIds.length()") { value(1) } - jsonPath("$.name") { value("readlist") } - jsonPath("$.summary") { value("summary") } - } + mockMvc + .post("/api/v1/readlists") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isOk() } + jsonPath("$.bookIds.length()") { value(1) } + jsonPath("$.name") { value("readlist") } + jsonPath("$.summary") { value("summary") } + } } @Test @@ -891,12 +947,13 @@ class ReadListControllerTest( {"name":"Lib1","bookIds":["${booksLibrary1.first().id}"]} """.trimIndent() - mockMvc.post("/api/v1/readlists") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .post("/api/v1/readlists") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -908,12 +965,13 @@ class ReadListControllerTest( {"name":"Lib1","bookIds":["${booksLibrary1.first().id}","${booksLibrary1.first().id}"]} """.trimIndent() - mockMvc.post("/api/v1/readlists") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .post("/api/v1/readlists") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } } @@ -928,12 +986,13 @@ class ReadListControllerTest( {"name":"readlist","bookIds":["3"]} """.trimIndent() - mockMvc.patch("/api/v1/readlists/5") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isForbidden() } - } + mockMvc + .patch("/api/v1/readlists/5") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isForbidden() } + } } @Test @@ -947,14 +1006,16 @@ class ReadListControllerTest( {"name":"updated","summary":"updatedSummary","bookIds":["${booksLibrary1.first().id}"]} """.trimIndent() - mockMvc.patch("/api/v1/readlists/${rlLib1.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/readlists/${rlLib1.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } - mockMvc.get("/api/v1/readlists/${rlLib1.id}") + mockMvc + .get("/api/v1/readlists/${rlLib1.id}") .andExpect { status { isOk() } jsonPath("$.name") { value("updated") } @@ -972,12 +1033,13 @@ class ReadListControllerTest( // language=JSON val jsonString = """{"name":"Lib2"}""" - mockMvc.patch("/api/v1/readlists/${rlLib1.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .patch("/api/v1/readlists/${rlLib1.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -988,12 +1050,13 @@ class ReadListControllerTest( // language=JSON val jsonString = """{"bookIds":["${booksLibrary1.first().id}","${booksLibrary1.first().id}"]}""" - mockMvc.patch("/api/v1/readlists/${rlLib1.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .patch("/api/v1/readlists/${rlLib1.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -1006,7 +1069,8 @@ class ReadListControllerTest( content = """{"name":"newName"}""" } - mockMvc.get("/api/v1/readlists/${rlLib2.id}") + mockMvc + .get("/api/v1/readlists/${rlLib2.id}") .andExpect { status { isOk() } jsonPath("$.name") { value("newName") } @@ -1019,7 +1083,8 @@ class ReadListControllerTest( content = """{"summary":"newSummary"}""" } - mockMvc.get("/api/v1/readlists/${rlLib1.id}") + mockMvc + .get("/api/v1/readlists/${rlLib1.id}") .andExpect { status { isOk() } jsonPath("$.name") { value("Lib1") } @@ -1032,7 +1097,8 @@ class ReadListControllerTest( content = """{"bookIds":["${booksLibrary1.first().id}"]}""" } - mockMvc.get("/api/v1/readlists/${rlLibBoth.id}") + mockMvc + .get("/api/v1/readlists/${rlLibBoth.id}") .andExpect { status { isOk() } jsonPath("$.name") { value("Lib1+2") } @@ -1047,7 +1113,8 @@ class ReadListControllerTest( @Test @WithMockCustomUser fun `given non-admin user when deleting read list then return forbidden`() { - mockMvc.delete("/api/v1/readlists/5") + mockMvc + .delete("/api/v1/readlists/5") .andExpect { status { isForbidden() } } @@ -1058,12 +1125,14 @@ class ReadListControllerTest( fun `given admin user when deleting read list then return no content`() { makeReadLists() - mockMvc.delete("/api/v1/readlists/${rlLib1.id}") + mockMvc + .delete("/api/v1/readlists/${rlLib1.id}") .andExpect { status { isNoContent() } } - mockMvc.get("/api/v1/readlists/${rlLib1.id}") + mockMvc + .get("/api/v1/readlists/${rlLib1.id}") .andExpect { status { isNotFound() } } @@ -1077,7 +1146,8 @@ class ReadListControllerTest( fun `given readlist with Unicode name when getting readlist file then attachment name is correct`() { val name = "アキラ" val tempFile = - Files.createTempFile(name, ".cbz") + Files + .createTempFile(name, ".cbz") .also { it.toFile().deleteOnExit() } val book = makeBook(name, libraryId = library1.id, url = tempFile.toUri().toURL()) makeSeries(name = "series", libraryId = library1.id).let { series -> @@ -1095,7 +1165,8 @@ class ReadListControllerTest( ), ) - mockMvc.get("/api/v1/readlists/${readlist.id}/file") + mockMvc + .get("/api/v1/readlists/${readlist.id}/file") .andExpect { status { isOk() } header { string("Content-Disposition", Matchers.containsString(URLEncoder.encode(name, StandardCharsets.UTF_8.name()))) } @@ -1159,19 +1230,22 @@ class ReadListControllerTest( @Test @WithMockCustomUser fun `given unordered read lists when getting books then books are sorted by release date`() { - mockMvc.get("/api/v1/readlists/${rlAllDiffDates.id}/books") + mockMvc + .get("/api/v1/readlists/${rlAllDiffDates.id}/books") .andExpect { status { isOk() } jsonPath("$.content.[*].['id']") { contains(listOf(1, 2).map { books[it].id }) } } - mockMvc.get("/api/v1/readlists/${rlAllNullDates.id}/books") + mockMvc + .get("/api/v1/readlists/${rlAllNullDates.id}/books") .andExpect { status { isOk() } jsonPath("$.content.[*].['id']") { contains(listOf(3, 4).map { books[it].id }) } } - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books") .andExpect { status { isOk() } jsonPath("$.content.[*].['id']") { contains(listOf(3, 4, 0, 1, 2).map { books[it].id }) } @@ -1183,95 +1257,113 @@ class ReadListControllerTest( fun `given unordered read lists when getting book siblings then it is returned according to release date sort or not found`() { // rlAllDiffDates: 1, 2 // first book: id=1 - mockMvc.get("/api/v1/readlists/${rlAllDiffDates.id}/books/${books[1].id}/previous") + mockMvc + .get("/api/v1/readlists/${rlAllDiffDates.id}/books/${books[1].id}/previous") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/readlists/${rlAllDiffDates.id}/books/${books[1].id}/next") + mockMvc + .get("/api/v1/readlists/${rlAllDiffDates.id}/books/${books[1].id}/next") .andExpect { status { isOk() } jsonPath("$.id") { value(books[2].id) } } // second book: id=2 - mockMvc.get("/api/v1/readlists/${rlAllDiffDates.id}/books/${books[2].id}/previous") + mockMvc + .get("/api/v1/readlists/${rlAllDiffDates.id}/books/${books[2].id}/previous") .andExpect { status { isOk() } jsonPath("$.id") { value(books[1].id) } } - mockMvc.get("/api/v1/readlists/${rlAllDiffDates.id}/books/${books[2].id}/next") + mockMvc + .get("/api/v1/readlists/${rlAllDiffDates.id}/books/${books[2].id}/next") .andExpect { status { isNotFound() } } // rlAllNullDates: 3, 4 // first book: id=3 - mockMvc.get("/api/v1/readlists/${rlAllNullDates.id}/books/${books[3].id}/previous") + mockMvc + .get("/api/v1/readlists/${rlAllNullDates.id}/books/${books[3].id}/previous") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/readlists/${rlAllNullDates.id}/books/${books[3].id}/next") + mockMvc + .get("/api/v1/readlists/${rlAllNullDates.id}/books/${books[3].id}/next") .andExpect { status { isOk() } jsonPath("$.id") { value(books[4].id) } } // second book: id=4 - mockMvc.get("/api/v1/readlists/${rlAllNullDates.id}/books/${books[4].id}/previous") + mockMvc + .get("/api/v1/readlists/${rlAllNullDates.id}/books/${books[4].id}/previous") .andExpect { status { isOk() } jsonPath("$.id") { value(books[3].id) } } - mockMvc.get("/api/v1/readlists/${rlAllNullDates.id}/books/${books[4].id}/next") + mockMvc + .get("/api/v1/readlists/${rlAllNullDates.id}/books/${books[4].id}/next") .andExpect { status { isNotFound() } } // rlAllBooks: 3, 4, 0, 1, 2 // first book: id=3 - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[3].id}/previous") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[3].id}/previous") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[3].id}/next") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[3].id}/next") .andExpect { status { isOk() } jsonPath("$.id") { value(books[4].id) } } // second book: id=4 - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[4].id}/previous") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[4].id}/previous") .andExpect { status { isOk() } jsonPath("$.id") { value(books[3].id) } } - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[4].id}/next") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[4].id}/next") .andExpect { status { isOk() } jsonPath("$.id") { value(books[0].id) } } // third book: id=0 - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[0].id}/previous") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[0].id}/previous") .andExpect { status { isOk() } jsonPath("$.id") { value(books[4].id) } } - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[0].id}/next") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[0].id}/next") .andExpect { status { isOk() } jsonPath("$.id") { value(books[1].id) } } // fourth book: id=1 - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[1].id}/previous") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[1].id}/previous") .andExpect { status { isOk() } jsonPath("$.id") { value(books[0].id) } } - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[1].id}/next") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[1].id}/next") .andExpect { status { isOk() } jsonPath("$.id") { value(books[2].id) } } // last book: id=2 - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[2].id}/previous") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[2].id}/previous") .andExpect { status { isOk() } jsonPath("$.id") { value(books[1].id) } } - mockMvc.get("/api/v1/readlists/${rlAllBooks.id}/books/${books[2].id}/next") + mockMvc + .get("/api/v1/readlists/${rlAllBooks.id}/books/${books[2].id}/next") .andExpect { status { isNotFound() } } } } @@ -1281,10 +1373,10 @@ class ReadListControllerTest( @Test @WithMockCustomUser fun `given non-admin user when matching cbl file then return forbidden`() { - mockMvc.multipart("/api/v1/readlists/match/comicrack") { - file("file", byteArrayOf()) - } - .andExpect { + mockMvc + .multipart("/api/v1/readlists/match/comicrack") { + file("file", byteArrayOf()) + }.andExpect { status { isForbidden() } } } @@ -1294,10 +1386,10 @@ class ReadListControllerTest( fun `given invalid cbl file when matching then return bad request`() { val content = "garbled" - mockMvc.multipart("/api/v1/readlists/match/comicrack") { - file("file", content.toByteArray()) - } - .andExpect { + mockMvc + .multipart("/api/v1/readlists/match/comicrack") { + file("file", content.toByteArray()) + }.andExpect { status { isBadRequest() reason("ERR_1015") @@ -1318,10 +1410,10 @@ class ReadListControllerTest( """.trimIndent() - mockMvc.multipart("/api/v1/readlists/match/comicrack") { - file("file", content.toByteArray()) - } - .andExpect { + mockMvc + .multipart("/api/v1/readlists/match/comicrack") { + file("file", content.toByteArray()) + }.andExpect { status { isBadRequest() reason("ERR_1029") @@ -1343,10 +1435,10 @@ class ReadListControllerTest( """.trimIndent() - mockMvc.multipart("/api/v1/readlists/match/comicrack") { - file("file", content.toByteArray()) - } - .andExpect { + mockMvc + .multipart("/api/v1/readlists/match/comicrack") { + file("file", content.toByteArray()) + }.andExpect { status { isBadRequest() reason("ERR_1030") @@ -1368,10 +1460,10 @@ class ReadListControllerTest( """.trimIndent() - mockMvc.multipart("/api/v1/readlists/match/comicrack") { - file("file", content.toByteArray()) - } - .andExpect { + mockMvc + .multipart("/api/v1/readlists/match/comicrack") { + file("file", content.toByteArray()) + }.andExpect { status { isBadRequest() reason("ERR_1031") diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionControllerTest.kt index d84c844d..978cc581 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionControllerTest.kt @@ -108,7 +108,8 @@ class SeriesCollectionControllerTest( fun `given user with access to all libraries when getting collections then get all collections`() { makeCollections() - mockMvc.get("/api/v1/collections") + mockMvc + .get("/api/v1/collections") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(3) } @@ -123,7 +124,8 @@ class SeriesCollectionControllerTest( fun `given user with access to a single library when getting collections then only get collections from this library`() { makeCollections() - mockMvc.get("/api/v1/collections") + mockMvc + .get("/api/v1/collections") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -137,14 +139,16 @@ class SeriesCollectionControllerTest( fun `given user with access to all libraries when getting single collection then it is not filtered`() { makeCollections() - mockMvc.get("/api/v1/collections/${colLibBoth.id}") + mockMvc + .get("/api/v1/collections/${colLibBoth.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(10) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/collections/${colLibBoth.id}/series") + mockMvc + .get("/api/v1/collections/${colLibBoth.id}/series") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(10) } @@ -156,7 +160,8 @@ class SeriesCollectionControllerTest( fun `given user with access to a single library when getting single collection with items from 2 libraries then it is filtered`() { makeCollections() - mockMvc.get("/api/v1/collections/${colLibBoth.id}") + mockMvc + .get("/api/v1/collections/${colLibBoth.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(5) } @@ -169,7 +174,8 @@ class SeriesCollectionControllerTest( fun `given user with access to a single library when getting single collection from another library then return not found`() { makeCollections() - mockMvc.get("/api/v1/collections/${colLib2.id}") + mockMvc + .get("/api/v1/collections/${colLib2.id}") .andExpect { status { isNotFound() } } @@ -224,7 +230,8 @@ class SeriesCollectionControllerTest( ), ) - mockMvc.get("/api/v1/collections") + mockMvc + .get("/api/v1/collections") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -232,26 +239,30 @@ class SeriesCollectionControllerTest( jsonPath("$.content[?(@.name == '${colFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colAllowed.id}") + mockMvc + .get("/api/v1/collections/${colAllowed.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(1) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/collections/${colFiltered.id}") + mockMvc + .get("/api/v1/collections/${colFiltered.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(1) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colDenied.id}") + mockMvc + .get("/api/v1/collections/${colDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/series/${series10.id}/collections") + mockMvc + .get("/api/v1/series/${series10.id}/collections") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -328,7 +339,8 @@ class SeriesCollectionControllerTest( ), ) - mockMvc.get("/api/v1/collections") + mockMvc + .get("/api/v1/collections") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -336,26 +348,30 @@ class SeriesCollectionControllerTest( jsonPath("$.content[?(@.name == '${colFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colAllowed.id}") + mockMvc + .get("/api/v1/collections/${colAllowed.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(2) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/collections/${colFiltered.id}") + mockMvc + .get("/api/v1/collections/${colFiltered.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(2) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colDenied.id}") + mockMvc + .get("/api/v1/collections/${colDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/series/${series10.id}/collections") + mockMvc + .get("/api/v1/series/${series10.id}/collections") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -432,7 +448,8 @@ class SeriesCollectionControllerTest( ), ) - mockMvc.get("/api/v1/collections") + mockMvc + .get("/api/v1/collections") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -440,26 +457,30 @@ class SeriesCollectionControllerTest( jsonPath("$.content[?(@.name == '${colFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colAllowed.id}") + mockMvc + .get("/api/v1/collections/${colAllowed.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(2) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/collections/${colFiltered.id}") + mockMvc + .get("/api/v1/collections/${colFiltered.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(2) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colDenied.id}") + mockMvc + .get("/api/v1/collections/${colDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/series/${seriesKids.id}/collections") + mockMvc + .get("/api/v1/series/${seriesKids.id}/collections") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -536,7 +557,8 @@ class SeriesCollectionControllerTest( ), ) - mockMvc.get("/api/v1/collections") + mockMvc + .get("/api/v1/collections") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -544,26 +566,30 @@ class SeriesCollectionControllerTest( jsonPath("$.content[?(@.name == '${colFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colAllowed.id}") + mockMvc + .get("/api/v1/collections/${colAllowed.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(2) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/collections/${colFiltered.id}") + mockMvc + .get("/api/v1/collections/${colFiltered.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(2) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colDenied.id}") + mockMvc + .get("/api/v1/collections/${colDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/series/${series.id}/collections") + mockMvc + .get("/api/v1/series/${series.id}/collections") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -640,7 +666,8 @@ class SeriesCollectionControllerTest( ), ) - mockMvc.get("/api/v1/collections") + mockMvc + .get("/api/v1/collections") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -648,26 +675,30 @@ class SeriesCollectionControllerTest( jsonPath("$.content[?(@.name == '${colFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colAllowed.id}") + mockMvc + .get("/api/v1/collections/${colAllowed.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(2) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/collections/${colFiltered.id}") + mockMvc + .get("/api/v1/collections/${colFiltered.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(2) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colDenied.id}") + mockMvc + .get("/api/v1/collections/${colDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/series/${seriesKids.id}/collections") + mockMvc + .get("/api/v1/series/${seriesKids.id}/collections") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -725,7 +756,8 @@ class SeriesCollectionControllerTest( ), ) - mockMvc.get("/api/v1/collections") + mockMvc + .get("/api/v1/collections") .andExpect { status { isOk() } jsonPath("$.totalElements") { value(2) } @@ -733,26 +765,30 @@ class SeriesCollectionControllerTest( jsonPath("$.content[?(@.name == '${colFiltered.name}')].filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colAllowed.id}") + mockMvc + .get("/api/v1/collections/${colAllowed.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(1) } jsonPath("$.filtered") { value(false) } } - mockMvc.get("/api/v1/collections/${colFiltered.id}") + mockMvc + .get("/api/v1/collections/${colFiltered.id}") .andExpect { status { isOk() } jsonPath("$.seriesIds.length()") { value(1) } jsonPath("$.filtered") { value(true) } } - mockMvc.get("/api/v1/collections/${colDenied.id}") + mockMvc + .get("/api/v1/collections/${colDenied.id}") .andExpect { status { isNotFound() } } - mockMvc.get("/api/v1/series/${seriesTeen.id}/collections") + mockMvc + .get("/api/v1/series/${seriesTeen.id}/collections") .andExpect { status { isOk() } jsonPath("$.length()") { value(2) } @@ -773,12 +809,13 @@ class SeriesCollectionControllerTest( {"name":"collection","ordered":false,"seriesIds":["3"]} """.trimIndent() - mockMvc.post("/api/v1/collections") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isForbidden() } - } + mockMvc + .post("/api/v1/collections") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isForbidden() } + } } @Test @@ -790,15 +827,16 @@ class SeriesCollectionControllerTest( {"name":"collection","ordered":false,"seriesIds":["${seriesLibrary1.first().id}"]} """.trimIndent() - mockMvc.post("/api/v1/collections") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isOk() } - jsonPath("$.seriesIds.length()") { value(1) } - jsonPath("$.name") { value("collection") } - jsonPath("$.ordered") { value(false) } - } + mockMvc + .post("/api/v1/collections") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isOk() } + jsonPath("$.seriesIds.length()") { value(1) } + jsonPath("$.name") { value("collection") } + jsonPath("$.ordered") { value(false) } + } } @Test @@ -812,12 +850,13 @@ class SeriesCollectionControllerTest( {"name":"Lib1","ordered":false,"seriesIds":["${seriesLibrary1.first().id}"]} """.trimIndent() - mockMvc.post("/api/v1/collections") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .post("/api/v1/collections") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -829,12 +868,13 @@ class SeriesCollectionControllerTest( {"name":"Lib1","ordered":false,"seriesIds":["${seriesLibrary1.first().id}","${seriesLibrary1.first().id}"]} """.trimIndent() - mockMvc.post("/api/v1/collections") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .post("/api/v1/collections") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } } @@ -849,12 +889,13 @@ class SeriesCollectionControllerTest( {"name":"collection","ordered":false,"seriesIds":["3"]} """.trimIndent() - mockMvc.patch("/api/v1/collections/5") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isForbidden() } - } + mockMvc + .patch("/api/v1/collections/5") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isForbidden() } + } } @Test @@ -868,14 +909,16 @@ class SeriesCollectionControllerTest( {"name":"updated","ordered":true,"seriesIds":["${seriesLibrary1.first().id}"]} """.trimIndent() - mockMvc.patch("/api/v1/collections/${colLib1.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/collections/${colLib1.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } - mockMvc.get("/api/v1/collections/${colLib1.id}") + mockMvc + .get("/api/v1/collections/${colLib1.id}") .andExpect { status { isOk() } jsonPath("$.name") { value("updated") } @@ -893,12 +936,13 @@ class SeriesCollectionControllerTest( // language=JSON val jsonString = """{"name":"Lib2"}""" - mockMvc.patch("/api/v1/collections/${colLib1.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .patch("/api/v1/collections/${colLib1.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -909,12 +953,13 @@ class SeriesCollectionControllerTest( // language=JSON val jsonString = """{"seriesIds":["${seriesLibrary1.first().id}","${seriesLibrary1.first().id}"]}""" - mockMvc.patch("/api/v1/collections/${colLib1.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .patch("/api/v1/collections/${colLib1.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -927,7 +972,8 @@ class SeriesCollectionControllerTest( content = """{"ordered":true}""" } - mockMvc.get("/api/v1/collections/${colLib1.id}") + mockMvc + .get("/api/v1/collections/${colLib1.id}") .andExpect { status { isOk() } jsonPath("$.name") { value("Lib1") } @@ -940,7 +986,8 @@ class SeriesCollectionControllerTest( content = """{"name":"newName"}""" } - mockMvc.get("/api/v1/collections/${colLib2.id}") + mockMvc + .get("/api/v1/collections/${colLib2.id}") .andExpect { status { isOk() } jsonPath("$.name") { value("newName") } @@ -953,7 +1000,8 @@ class SeriesCollectionControllerTest( content = """{"seriesIds":["${seriesLibrary1.first().id}"]}""" } - mockMvc.get("/api/v1/collections/${colLibBoth.id}") + mockMvc + .get("/api/v1/collections/${colLibBoth.id}") .andExpect { status { isOk() } jsonPath("$.name") { value("Lib1+2") } @@ -968,7 +1016,8 @@ class SeriesCollectionControllerTest( @Test @WithMockCustomUser fun `given non-admin user when deleting collection then return forbidden`() { - mockMvc.delete("/api/v1/collections/5") + mockMvc + .delete("/api/v1/collections/5") .andExpect { status { isForbidden() } } @@ -979,12 +1028,14 @@ class SeriesCollectionControllerTest( fun `given admin user when deleting collection then return no content`() { makeCollections() - mockMvc.delete("/api/v1/collections/${colLib1.id}") + mockMvc + .delete("/api/v1/collections/${colLib1.id}") .andExpect { status { isNoContent() } } - mockMvc.get("/api/v1/collections/${colLib1.id}") + mockMvc + .get("/api/v1/collections/${colLib1.id}") .andExpect { status { isNotFound() } } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SeriesControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SeriesControllerTest.kt index 319240f7..c567a8c5 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SeriesControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SeriesControllerTest.kt @@ -107,19 +107,19 @@ class SeriesControllerTest( } seriesLifecycle.createSeries(makeSeries("TheBeta", libraryId = library.id)) - mockMvc.get("/api/v1/series") { - param("search_regex", "a$,title_sort") - } - .andExpect { + mockMvc + .get("/api/v1/series") { + param("search_regex", "a$,title_sort") + }.andExpect { status { isOk() } jsonPath("$.content.length()") { value(1) } jsonPath("$.content[0].metadata.title") { value("TheBeta") } } - mockMvc.get("/api/v1/series") { - param("search_regex", "^the,title") - } - .andExpect { + mockMvc + .get("/api/v1/series") { + param("search_regex", "^the,title") + }.andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } jsonPath("$.content[0].metadata.title") { value("TheAlpha") } @@ -139,7 +139,8 @@ class SeriesControllerTest( } seriesLifecycle.createSeries(makeSeries("Beta", libraryId = library.id)) - mockMvc.get("/api/v1/series") + mockMvc + .get("/api/v1/series") .andExpect { status { isOk() } jsonPath("$.content[0].metadata.title") { value("TheAlpha") } @@ -156,10 +157,10 @@ class SeriesControllerTest( seriesLifecycle.createSeries(it) } - mockMvc.get("/api/v1/series") { - param("sort", "metadata.titleSort,asc") - } - .andExpect { + mockMvc + .get("/api/v1/series") { + param("sort", "metadata.titleSort,asc") + }.andExpect { status { isOk() } jsonPath("$.content[0].metadata.title") { value("a") } jsonPath("$.content[1].metadata.title") { value(Matchers.equalToIgnoringCase("b")) } @@ -186,7 +187,8 @@ class SeriesControllerTest( seriesLifecycle.addBooks(createdSeries, listOf(addedBook)) seriesLifecycle.sortBooks(createdSeries) - mockMvc.get("/api/v1/series/${createdSeries.id}/books") + mockMvc + .get("/api/v1/series/${createdSeries.id}/books") .andExpect { status { isOk() } jsonPath("$.content[0].name") { value("1") } @@ -210,7 +212,8 @@ class SeriesControllerTest( seriesLifecycle.addBooks(createdSeries, listOf(addedBook)) seriesLifecycle.sortBooks(createdSeries) - mockMvc.get("/api/v1/series/${createdSeries.id}/books") + mockMvc + .get("/api/v1/series/${createdSeries.id}/books") .andExpect { status { isOk() } jsonPath("$.content[0].name") { value("1") } @@ -245,7 +248,8 @@ class SeriesControllerTest( } } - mockMvc.get("/api/v1/series") + mockMvc + .get("/api/v1/series") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(1) } @@ -305,7 +309,8 @@ class SeriesControllerTest( mockMvc.get("/api/v1/series/${series15.id}").andExpect { status { isForbidden() } } mockMvc.get("/api/v1/series/${series.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/series?sort=metadata.titleSort") + mockMvc + .get("/api/v1/series?sort=metadata.titleSort") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -363,7 +368,8 @@ class SeriesControllerTest( mockMvc.get("/api/v1/series/${series16.id}").andExpect { status { isForbidden() } } mockMvc.get("/api/v1/series/${series18.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/series?sort=metadata.titleSort") + mockMvc + .get("/api/v1/series?sort=metadata.titleSort") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -421,7 +427,8 @@ class SeriesControllerTest( mockMvc.get("/api/v1/series/${seriesAdult.id}").andExpect { status { isForbidden() } } mockMvc.get("/api/v1/series/${series.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/series?sort=metadata.titleSort") + mockMvc + .get("/api/v1/series?sort=metadata.titleSort") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -479,7 +486,8 @@ class SeriesControllerTest( mockMvc.get("/api/v1/series/${seriesAdult.id}").andExpect { status { isOk() } } mockMvc.get("/api/v1/series/${series.id}").andExpect { status { isOk() } } - mockMvc.get("/api/v1/series?sort=metadata.titleSort") + mockMvc + .get("/api/v1/series?sort=metadata.titleSort") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -537,7 +545,8 @@ class SeriesControllerTest( mockMvc.get("/api/v1/series/${seriesAdult.id}").andExpect { status { isForbidden() } } mockMvc.get("/api/v1/series/${series.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/series?sort=metadata.titleSort") + mockMvc + .get("/api/v1/series?sort=metadata.titleSort") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(2) } @@ -562,7 +571,8 @@ class SeriesControllerTest( mockMvc.get("/api/v1/series/${seriesTeen16.id}").andExpect { status { isForbidden() } } - mockMvc.get("/api/v1/series") + mockMvc + .get("/api/v1/series") .andExpect { status { isOk() } jsonPath("$.content.length()") { value(0) } @@ -583,7 +593,8 @@ class SeriesControllerTest( } } - mockMvc.get("/api/v1/series/${createdSeries.id}") + mockMvc + .get("/api/v1/series/${createdSeries.id}") .andExpect { status { isForbidden() } } } @@ -598,7 +609,8 @@ class SeriesControllerTest( } } - mockMvc.get("/api/v1/series/${createdSeries.id}/thumbnail") + mockMvc + .get("/api/v1/series/${createdSeries.id}/thumbnail") .andExpect { status { isForbidden() } } } @@ -613,7 +625,8 @@ class SeriesControllerTest( } } - mockMvc.get("/api/v1/series/${createdSeries.id}/books") + mockMvc + .get("/api/v1/series/${createdSeries.id}/books") .andExpect { status { isForbidden() } } } @@ -628,7 +641,8 @@ class SeriesControllerTest( } } - mockMvc.get("/api/v1/series/${createdSeries.id}/file") + mockMvc + .get("/api/v1/series/${createdSeries.id}/file") .andExpect { status { isForbidden() } } } } @@ -646,7 +660,8 @@ class SeriesControllerTest( } } - mockMvc.get("/api/v1/series/${createdSeries.id}/file") + mockMvc + .get("/api/v1/series/${createdSeries.id}/file") .andExpect { status { isForbidden() } } } } @@ -664,7 +679,8 @@ class SeriesControllerTest( } } - mockMvc.get("/api/v1/series/${createdSeries.id}/thumbnail") + mockMvc + .get("/api/v1/series/${createdSeries.id}/thumbnail") .andExpect { status { isNotFound() } } } } @@ -687,16 +703,20 @@ class SeriesControllerTest( jsonPath("$.content[0].url") { value("") } } - mockMvc.get("/api/v1/series") + mockMvc + .get("/api/v1/series") .andExpect(validation) - mockMvc.get("/api/v1/series/latest") + mockMvc + .get("/api/v1/series/latest") .andExpect(validation) - mockMvc.get("/api/v1/series/new") + mockMvc + .get("/api/v1/series/new") .andExpect(validation) - mockMvc.get("/api/v1/series/${createdSeries.id}") + mockMvc + .get("/api/v1/series/${createdSeries.id}") .andExpect { status { isOk() } jsonPath("$.url") { value("") } @@ -719,16 +739,20 @@ class SeriesControllerTest( jsonPath("$.content[0].url") { value(Matchers.containsString("series")) } } - mockMvc.get("/api/v1/series") + mockMvc + .get("/api/v1/series") .andExpect(validation) - mockMvc.get("/api/v1/series/latest") + mockMvc + .get("/api/v1/series/latest") .andExpect(validation) - mockMvc.get("/api/v1/series/new") + mockMvc + .get("/api/v1/series/new") .andExpect(validation) - mockMvc.get("/api/v1/series/${createdSeries.id}") + mockMvc + .get("/api/v1/series/${createdSeries.id}") .andExpect { status { isOk() } jsonPath("$.url") { value(Matchers.containsString("series")) } @@ -741,12 +765,13 @@ class SeriesControllerTest( @Test @WithMockCustomUser fun `given non-admin user when updating metadata then raise forbidden`() { - mockMvc.patch("/api/v1/series/1/metadata") { - contentType = MediaType.APPLICATION_JSON - content = "{}" - }.andExpect { - status { isForbidden() } - } + mockMvc + .patch("/api/v1/series/1/metadata") { + contentType = MediaType.APPLICATION_JSON + content = "{}" + }.andExpect { + status { isForbidden() } + } } @ParameterizedTest @@ -761,12 +786,13 @@ class SeriesControllerTest( ) @WithMockCustomUser(roles = [ROLE_ADMIN]) fun `given invalid json when updating metadata then raise validation error`(jsonString: String) { - mockMvc.patch("/api/v1/series/1/metadata") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .patch("/api/v1/series/1/metadata") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -809,12 +835,13 @@ class SeriesControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/series/${createdSeries.id}/metadata") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/series/${createdSeries.id}/metadata") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } val updatedMetadata = seriesMetadataRepository.findById(createdSeries.id) with(updatedMetadata) { @@ -887,12 +914,13 @@ class SeriesControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/series/${createdSeries.id}/metadata") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v1/series/${createdSeries.id}/metadata") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } val updatedMetadata = seriesMetadataRepository.findById(createdSeries.id) with(updatedMetadata) { @@ -935,16 +963,19 @@ class SeriesControllerTest( val url = "/api/v1/series/${createdSeries.id}/thumbnail" val response = - mockMvc.get(url) - .andReturn().response + mockMvc + .get(url) + .andReturn() + .response - mockMvc.get(url) { - headers { - ifNoneMatch = listOf(response.getHeader(HttpHeaders.ETAG)!!) + mockMvc + .get(url) { + headers { + ifNoneMatch = listOf(response.getHeader(HttpHeaders.ETAG)!!) + } + }.andExpect { + status { isNotModified() } } - }.andExpect { - status { isNotModified() } - } } @Test @@ -982,13 +1013,14 @@ class SeriesControllerTest( } } - mockMvc.get(url) { - headers { - ifNoneMatch = listOf(response.getHeader(HttpHeaders.ETAG)!!) + mockMvc + .get(url) { + headers { + ifNoneMatch = listOf(response.getHeader(HttpHeaders.ETAG)!!) + } + }.andExpect { + status { isOk() } } - }.andExpect { - status { isOk() } - } } } @@ -1017,19 +1049,22 @@ class SeriesControllerTest( } } - mockMvc.post("/api/v1/series/${series.id}/read-progress") + mockMvc + .post("/api/v1/series/${series.id}/read-progress") .andExpect { status { isNoContent() } } - mockMvc.get("/api/v1/series/${series.id}") + mockMvc + .get("/api/v1/series/${series.id}") .andExpect { status { isOk() } jsonPath("$.booksUnreadCount") { value(0) } jsonPath("$.booksReadCount") { value(2) } } - mockMvc.get("/api/v1/series/${series.id}/books") + mockMvc + .get("/api/v1/series/${series.id}/books") .andExpect { status { isOk() } jsonPath("$.content[0].readProgress.completed") { value(true) } @@ -1061,24 +1096,28 @@ class SeriesControllerTest( } } - mockMvc.post("/api/v1/series/${series.id}/read-progress") + mockMvc + .post("/api/v1/series/${series.id}/read-progress") .andExpect { status { isNoContent() } } - mockMvc.delete("/api/v1/series/${series.id}/read-progress") + mockMvc + .delete("/api/v1/series/${series.id}/read-progress") .andExpect { status { isNoContent() } } - mockMvc.get("/api/v1/series/${series.id}") + mockMvc + .get("/api/v1/series/${series.id}") .andExpect { status { isOk() } jsonPath("$.booksUnreadCount") { value(2) } jsonPath("$.booksReadCount") { value(0) } } - mockMvc.get("/api/v1/series/${series.id}/books") + mockMvc + .get("/api/v1/series/${series.id}/books") .andExpect { status { isOk() } jsonPath("$.content[0].readProgress") { value(IsNull.nullValue()) } @@ -1127,7 +1166,8 @@ class SeriesControllerTest( content = """{"completed":true}""" } - mockMvc.get("/api/v1/series/${series.id}") + mockMvc + .get("/api/v1/series/${series.id}") .andExpect { status { isOk() } jsonPath("$.booksUnreadCount") { value(1) } @@ -1144,7 +1184,8 @@ class SeriesControllerTest( fun `given series with Unicode name when getting series file then attachment name is correct`() { val name = "アキラ" val tempFile = - Files.createTempFile(name, ".cbz") + Files + .createTempFile(name, ".cbz") .also { it.toFile().deleteOnExit() } val series = makeSeries(name = name, libraryId = library.id).let { series -> @@ -1155,7 +1196,8 @@ class SeriesControllerTest( series } - mockMvc.get("/api/v1/series/${series.id}/file") + mockMvc + .get("/api/v1/series/${series.id}/file") .andExpect { status { isOk() } header { string("Content-Disposition", Matchers.containsString(URLEncoder.encode(name, StandardCharsets.UTF_8.name()))) } @@ -1175,7 +1217,8 @@ class SeriesControllerTest( ) libraryContentLifecycle.scanRootFolder(library) - mockMvc.get("/api/v1/series/updated") + mockMvc + .get("/api/v1/series/updated") .andExpect { status { isOk() } jsonPath("$.content") { isEmpty() } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SettingsControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SettingsControllerTest.kt index 30701818..a8928155 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SettingsControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SettingsControllerTest.kt @@ -30,7 +30,8 @@ class SettingsControllerTest( @Test @WithAnonymousUser fun `given anonymous user when retrieving settings then returns unauthorized`() { - mockMvc.get("/api/v1/settings") + mockMvc + .get("/api/v1/settings") .andExpect { status { isUnauthorized() } } @@ -39,7 +40,8 @@ class SettingsControllerTest( @Test @WithMockCustomUser(roles = [ROLE_USER]) fun `given restricted user when retrieving settings then returns forbidden`() { - mockMvc.get("/api/v1/settings") + mockMvc + .get("/api/v1/settings") .andExpect { status { isForbidden() } } @@ -57,7 +59,8 @@ class SettingsControllerTest( komgaSettingsProvider.serverPort = 1234 komgaSettingsProvider.serverContextPath = "/example" - mockMvc.get("/api/v1/settings") + mockMvc + .get("/api/v1/settings") .andExpect { status { isOk() } jsonPath("deleteEmptyCollections") { value(true) } @@ -101,11 +104,11 @@ class SettingsControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/settings") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - } - .andExpect { + mockMvc + .patch("/api/v1/settings") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { status { isNoContent() } } @@ -146,11 +149,11 @@ class SettingsControllerTest( } """.trimIndent() - mockMvc.patch("/api/v1/settings") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - } - .andExpect { + mockMvc + .patch("/api/v1/settings") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { status { isNoContent() } } @@ -185,11 +188,11 @@ class SettingsControllerTest( ], ) fun `given admin user when updating with invalid settings then returns bad request`(jsonString: String) { - mockMvc.patch("/api/v1/settings") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - } - .andExpect { + mockMvc + .patch("/api/v1/settings") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { status { isBadRequest() } } } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerDemoTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerDemoTest.kt index a0bd28c2..d44bcb75 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerDemoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerDemoTest.kt @@ -22,18 +22,20 @@ class UserControllerDemoTest( // language=JSON val jsonString = """{"password":"new"}""" - mockMvc.patch("/api/v2/users/me/password") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isForbidden() } - } + mockMvc + .patch("/api/v2/users/me/password") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isForbidden() } + } } @Test @WithMockCustomUser fun `given demo profile is active when a user tries to retrieve own authentication activity then returns forbidden`() { - mockMvc.get("/api/v2/users/me/authentication-activity") + mockMvc + .get("/api/v2/users/me/authentication-activity") .andExpect { status { isForbidden() } } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerTest.kt index 8b566a60..f08fe56d 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerTest.kt @@ -66,7 +66,8 @@ class UserControllerTest( @AfterEach fun deleteUsers() { - userRepository.findAll() + userRepository + .findAll() .filterNot { it.email == admin.email } .forEach { userLifecycle.deleteUser(it) } } @@ -78,12 +79,13 @@ class UserControllerTest( // language=JSON val jsonString = """{"email":"$email","password":"password"}""" - mockMvc.post("/api/v2/users") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .post("/api/v2/users") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Nested @@ -102,12 +104,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -132,12 +135,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -164,12 +168,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -195,12 +200,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -226,12 +232,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -255,12 +262,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -295,12 +303,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -326,12 +335,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -358,12 +368,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -390,12 +401,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -430,12 +442,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.patch("/api/v2/users/${user.id}") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isNoContent() } - } + mockMvc + .patch("/api/v2/users/${user.id}") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isNoContent() } + } with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull @@ -464,15 +477,16 @@ class UserControllerTest( } """.trimIndent() - mockMvc.post("/api/v2/users/me/api-keys") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isOk() } - jsonPath("$.userId") { value(admin.id) } - jsonPath("$.key") { value(MatchesPattern(Regex("""[^*]+""").toPattern())) } - jsonPath("$.comment") { value("test api key") } - } + mockMvc + .post("/api/v2/users/me/api-keys") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isOk() } + jsonPath("$.userId") { value(admin.id) } + jsonPath("$.key") { value(MatchesPattern(Regex("""[^*]+""").toPattern())) } + jsonPath("$.comment") { value("test api key") } + } with(userRepository.findApiKeyByUserId(admin.id)) { assertThat(this).hasSize(1) @@ -482,7 +496,8 @@ class UserControllerTest( } } - mockMvc.get("/api/v2/users/me/api-keys") + mockMvc + .get("/api/v2/users/me/api-keys") .andExpect { status { isOk() } jsonPath("$.length()") { value(1) } @@ -503,12 +518,13 @@ class UserControllerTest( } """.trimIndent() - mockMvc.post("/api/v2/users/me/api-keys") { - contentType = MediaType.APPLICATION_JSON - content = jsonString - }.andExpect { - status { isBadRequest() } - } + mockMvc + .post("/api/v2/users/me/api-keys") { + contentType = MediaType.APPLICATION_JSON + content = jsonString + }.andExpect { + status { isBadRequest() } + } } @Test @@ -516,7 +532,8 @@ class UserControllerTest( fun `given user with api key when deleting API key then it is deleted`() { val apiKey = userLifecycle.createApiKey(admin, "test")!! - mockMvc.delete("/api/v2/users/me/api-keys/${apiKey.id}") + mockMvc + .delete("/api/v2/users/me/api-keys/${apiKey.id}") .andExpect { status { isNoContent() } } @@ -529,7 +546,8 @@ class UserControllerTest( fun `given user with api key when deleting different API key ID then returns bad request`() { userLifecycle.createApiKey(admin, "test")!! - mockMvc.delete("/api/v2/users/me/api-keys/abc123") + mockMvc + .delete("/api/v2/users/me/api-keys/abc123") .andExpect { status { isNotFound() } } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/mvc/ResourceNotFoundControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/mvc/ResourceNotFoundControllerTest.kt index 50b5c4e9..6b86238c 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/mvc/ResourceNotFoundControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/mvc/ResourceNotFoundControllerTest.kt @@ -16,7 +16,8 @@ class ResourceNotFoundControllerTest( @Test @WithMockCustomUser fun `when getting an unknown API endpoint then 404 is returned`() { - mockMvc.get("/api/v1/doesnotexist") + mockMvc + .get("/api/v1/doesnotexist") .andExpect { status { isNotFound() } } @@ -25,7 +26,8 @@ class ResourceNotFoundControllerTest( @Test @WithMockCustomUser fun `when getting an unknown OPDS endpoint then 404 is returned`() { - mockMvc.get("/opds/v2/doesnotexist") + mockMvc + .get("/opds/v2/doesnotexist") .andExpect { status { isNotFound() } } @@ -34,7 +36,8 @@ class ResourceNotFoundControllerTest( @Test @WithMockCustomUser fun `when getting an unknown SSE endpoint then 404 is returned`() { - mockMvc.get("/sse/v1/doesnotexist") + mockMvc + .get("/sse/v1/doesnotexist") .andExpect { status { isNotFound() } } @@ -43,7 +46,8 @@ class ResourceNotFoundControllerTest( @Test @WithMockCustomUser fun `when getting an unknown endpoint then it is forwarded to index`() { - mockMvc.get("/book/0DBTWY6S0KNX9") + mockMvc + .get("/book/0DBTWY6S0KNX9") .andExpect { status { isOk() } }