mirror of
https://github.com/gotson/komga.git
synced 2026-04-25 00:13:51 +02:00
style: apply ktlint to whole project
This commit is contained in:
parent
6b769884ed
commit
52ce9a575a
76 changed files with 537 additions and 500 deletions
|
|
@ -3,7 +3,7 @@
|
|||
<JetCodeStyleSettings>
|
||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||
<value>
|
||||
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
|
||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||
|
|
@ -17,16 +17,16 @@
|
|||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
|
||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
</component>
|
||||
|
|
@ -61,7 +61,6 @@ class TaskHandler(
|
|||
seriesRepository.findByIdOrNull(task.seriesId)?.let {
|
||||
metadataLifecycle.refreshMetadata(it)
|
||||
} ?: logger.warn { "Cannot execute task $task: Series does not exist" }
|
||||
|
||||
}
|
||||
}.also {
|
||||
logger.info { "Task $task executed in $it" }
|
||||
|
|
@ -71,5 +70,3 @@ class TaskHandler(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,10 +32,12 @@ class TaskReceiver(
|
|||
}
|
||||
|
||||
fun analyzeUnknownAndOutdatedBooks(library: Library) {
|
||||
bookRepository.findAllId(BookSearch(
|
||||
libraryIds = listOf(library.id),
|
||||
mediaStatus = listOf(Media.Status.UNKNOWN, Media.Status.OUTDATED)
|
||||
)).forEach {
|
||||
bookRepository.findAllId(
|
||||
BookSearch(
|
||||
libraryIds = listOf(library.id),
|
||||
mediaStatus = listOf(Media.Status.UNKNOWN, Media.Status.OUTDATED)
|
||||
)
|
||||
).forEach {
|
||||
submitTask(Task.AnalyzeBook(it))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,4 +15,3 @@ class BookSearchWithReadProgress(
|
|||
val tags: Collection<String>? = null,
|
||||
val readStatus: Collection<ReadStatus>? = null
|
||||
) : BookSearch(libraryIds, seriesIds, searchTerm, mediaStatus)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package org.gotson.komga.domain.persistence
|
|||
|
||||
import org.gotson.komga.domain.model.ReadProgress
|
||||
|
||||
|
||||
interface ReadProgressRepository {
|
||||
fun findAll(): Collection<ReadProgress>
|
||||
fun findByBookIdAndUserId(bookId: String, userId: String): ReadProgress?
|
||||
|
|
|
|||
|
|
@ -39,26 +39,30 @@ class FileSystemScanner(
|
|||
measureTime {
|
||||
val dirs = mutableListOf<Path>()
|
||||
|
||||
Files.walkFileTree(root, setOf(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, object : FileVisitor<Path> {
|
||||
override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes?): FileVisitResult {
|
||||
logger.trace { "preVisit: $dir" }
|
||||
if (!Files.isHidden(dir) && komgaProperties.librariesScanDirectoryExclusions.any { exclude ->
|
||||
Files.walkFileTree(
|
||||
root, setOf(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
|
||||
object : FileVisitor<Path> {
|
||||
override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes?): FileVisitResult {
|
||||
logger.trace { "preVisit: $dir" }
|
||||
if (!Files.isHidden(dir) && komgaProperties.librariesScanDirectoryExclusions.any { exclude ->
|
||||
dir.toString().contains(exclude, true)
|
||||
}) return FileVisitResult.SKIP_SUBTREE
|
||||
}
|
||||
) return FileVisitResult.SKIP_SUBTREE
|
||||
|
||||
dirs.add(dir)
|
||||
return FileVisitResult.CONTINUE
|
||||
dirs.add(dir)
|
||||
return FileVisitResult.CONTINUE
|
||||
}
|
||||
|
||||
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult = FileVisitResult.CONTINUE
|
||||
|
||||
override fun visitFileFailed(file: Path?, exc: IOException?): FileVisitResult {
|
||||
logger.warn { "Could not access: $file" }
|
||||
return FileVisitResult.SKIP_SUBTREE
|
||||
}
|
||||
|
||||
override fun postVisitDirectory(dir: Path?, exc: IOException?): FileVisitResult = FileVisitResult.CONTINUE
|
||||
}
|
||||
|
||||
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult = FileVisitResult.CONTINUE
|
||||
|
||||
override fun visitFileFailed(file: Path?, exc: IOException?): FileVisitResult {
|
||||
logger.warn { "Could not access: $file" }
|
||||
return FileVisitResult.SKIP_SUBTREE
|
||||
}
|
||||
|
||||
override fun postVisitDirectory(dir: Path?, exc: IOException?): FileVisitResult = FileVisitResult.CONTINUE
|
||||
})
|
||||
)
|
||||
|
||||
logger.debug { "Found directories: $dirs" }
|
||||
|
||||
|
|
@ -73,27 +77,27 @@ class FileSystemScanner(
|
|||
.filter { supportedExtensions.contains(FilenameUtils.getExtension(it.fileName.toString()).toLowerCase()) }
|
||||
.map {
|
||||
logger.debug { "Processing file: $it" }
|
||||
Book(
|
||||
name = FilenameUtils.getBaseName(it.fileName.toString()),
|
||||
url = it.toUri().toURL(),
|
||||
fileLastModified = it.getUpdatedTime(),
|
||||
fileSize = Files.readAttributes(it, BasicFileAttributes::class.java).size()
|
||||
)
|
||||
}.toList()
|
||||
}
|
||||
if (books.isNullOrEmpty()) {
|
||||
logger.debug { "No books in directory: $dir" }
|
||||
return@mapNotNull null
|
||||
}
|
||||
Series(
|
||||
name = dir.fileName.toString(),
|
||||
url = dir.toUri().toURL(),
|
||||
fileLastModified =
|
||||
if (forceDirectoryModifiedTime)
|
||||
maxOf(dir.getUpdatedTime(), books.map { it.fileLastModified }.maxOrNull()!!)
|
||||
else dir.getUpdatedTime()
|
||||
) to books
|
||||
}.toMap()
|
||||
Book(
|
||||
name = FilenameUtils.getBaseName(it.fileName.toString()),
|
||||
url = it.toUri().toURL(),
|
||||
fileLastModified = it.getUpdatedTime(),
|
||||
fileSize = Files.readAttributes(it, BasicFileAttributes::class.java).size()
|
||||
)
|
||||
}.toList()
|
||||
}
|
||||
if (books.isNullOrEmpty()) {
|
||||
logger.debug { "No books in directory: $dir" }
|
||||
return@mapNotNull null
|
||||
}
|
||||
Series(
|
||||
name = dir.fileName.toString(),
|
||||
url = dir.toUri().toURL(),
|
||||
fileLastModified =
|
||||
if (forceDirectoryModifiedTime)
|
||||
maxOf(dir.getUpdatedTime(), books.map { it.fileLastModified }.maxOrNull()!!)
|
||||
else dir.getUpdatedTime()
|
||||
) to books
|
||||
}.toMap()
|
||||
}.also {
|
||||
val countOfBooks = scannedSeries.values.sumBy { it.size }
|
||||
logger.info { "Scanned ${scannedSeries.size} series and $countOfBooks books in $it" }
|
||||
|
|
|
|||
|
|
@ -72,6 +72,4 @@ class KomgaUserLifecycle(
|
|||
it.expireNow()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,5 +109,4 @@ class LibraryScanner(
|
|||
}
|
||||
}.also { logger.info { "Library updated in $it" } }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,5 +42,4 @@ class MetadataApplier {
|
|||
genres = getIfNotLocked(genres, patch.genres, genresLock)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ class MetadataLifecycle(
|
|||
|
||||
// handle book metadata
|
||||
if ((provider is ComicInfoProvider && library.importComicInfoBook) ||
|
||||
(provider is EpubMetadataProvider && library.importEpubBook)) {
|
||||
(provider is EpubMetadataProvider && library.importEpubBook)
|
||||
) {
|
||||
patch?.let { bPatch ->
|
||||
bookMetadataRepository.findById(book.id).let {
|
||||
logger.debug { "Original metadata: $it" }
|
||||
|
|
@ -93,15 +94,16 @@ class MetadataLifecycle(
|
|||
}
|
||||
} else {
|
||||
logger.debug { "Adding book '${book.name}' to new readlist '$readList'" }
|
||||
readListLifecycle.addReadList(ReadList(
|
||||
name = readList.name,
|
||||
bookIds = mapOf((readList.number ?: 0) to book.id).toSortedMap()
|
||||
))
|
||||
readListLifecycle.addReadList(
|
||||
ReadList(
|
||||
name = readList.name,
|
||||
bookIds = mapOf((readList.number ?: 0) to book.id).toSortedMap()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +130,8 @@ class MetadataLifecycle(
|
|||
|
||||
// handle series metadata
|
||||
if ((provider is ComicInfoProvider && library.importComicInfoSeries) ||
|
||||
(provider is EpubMetadataProvider && library.importEpubSeries)) {
|
||||
(provider is EpubMetadataProvider && library.importEpubSeries)
|
||||
) {
|
||||
|
||||
val aggregatedPatch = SeriesMetadataPatch(
|
||||
title = patches.mostFrequent { it.title },
|
||||
|
|
@ -169,10 +172,12 @@ class MetadataLifecycle(
|
|||
}
|
||||
} else {
|
||||
logger.debug { "Adding series '${series.name}' to new collection '$collection'" }
|
||||
collectionLifecycle.addCollection(SeriesCollection(
|
||||
name = collection,
|
||||
seriesIds = listOf(series.id)
|
||||
))
|
||||
collectionLifecycle.addCollection(
|
||||
SeriesCollection(
|
||||
name = collection,
|
||||
seriesIds = listOf(series.id)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -195,4 +200,3 @@ class MetadataLifecycle(
|
|||
.maxByOrNull { it.value }?.key
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@ class DataSourcesConfiguration(
|
|||
@Bean("sqliteDataSource")
|
||||
@Primary
|
||||
fun sqliteDataSource(): DataSource =
|
||||
(DataSourceBuilder.create()
|
||||
.apply {
|
||||
driverClassName("org.sqlite.JDBC")
|
||||
url("jdbc:sqlite:${komgaProperties.database.file}?foreign_keys=on;")
|
||||
}.type(HikariDataSource::class.java)
|
||||
.build() as HikariDataSource)
|
||||
(
|
||||
DataSourceBuilder.create()
|
||||
.apply {
|
||||
driverClassName("org.sqlite.JDBC")
|
||||
url("jdbc:sqlite:${komgaProperties.database.file}?foreign_keys=on;")
|
||||
}.type(HikariDataSource::class.java)
|
||||
.build() as HikariDataSource
|
||||
)
|
||||
.apply { maximumPoolSize = 1 }
|
||||
|
||||
@Bean
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ class DatabaseMigration(
|
|||
jmsListenerEndpointRegistry.start()
|
||||
|
||||
logger.info { "Migration finished" }
|
||||
|
||||
} catch (e: Exception) {
|
||||
logger.error(e) { "Migration failed" }
|
||||
|
||||
|
|
@ -171,30 +170,37 @@ class DatabaseMigration(
|
|||
if (countBook > 0) {
|
||||
logger.info { "Found $countBook books with missing page numbers, marking them as to be re-analyzed" }
|
||||
|
||||
jdbc.update("""
|
||||
jdbc.update(
|
||||
"""
|
||||
update media set STATUS='UNKNOWN'
|
||||
where BOOK_ID in (
|
||||
select distinct BOOK_ID from media_page where number is null
|
||||
)""")
|
||||
)"""
|
||||
)
|
||||
jdbc.update("delete from media_page where number is null")
|
||||
jdbc.update("""
|
||||
jdbc.update(
|
||||
"""
|
||||
delete from media_page
|
||||
where BOOK_ID in (
|
||||
select distinct BOOK_ID from media_page where number is null
|
||||
)""")
|
||||
)"""
|
||||
)
|
||||
}
|
||||
|
||||
val invalidReadProgress = jdbc.query("""
|
||||
val invalidReadProgress = jdbc.query(
|
||||
"""
|
||||
select b.id as BOOK_ID, u.id as USER_ID, count(p.BOOK_ID)
|
||||
from read_progress p left join user u on p.user_id = u.id left join book b on p.book_id = b.id
|
||||
group by b.id, b.name, u.id, u.email
|
||||
having count(p.book_id) > 1
|
||||
""") { rs, _ -> Triple(rs.getLong(1), rs.getLong(2), rs.getLong(3)) }
|
||||
"""
|
||||
) { rs, _ -> Triple(rs.getLong(1), rs.getLong(2), rs.getLong(3)) }
|
||||
|
||||
if (invalidReadProgress.isNotEmpty()) {
|
||||
logger.info { "Found ${invalidReadProgress.size} invalid read progress, removing extra rows and keep one per (book,user)" }
|
||||
invalidReadProgress.forEach {
|
||||
jdbc.update("delete from read_progress where book_id = ? and user_id = ? and rownum() < ?",
|
||||
jdbc.update(
|
||||
"delete from read_progress where book_id = ? and user_id = ? and rownum() < ?",
|
||||
it.first, it.second, it.third
|
||||
)
|
||||
}
|
||||
|
|
@ -268,7 +274,6 @@ class DatabaseMigration(
|
|||
|
||||
return "insert into $table (${columns.joinToString()}) values (${quids.joinToString()})"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val excludeH2Url = listOf(":mem:", ":ssl:", ":tcp:", ":zip:")
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ import org.springframework.context.annotation.Profile
|
|||
@Profile("dev")
|
||||
@Configuration
|
||||
@ImportResource("classpath:h2server.xml")
|
||||
class DevelopmentConfiguration
|
||||
class DevelopmentConfiguration
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import javax.imageio.ImageIO
|
|||
import javax.imageio.spi.IIORegistry
|
||||
import javax.imageio.spi.ImageReaderSpi
|
||||
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
@Service
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import java.awt.image.BufferedImage
|
|||
import java.io.ByteArrayOutputStream
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
|
||||
@Service
|
||||
class MosaicGenerator {
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,12 @@ class ArtemisConfig : ArtemisConfigurationCustomizer {
|
|||
// default is 90, meaning the queue would block if disk is 90% full. Set it to 100 to avoid blocking.
|
||||
it.maxDiskUsage = 100
|
||||
// disable prefetch, ensures messages stay in the queue and last value can have desired effect
|
||||
it.addAddressesSetting(QUEUE_TASKS, AddressSettings().apply {
|
||||
defaultConsumerWindowSize = 0
|
||||
})
|
||||
it.addAddressesSetting(
|
||||
QUEUE_TASKS,
|
||||
AddressSettings().apply {
|
||||
defaultConsumerWindowSize = 0
|
||||
}
|
||||
)
|
||||
it.addQueueConfiguration(
|
||||
QueueConfiguration(QUEUE_TASKS)
|
||||
.setAddress(QUEUE_TASKS)
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ class BookDao(
|
|||
|
||||
val orderBy = pageable.sort.toOrderBy(sorts)
|
||||
|
||||
|
||||
val items = dsl.select(*b.fields())
|
||||
.from(b)
|
||||
.leftJoin(d).on(b.ID.eq(d.BOOK_ID))
|
||||
|
|
@ -93,7 +92,6 @@ class BookDao(
|
|||
)
|
||||
}
|
||||
|
||||
|
||||
override fun getLibraryId(bookId: String): String? =
|
||||
dsl.select(b.LIBRARY_ID)
|
||||
.from(b)
|
||||
|
|
@ -138,7 +136,6 @@ class BookDao(
|
|||
.fetch(0, String::class.java)
|
||||
}
|
||||
|
||||
|
||||
override fun insert(book: Book) {
|
||||
insertMany(listOf(book))
|
||||
}
|
||||
|
|
@ -226,7 +223,6 @@ class BookDao(
|
|||
|
||||
override fun count(): Long = dsl.fetchCount(b).toLong()
|
||||
|
||||
|
||||
private fun BookSearch.toCondition(): Condition {
|
||||
var c: Condition = DSL.trueCondition()
|
||||
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ class BookDtoDao(
|
|||
override fun findNextInSeries(bookId: String, userId: String): BookDto? =
|
||||
findSiblingSeries(bookId, userId, next = true)
|
||||
|
||||
|
||||
override fun findPreviousInReadList(
|
||||
readListId: String,
|
||||
bookId: String,
|
||||
|
|
@ -144,7 +143,6 @@ class BookDtoDao(
|
|||
): BookDto? =
|
||||
findSiblingReadList(readListId, bookId, userId, filterOnLibraryIds, next = true)
|
||||
|
||||
|
||||
override fun findOnDeck(libraryIds: Collection<String>, userId: String, pageable: Pageable): Page<BookDto> {
|
||||
val conditions = if (libraryIds.isEmpty()) DSL.trueCondition() else s.LIBRARY_ID.`in`(libraryIds)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import org.gotson.komga.jooq.Tables
|
|||
import org.gotson.komga.jooq.tables.records.BookMetadataAuthorRecord
|
||||
import org.gotson.komga.jooq.tables.records.BookMetadataRecord
|
||||
import org.jooq.DSLContext
|
||||
import org.jooq.impl.DSL
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
|
|
|
|||
|
|
@ -56,8 +56,7 @@ class KomgaUserDao(
|
|||
|
||||
override fun insert(user: KomgaUser) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
insertInto(u)
|
||||
.set(u.ID, user.id)
|
||||
.set(u.EMAIL, user.email)
|
||||
|
|
@ -80,8 +79,7 @@ class KomgaUserDao(
|
|||
|
||||
override fun update(user: KomgaUser) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
update(u)
|
||||
.set(u.EMAIL, user.email)
|
||||
.set(u.PASSWORD, user.password)
|
||||
|
|
@ -109,8 +107,7 @@ class KomgaUserDao(
|
|||
|
||||
override fun delete(userId: String) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(ul).where(ul.USER_ID.equal(userId)).execute()
|
||||
deleteFrom(u).where(u.ID.equal(userId)).execute()
|
||||
}
|
||||
|
|
@ -119,8 +116,7 @@ class KomgaUserDao(
|
|||
|
||||
override fun deleteAll() {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(ul).execute()
|
||||
deleteFrom(u).execute()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,7 @@ class LibraryDao(
|
|||
|
||||
override fun delete(libraryId: String) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(ul).where(ul.LIBRARY_ID.eq(libraryId)).execute()
|
||||
deleteFrom(l).where(l.ID.eq(libraryId)).execute()
|
||||
}
|
||||
|
|
@ -54,8 +53,7 @@ class LibraryDao(
|
|||
|
||||
override fun deleteAll() {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(ul).execute()
|
||||
deleteFrom(l).execute()
|
||||
}
|
||||
|
|
@ -99,7 +97,6 @@ class LibraryDao(
|
|||
|
||||
override fun count(): Long = dsl.fetchCount(l).toLong()
|
||||
|
||||
|
||||
private fun LibraryRecord.toDomain() =
|
||||
Library(
|
||||
name = name,
|
||||
|
|
|
|||
|
|
@ -130,8 +130,7 @@ class MediaDao(
|
|||
|
||||
override fun update(media: Media) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
update(m)
|
||||
.set(m.STATUS, media.status.toString())
|
||||
.set(m.MEDIA_TYPE, media.mediaType)
|
||||
|
|
@ -157,8 +156,7 @@ class MediaDao(
|
|||
|
||||
override fun delete(bookId: String) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(p).where(p.BOOK_ID.eq(bookId)).execute()
|
||||
deleteFrom(f).where(f.BOOK_ID.eq(bookId)).execute()
|
||||
deleteFrom(m).where(m.BOOK_ID.eq(bookId)).execute()
|
||||
|
|
@ -168,8 +166,7 @@ class MediaDao(
|
|||
|
||||
override fun deleteByBookIds(bookIds: Collection<String>) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(p).where(p.BOOK_ID.`in`(bookIds)).execute()
|
||||
deleteFrom(f).where(f.BOOK_ID.`in`(bookIds)).execute()
|
||||
deleteFrom(m).where(m.BOOK_ID.`in`(bookIds)).execute()
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ class ReadListDao(
|
|||
"name" to DSL.lower(rl.NAME)
|
||||
)
|
||||
|
||||
|
||||
override fun findByIdOrNull(readListId: String): ReadList? =
|
||||
selectBase()
|
||||
.where(rl.ID.eq(readListId))
|
||||
|
|
@ -141,7 +140,6 @@ class ReadListDao(
|
|||
rr.toDomain(bookIds)
|
||||
}
|
||||
|
||||
|
||||
override fun insert(readList: ReadList) {
|
||||
dsl.transaction { config ->
|
||||
config.dsl().insertInto(rl)
|
||||
|
|
@ -154,7 +152,6 @@ class ReadListDao(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun insertBooks(dsl: DSLContext, readList: ReadList) {
|
||||
readList.bookIds.map { (index, id) ->
|
||||
dsl.insertInto(rlb)
|
||||
|
|
@ -196,8 +193,7 @@ class ReadListDao(
|
|||
|
||||
override fun delete(readListId: String) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(rlb).where(rlb.READLIST_ID.eq(readListId)).execute()
|
||||
deleteFrom(rl).where(rl.ID.eq(readListId)).execute()
|
||||
}
|
||||
|
|
@ -206,8 +202,7 @@ class ReadListDao(
|
|||
|
||||
override fun deleteAll() {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(rlb).execute()
|
||||
deleteFrom(rl).execute()
|
||||
}
|
||||
|
|
@ -220,7 +215,6 @@ class ReadListDao(
|
|||
.where(rl.NAME.equalIgnoreCase(name))
|
||||
)
|
||||
|
||||
|
||||
private fun ReadlistRecord.toDomain(bookIds: SortedMap<Int, String>) =
|
||||
ReadList(
|
||||
name = name,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ class ReadProgressDao(
|
|||
.fetchInto(r)
|
||||
.map { it.toDomain() }
|
||||
|
||||
|
||||
override fun save(readProgress: ReadProgress) {
|
||||
dsl.insertInto(r, r.BOOK_ID, r.USER_ID, r.PAGE, r.COMPLETED)
|
||||
.values(readProgress.bookId, readProgress.userId, readProgress.page, readProgress.completed)
|
||||
|
|
@ -44,7 +43,6 @@ class ReadProgressDao(
|
|||
.execute()
|
||||
}
|
||||
|
||||
|
||||
override fun delete(bookId: String, userId: String) {
|
||||
dsl.deleteFrom(r)
|
||||
.where(r.BOOK_ID.eq(bookId).and(r.USER_ID.eq(userId)))
|
||||
|
|
@ -73,7 +71,6 @@ class ReadProgressDao(
|
|||
dsl.deleteFrom(r).execute()
|
||||
}
|
||||
|
||||
|
||||
private fun ReadProgressRecord.toDomain() =
|
||||
ReadProgress(
|
||||
bookId = bookId,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ class SeriesCollectionDao(
|
|||
"name" to DSL.lower(c.NAME)
|
||||
)
|
||||
|
||||
|
||||
override fun findByIdOrNull(collectionId: String): SeriesCollection? =
|
||||
selectBase()
|
||||
.where(c.ID.eq(collectionId))
|
||||
|
|
@ -152,7 +151,6 @@ class SeriesCollectionDao(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun insertSeries(dsl: DSLContext, collection: SeriesCollection) {
|
||||
collection.seriesIds.forEachIndexed { index, id ->
|
||||
dsl.insertInto(cs)
|
||||
|
|
@ -195,8 +193,7 @@ class SeriesCollectionDao(
|
|||
|
||||
override fun delete(collectionId: String) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(cs).where(cs.COLLECTION_ID.eq(collectionId)).execute()
|
||||
deleteFrom(c).where(c.ID.eq(collectionId)).execute()
|
||||
}
|
||||
|
|
@ -205,8 +202,7 @@ class SeriesCollectionDao(
|
|||
|
||||
override fun deleteAll() {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(cs).execute()
|
||||
deleteFrom(c).execute()
|
||||
}
|
||||
|
|
@ -219,7 +215,6 @@ class SeriesCollectionDao(
|
|||
.where(c.NAME.equalIgnoreCase(name))
|
||||
)
|
||||
|
||||
|
||||
private fun CollectionRecord.toDomain(seriesIds: List<String>) =
|
||||
SeriesCollection(
|
||||
name = name,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ class SeriesDao(
|
|||
private val d = Tables.SERIES_METADATA
|
||||
private val cs = Tables.COLLECTION_SERIES
|
||||
|
||||
|
||||
override fun findAll(): Collection<Series> =
|
||||
dsl.selectFrom(s)
|
||||
.fetchInto(s)
|
||||
|
|
@ -52,14 +51,12 @@ class SeriesDao(
|
|||
.fetchOneInto(s)
|
||||
?.toDomain()
|
||||
|
||||
|
||||
override fun getLibraryId(seriesId: String): String? =
|
||||
dsl.select(s.LIBRARY_ID)
|
||||
.from(s)
|
||||
.where(s.ID.eq(seriesId))
|
||||
.fetchOne(0, String::class.java)
|
||||
|
||||
|
||||
override fun findAll(search: SeriesSearch): Collection<Series> {
|
||||
val conditions = search.toCondition()
|
||||
|
||||
|
|
@ -72,7 +69,6 @@ class SeriesDao(
|
|||
.map { it.toDomain() }
|
||||
}
|
||||
|
||||
|
||||
override fun insert(series: Series) {
|
||||
dsl.insertInto(s)
|
||||
.set(s.ID, series.id)
|
||||
|
|
@ -96,8 +92,7 @@ class SeriesDao(
|
|||
|
||||
override fun delete(seriesId: String) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(s).where(s.ID.eq(seriesId)).execute()
|
||||
}
|
||||
}
|
||||
|
|
@ -105,8 +100,7 @@ class SeriesDao(
|
|||
|
||||
override fun deleteAll() {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(s).execute()
|
||||
}
|
||||
}
|
||||
|
|
@ -114,8 +108,7 @@ class SeriesDao(
|
|||
|
||||
override fun deleteAll(seriesIds: Collection<String>) {
|
||||
dsl.transaction { config ->
|
||||
with(config.dsl())
|
||||
{
|
||||
with(config.dsl()) {
|
||||
deleteFrom(s).where(s.ID.`in`(seriesIds)).execute()
|
||||
}
|
||||
}
|
||||
|
|
@ -123,7 +116,6 @@ class SeriesDao(
|
|||
|
||||
override fun count(): Long = dsl.fetchCount(s).toLong()
|
||||
|
||||
|
||||
private fun SeriesSearch.toCondition(): Condition {
|
||||
var c: Condition = DSL.trueCondition()
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ class SeriesDtoDao(
|
|||
.fetchAndMap(userId)
|
||||
.firstOrNull()
|
||||
|
||||
|
||||
private fun selectBase(
|
||||
userId: String,
|
||||
joinConditions: JoinConditions = JoinConditions()
|
||||
|
|
@ -273,5 +272,3 @@ class SeriesDtoDao(
|
|||
tagsLock = tagsLock
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import org.gotson.komga.domain.persistence.SeriesMetadataRepository
|
|||
import org.gotson.komga.jooq.Tables
|
||||
import org.gotson.komga.jooq.tables.records.SeriesMetadataRecord
|
||||
import org.jooq.DSLContext
|
||||
import org.jooq.impl.DSL.lower
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
|
|
@ -161,7 +160,6 @@ class SeriesMetadataDao(
|
|||
|
||||
override fun count(): Long = dsl.fetchCount(d).toLong()
|
||||
|
||||
|
||||
private fun SeriesMetadataRecord.toDomain(genres: Set<String>, tags: Set<String>) =
|
||||
SeriesMetadata(
|
||||
status = SeriesMetadata.Status.valueOf(status),
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ class EpubExtractor(
|
|||
.flatMap { pagePath ->
|
||||
val doc = zip.getInputStream(zip.getEntry(pagePath.separatorsToUnix())).use { Jsoup.parse(it, null, "") }
|
||||
doc.getElementsByTag("img")
|
||||
.map { it.attr("src") } //get the src, which can be a relative path
|
||||
.map { pagePath.parentOrEmpty().resolve(it).normalize() } //resolve it against the page folder
|
||||
.map { it.attr("src") } // get the src, which can be a relative path
|
||||
.map { pagePath.parentOrEmpty().resolve(it).normalize() } // resolve it against the page folder
|
||||
}
|
||||
|
||||
return images.map { image ->
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ class ComicInfoProvider(
|
|||
readLists.addAll(arcs.map { BookMetadataPatch.ReadListEntry(it) })
|
||||
}
|
||||
|
||||
|
||||
return BookMetadataPatch(
|
||||
title = comicInfo.title?.ifBlank { null },
|
||||
summary = comicInfo.summary?.ifBlank { null },
|
||||
|
|
|
|||
|
|
@ -116,5 +116,4 @@ class ComicInfo {
|
|||
|
||||
@JsonProperty(value = "AgeRating", defaultValue = "Unknown")
|
||||
var ageRating: AgeRating? = null
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,5 +109,4 @@ class EpubMetadataProvider(
|
|||
null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,5 +65,4 @@ class LocalArtworkProvider(
|
|||
}.toList()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class SecurityConfiguration(
|
|||
.and()
|
||||
.headers {
|
||||
it.frameOptions().sameOrigin()
|
||||
it.cacheControl().disable() //headers are set in WebMvcConfiguration
|
||||
it.cacheControl().disable() // headers are set in WebMvcConfiguration
|
||||
}
|
||||
|
||||
.httpBasic()
|
||||
|
|
|
|||
|
|
@ -40,9 +40,7 @@ annotation class PageableWithoutSortAsQueryParam
|
|||
),
|
||||
Parameter(
|
||||
description = "Sorting criteria in the format: property(,asc|desc). Default sort order is ascending. Multiple sort criteria are supported.",
|
||||
`in` = ParameterIn.QUERY
|
||||
, name = "sort"
|
||||
, content = [Content(array = ArraySchema(schema = Schema(type = "string")))]
|
||||
`in` = ParameterIn.QUERY, name = "sort", content = [Content(array = ArraySchema(schema = Schema(type = "string")))]
|
||||
)
|
||||
)
|
||||
annotation class PageableAsQueryParam
|
||||
|
|
|
|||
|
|
@ -15,20 +15,29 @@ class SwaggerConfiguration {
|
|||
@Bean
|
||||
fun openApi(): OpenAPI =
|
||||
OpenAPI()
|
||||
.info(Info()
|
||||
.title("Komga API")
|
||||
.version("v1.0")
|
||||
.description("""
|
||||
.info(
|
||||
Info()
|
||||
.title("Komga API")
|
||||
.version("v1.0")
|
||||
.description(
|
||||
"""
|
||||
Komga offers 2 APIs: REST and OPDS.
|
||||
|
||||
Both APIs are secured using HTTP Basic Authentication.
|
||||
""".trimIndent())
|
||||
.license(License().name("MIT").url("https://github.com/gotson/komga/blob/master/LICENSE")))
|
||||
.externalDocs(ExternalDocumentation()
|
||||
.description("Komga documentation")
|
||||
.url("https://komga.org"))
|
||||
.components(Components()
|
||||
.addSecuritySchemes(
|
||||
"basicAuth",
|
||||
SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic")))
|
||||
""".trimIndent()
|
||||
)
|
||||
.license(License().name("MIT").url("https://github.com/gotson/komga/blob/master/LICENSE"))
|
||||
)
|
||||
.externalDocs(
|
||||
ExternalDocumentation()
|
||||
.description("Komga documentation")
|
||||
.url("https://komga.org")
|
||||
)
|
||||
.components(
|
||||
Components()
|
||||
.addSecuritySchemes(
|
||||
"basicAuth",
|
||||
SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import javax.validation.ConstraintValidator
|
|||
import javax.validation.ConstraintValidatorContext
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
@Constraint(validatedBy = [BCP47Validator::class])
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.ANNOTATION_CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
package org.gotson.komga.infrastructure.validation
|
||||
|
||||
import com.ibm.icu.util.ULocale
|
||||
import javax.validation.Constraint
|
||||
import javax.validation.ConstraintValidator
|
||||
import javax.validation.ConstraintValidatorContext
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
@Constraint(validatedBy = [BlankValidator::class])
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.ANNOTATION_CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@ package org.gotson.komga.infrastructure.validation
|
|||
import org.hibernate.validator.constraints.CompositionType
|
||||
import org.hibernate.validator.constraints.ConstraintComposition
|
||||
import javax.validation.Constraint
|
||||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.Null
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
@ConstraintComposition(CompositionType.OR)
|
||||
@Constraint(validatedBy = [])
|
||||
@Null
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import javax.validation.constraints.NotBlank
|
|||
import javax.validation.constraints.Null
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
@ConstraintComposition(CompositionType.OR)
|
||||
@Constraint(validatedBy = [])
|
||||
@Null
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import javax.validation.constraints.NotEmpty
|
|||
import javax.validation.constraints.Null
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
@ConstraintComposition(CompositionType.OR)
|
||||
@Constraint(validatedBy = [])
|
||||
@Null
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import org.springframework.context.annotation.Bean
|
|||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.web.filter.ShallowEtagHeaderFilter
|
||||
|
||||
|
||||
@Configuration
|
||||
class EtagFilterConfiguration {
|
||||
@Bean
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
|
|||
import org.springframework.web.servlet.mvc.WebContentInterceptor
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
@Configuration
|
||||
class WebMvcConfiguration : WebMvcConfigurer {
|
||||
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
|
||||
|
|
|
|||
|
|
@ -195,7 +195,6 @@ class OpdsController(
|
|||
.sortedBy { it.metadata.titleSort.toLowerCase() }
|
||||
.map { it.toOpdsEntry() }
|
||||
|
||||
|
||||
return OpdsFeedNavigation(
|
||||
id = ID_SERIES_ALL,
|
||||
title = "All series",
|
||||
|
|
@ -343,7 +342,6 @@ class OpdsController(
|
|||
if (principal.user.sharedAllLibraries) referentialRepository.findAllPublishers()
|
||||
else referentialRepository.findAllPublishersByLibraries(principal.user.sharedLibrariesIds)
|
||||
|
||||
|
||||
return OpdsFeedNavigation(
|
||||
id = ID_PUBLISHERS_ALL,
|
||||
title = "All publishers",
|
||||
|
|
@ -375,10 +373,12 @@ class OpdsController(
|
|||
seriesRepository.findByIdOrNull(id)?.let { series ->
|
||||
if (!principal.user.canAccessSeries(series)) throw ResponseStatusException(HttpStatus.FORBIDDEN)
|
||||
|
||||
val books = bookRepository.findAll(BookSearch(
|
||||
seriesIds = listOf(id),
|
||||
mediaStatus = setOf(Media.Status.READY)
|
||||
))
|
||||
val books = bookRepository.findAll(
|
||||
BookSearch(
|
||||
seriesIds = listOf(id),
|
||||
mediaStatus = setOf(Media.Status.READY)
|
||||
)
|
||||
)
|
||||
val metadata = seriesMetadataRepository.findById(series.id)
|
||||
|
||||
val entries = books
|
||||
|
|
@ -485,7 +485,6 @@ class OpdsController(
|
|||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
}
|
||||
|
||||
|
||||
private fun SeriesWithInfo.toOpdsEntry(prepend: Int? = null): OpdsEntryNavigation {
|
||||
val pre = prepend?.let { decimalFormat.format(it) + " - " } ?: ""
|
||||
return OpdsEntryNavigation(
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ class BookController(
|
|||
.map { it.restrictUrl(!principal.user.roleAdmin) }
|
||||
}
|
||||
|
||||
|
||||
@Operation(description = "Return newly added or updated books.")
|
||||
@PageableWithoutSortAsQueryParam
|
||||
@GetMapping("api/v1/books/latest")
|
||||
|
|
@ -161,7 +160,6 @@ class BookController(
|
|||
).map { it.restrictUrl(!principal.user.roleAdmin) }
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("api/v1/books/{bookId}")
|
||||
fun getOneBook(
|
||||
@AuthenticationPrincipal principal: KomgaPrincipal,
|
||||
|
|
@ -200,7 +198,6 @@ class BookController(
|
|||
?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("api/v1/books/{bookId}/readlists")
|
||||
fun getAllReadListsByBook(
|
||||
@AuthenticationPrincipal principal: KomgaPrincipal,
|
||||
|
|
@ -214,12 +211,14 @@ class BookController(
|
|||
.map { it.toDto() }
|
||||
}
|
||||
|
||||
|
||||
@ApiResponse(content = [Content(schema = Schema(type = "string", format = "binary"))])
|
||||
@GetMapping(value = [
|
||||
"api/v1/books/{bookId}/thumbnail",
|
||||
"opds/v1.2/books/{bookId}/thumbnail"
|
||||
], produces = [MediaType.IMAGE_JPEG_VALUE])
|
||||
@GetMapping(
|
||||
value = [
|
||||
"api/v1/books/{bookId}/thumbnail",
|
||||
"opds/v1.2/books/{bookId}/thumbnail"
|
||||
],
|
||||
produces = [MediaType.IMAGE_JPEG_VALUE]
|
||||
)
|
||||
fun getBookThumbnail(
|
||||
@AuthenticationPrincipal principal: KomgaPrincipal,
|
||||
@PathVariable bookId: String
|
||||
|
|
@ -232,11 +231,14 @@ class BookController(
|
|||
}
|
||||
|
||||
@Operation(description = "Download the book file.")
|
||||
@GetMapping(value = [
|
||||
"api/v1/books/{bookId}/file",
|
||||
"api/v1/books/{bookId}/file/*",
|
||||
"opds/v1.2/books/{bookId}/file/*"
|
||||
], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE])
|
||||
@GetMapping(
|
||||
value = [
|
||||
"api/v1/books/{bookId}/file",
|
||||
"api/v1/books/{bookId}/file/*",
|
||||
"opds/v1.2/books/{bookId}/file/*"
|
||||
],
|
||||
produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]
|
||||
)
|
||||
@PreAuthorize("hasRole('$ROLE_FILE_DOWNLOAD')")
|
||||
fun getBookFile(
|
||||
@AuthenticationPrincipal principal: KomgaPrincipal,
|
||||
|
|
@ -255,11 +257,13 @@ class BookController(
|
|||
}
|
||||
}
|
||||
ResponseEntity.ok()
|
||||
.headers(HttpHeaders().apply {
|
||||
contentDisposition = ContentDisposition.builder("attachment")
|
||||
.filename(book.fileName())
|
||||
.build()
|
||||
})
|
||||
.headers(
|
||||
HttpHeaders().apply {
|
||||
contentDisposition = ContentDisposition.builder("attachment")
|
||||
.filename(book.fileName())
|
||||
.build()
|
||||
}
|
||||
)
|
||||
.contentType(getMediaTypeOrDefault(media.mediaType))
|
||||
.contentLength(this.contentLength())
|
||||
.body(stream)
|
||||
|
|
@ -270,7 +274,6 @@ class BookController(
|
|||
}
|
||||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
|
||||
|
||||
@GetMapping("api/v1/books/{bookId}/pages")
|
||||
fun getBookPages(
|
||||
@AuthenticationPrincipal principal: KomgaPrincipal,
|
||||
|
|
@ -291,14 +294,21 @@ class BookController(
|
|||
}
|
||||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
|
||||
@ApiResponse(content = [Content(
|
||||
mediaType = "image/*",
|
||||
schema = Schema(type = "string", format = "binary")
|
||||
)])
|
||||
@GetMapping(value = [
|
||||
"api/v1/books/{bookId}/pages/{pageNumber}",
|
||||
"opds/v1.2/books/{bookId}/pages/{pageNumber}"
|
||||
], produces = [MediaType.ALL_VALUE])
|
||||
@ApiResponse(
|
||||
content = [
|
||||
Content(
|
||||
mediaType = "image/*",
|
||||
schema = Schema(type = "string", format = "binary")
|
||||
)
|
||||
]
|
||||
)
|
||||
@GetMapping(
|
||||
value = [
|
||||
"api/v1/books/{bookId}/pages/{pageNumber}",
|
||||
"opds/v1.2/books/{bookId}/pages/{pageNumber}"
|
||||
],
|
||||
produces = [MediaType.ALL_VALUE]
|
||||
)
|
||||
@PreAuthorize("hasRole('$ROLE_PAGE_STREAMING')")
|
||||
fun getBookPage(
|
||||
@AuthenticationPrincipal principal: KomgaPrincipal,
|
||||
|
|
@ -430,8 +440,8 @@ class BookController(
|
|||
if (authors != null) authors!!.map { Author(it.name ?: "", it.role ?: "") } else emptyList()
|
||||
} else existing.authors,
|
||||
authorsLock = authorsLock ?: existing.authorsLock,
|
||||
tags = if(isSet("tags")) {
|
||||
if(tags != null) tags!! else emptySet()
|
||||
tags = if (isSet("tags")) {
|
||||
if (tags != null) tags!! else emptySet()
|
||||
} else existing.tags,
|
||||
tagsLock = tagsLock ?: existing.tagsLock
|
||||
)
|
||||
|
|
@ -480,7 +490,6 @@ class BookController(
|
|||
private fun getBookLastModified(media: Media) =
|
||||
media.lastModifiedDate.toInstant(ZoneOffset.UTC).toEpochMilli()
|
||||
|
||||
|
||||
private fun getMediaTypeOrDefault(mediaTypeString: String?): MediaType {
|
||||
mediaTypeString?.let {
|
||||
try {
|
||||
|
|
@ -491,4 +500,3 @@ class BookController(
|
|||
return MediaType.APPLICATION_OCTET_STREAM
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ class ReadListController(
|
|||
@PathVariable id: String,
|
||||
@PathVariable bookId: String
|
||||
): BookDto =
|
||||
readListRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null))?.let { readList ->
|
||||
readListRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null))?.let {
|
||||
bookDtoRepository.findPreviousInReadList(
|
||||
id,
|
||||
bookId,
|
||||
|
|
@ -217,7 +217,7 @@ class ReadListController(
|
|||
@PathVariable id: String,
|
||||
@PathVariable bookId: String
|
||||
): BookDto =
|
||||
readListRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null))?.let { readList ->
|
||||
readListRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null))?.let {
|
||||
bookDtoRepository.findNextInReadList(
|
||||
id,
|
||||
bookId,
|
||||
|
|
@ -227,4 +227,3 @@ class ReadListController(
|
|||
?.restrictUrl(!principal.user.roleAdmin)
|
||||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import org.springframework.web.bind.annotation.RequestMapping
|
|||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("api/v1", produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
class ReferentialController(
|
||||
|
|
|
|||
|
|
@ -110,11 +110,13 @@ class SeriesCollectionController(
|
|||
@Valid @RequestBody 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)
|
||||
}
|
||||
|
|
@ -195,4 +197,3 @@ class SeriesCollectionController(
|
|||
.map { it.restrictUrl(!principal.user.roleAdmin) }
|
||||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -127,4 +127,3 @@ class UserController(
|
|||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,4 +72,3 @@ data class ReadProgressDto(
|
|||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
val lastModified: LocalDateTime
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
package org.gotson.komga.interfaces.rest.dto
|
||||
|
||||
import org.gotson.komga.domain.model.SeriesMetadata
|
||||
import org.gotson.komga.infrastructure.validation.NullOrNotBlank
|
||||
import java.time.LocalDate
|
||||
import javax.validation.Valid
|
||||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.PositiveOrZero
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class BookMetadataUpdateDto {
|
||||
|
|
@ -32,23 +30,23 @@ class BookMetadataUpdateDto {
|
|||
|
||||
var releaseDate: LocalDate?
|
||||
by Delegates.observable<LocalDate?>(null) { prop, _, _ ->
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
|
||||
var releaseDateLock: Boolean? = null
|
||||
|
||||
@get:Valid
|
||||
var authors: List<AuthorUpdateDto>?
|
||||
by Delegates.observable<List<AuthorUpdateDto>?>(null) { prop, _, _ ->
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
|
||||
var authorsLock: Boolean? = null
|
||||
|
||||
var tags: Set<String>?
|
||||
by Delegates.observable<Set<String>?>(null) { prop, _, _ ->
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
|
||||
var tagsLock: Boolean? = null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package org.gotson.komga.interfaces.rest.dto
|
|||
import org.gotson.komga.domain.model.SeriesMetadata
|
||||
import org.gotson.komga.infrastructure.validation.NullOrBlankOrBCP47
|
||||
import org.gotson.komga.infrastructure.validation.NullOrNotBlank
|
||||
import javax.validation.Valid
|
||||
import javax.validation.constraints.PositiveOrZero
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
|
@ -35,16 +34,16 @@ class SeriesMetadataUpdateDto {
|
|||
|
||||
var readingDirection: SeriesMetadata.ReadingDirection?
|
||||
by Delegates.observable<SeriesMetadata.ReadingDirection?>(null) { prop, _, _ ->
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
|
||||
var readingDirectionLock: Boolean? = null
|
||||
|
||||
@get:PositiveOrZero
|
||||
var ageRating: Int?
|
||||
by Delegates.observable<Int?>(null) { prop, _, _ ->
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
|
||||
var ageRatingLock: Boolean? = null
|
||||
|
||||
|
|
@ -55,15 +54,15 @@ class SeriesMetadataUpdateDto {
|
|||
|
||||
var genres: Set<String>?
|
||||
by Delegates.observable<Set<String>?>(null) { prop, _, _ ->
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
|
||||
var genresLock: Boolean? = null
|
||||
|
||||
var tags: Set<String>?
|
||||
by Delegates.observable<Set<String>?>(null) { prop, _, _ ->
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
isSet[prop.name] = true
|
||||
}
|
||||
|
||||
var tagsLock: Boolean? = null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension
|
|||
|
||||
@ExtendWith(SpringExtension::class)
|
||||
@SpringBootTest
|
||||
class AutowiringTriggerTest {
|
||||
class AutowiringTest {
|
||||
|
||||
@Test
|
||||
fun `Application loads properly with test properties`() = Unit
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_JAV
|
|||
import com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_JODATIME
|
||||
import org.gotson.komga.Application
|
||||
|
||||
|
||||
@AnalyzeClasses(packagesOf = [Application::class])
|
||||
class CodingRulesTest {
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes
|
|||
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses
|
||||
import org.gotson.komga.Application
|
||||
|
||||
|
||||
@AnalyzeClasses(packagesOf = [Application::class], importOptions = [ImportOption.DoNotIncludeTests::class])
|
||||
class DomainDrivenDesignRulesTest {
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import com.tngtech.archunit.lang.ArchRule
|
|||
import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices
|
||||
import org.gotson.komga.Application
|
||||
|
||||
|
||||
@AnalyzeClasses(packagesOf = [Application::class], importOptions = [ImportOption.DoNotIncludeTests::class])
|
||||
class SlicesIsolationRulesTest {
|
||||
@ArchTest
|
||||
|
|
|
|||
|
|
@ -32,9 +32,11 @@ class BookAnalyzerTest(
|
|||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = [
|
||||
"rar4-solid.rar", "rar4-encrypted.rar"
|
||||
])
|
||||
@ValueSource(
|
||||
strings = [
|
||||
"rar4-solid.rar", "rar4-encrypted.rar"
|
||||
]
|
||||
)
|
||||
fun `given rar4 solid or encrypted archive when analyzing then media status is UNSUPPORTED`(fileName: String) {
|
||||
val file = ClassPathResource("archives/rar4-solid.rar")
|
||||
val book = Book("book", file.url, LocalDateTime.now())
|
||||
|
|
@ -46,9 +48,11 @@ class BookAnalyzerTest(
|
|||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = [
|
||||
"rar5.rar", "rar5-solid.rar", "rar5-encrypted.rar"
|
||||
])
|
||||
@ValueSource(
|
||||
strings = [
|
||||
"rar5.rar", "rar5-solid.rar", "rar5-encrypted.rar"
|
||||
]
|
||||
)
|
||||
fun `given rar5 archive when analyzing then media status is UNSUPPORTED`(fileName: String) {
|
||||
val file = ClassPathResource("archives/$fileName")
|
||||
val book = Book("book", file.url, LocalDateTime.now())
|
||||
|
|
@ -60,9 +64,11 @@ class BookAnalyzerTest(
|
|||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = [
|
||||
"7zip.7z", "7zip-encrypted.7z"
|
||||
])
|
||||
@ValueSource(
|
||||
strings = [
|
||||
"7zip.7z", "7zip-encrypted.7z"
|
||||
]
|
||||
)
|
||||
fun `given 7zip archive when analyzing then media status is UNSUPPORTED`(fileName: String) {
|
||||
val file = ClassPathResource("archives/$fileName")
|
||||
val book = Book("book", file.url, LocalDateTime.now())
|
||||
|
|
@ -74,9 +80,11 @@ class BookAnalyzerTest(
|
|||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = [
|
||||
"zip.zip", "zip-bzip2.zip", "zip-copy.zip", "zip-deflate64.zip", "zip-lzma.zip", "zip-ppmd.zip"
|
||||
])
|
||||
@ValueSource(
|
||||
strings = [
|
||||
"zip.zip", "zip-bzip2.zip", "zip-copy.zip", "zip-deflate64.zip", "zip-lzma.zip", "zip-ppmd.zip"
|
||||
]
|
||||
)
|
||||
fun `given zip archive when analyzing then media status is READY`(fileName: String) {
|
||||
val file = ClassPathResource("archives/$fileName")
|
||||
val book = Book("book", file.url, LocalDateTime.now())
|
||||
|
|
|
|||
|
|
@ -76,10 +76,12 @@ class BookLifecycleTest(
|
|||
|
||||
val book = bookRepository.findAll().first()
|
||||
mediaRepository.findById(book.id).let { media ->
|
||||
mediaRepository.update(media.copy(
|
||||
status = Media.Status.OUTDATED,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
))
|
||||
mediaRepository.update(
|
||||
media.copy(
|
||||
status = Media.Status.OUTDATED,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
bookLifecycle.markReadProgressCompleted(book.id, user1)
|
||||
|
|
@ -107,10 +109,12 @@ class BookLifecycleTest(
|
|||
|
||||
val book = bookRepository.findAll().first()
|
||||
mediaRepository.findById(book.id).let { media ->
|
||||
mediaRepository.update(media.copy(
|
||||
status = Media.Status.OUTDATED,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
))
|
||||
mediaRepository.update(
|
||||
media.copy(
|
||||
status = Media.Status.OUTDATED,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
bookLifecycle.markReadProgressCompleted(book.id, user1)
|
||||
|
|
|
|||
|
|
@ -219,7 +219,6 @@ class LibraryScannerTest(
|
|||
assertThat(media.pages).hasSize(2)
|
||||
assertThat(media.pages.map { it.fileName }).containsExactly("1.jpg", "2.jpg")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -256,7 +255,6 @@ class LibraryScannerTest(
|
|||
assertThat(media.pages).hasSize(2)
|
||||
assertThat(media.pages.map { it.fileName }).containsExactly("1.jpg", "2.jpg")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ class BookDaoTest(
|
|||
libraryRepository.deleteAll()
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `given a book when inserting then it is persisted`() {
|
||||
val now = LocalDateTime.now()
|
||||
|
|
@ -190,7 +189,6 @@ class BookDaoTest(
|
|||
assertThat(bookDao.count()).isEqualTo(0)
|
||||
}
|
||||
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
// @Test
|
||||
|
|
|
|||
|
|
@ -68,10 +68,12 @@ class BookDtoDaoTest(
|
|||
}
|
||||
|
||||
private fun setupBooks() {
|
||||
seriesLifecycle.addBooks(series,
|
||||
seriesLifecycle.addBooks(
|
||||
series,
|
||||
(1..3).map {
|
||||
makeBook("$it", seriesId = series.id, libraryId = library.id)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
val books = bookRepository.findAll().sortedBy { it.name }
|
||||
books.elementAt(0).let { readProgressRepository.save(ReadProgress(it.id, user.id, 5, false)) }
|
||||
|
|
@ -241,10 +243,12 @@ class BookDtoDaoTest(
|
|||
@Test
|
||||
fun `given series with only unread books when searching for on deck then no books are returned`() {
|
||||
// given
|
||||
seriesLifecycle.addBooks(series,
|
||||
seriesLifecycle.addBooks(
|
||||
series,
|
||||
(1..3).map {
|
||||
makeBook("$it", seriesId = series.id, libraryId = library.id)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
// when
|
||||
val found = bookDtoDao.findOnDeck(
|
||||
|
|
@ -260,10 +264,12 @@ class BookDtoDaoTest(
|
|||
@Test
|
||||
fun `given series with some unread books when searching for on deck then first unread book of series is returned`() {
|
||||
// given
|
||||
seriesLifecycle.addBooks(series,
|
||||
seriesLifecycle.addBooks(
|
||||
series,
|
||||
(1..3).map {
|
||||
makeBook("$it", seriesId = series.id, libraryId = library.id)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
val books = bookRepository.findAll().sortedBy { it.name }
|
||||
books.elementAt(0).let { readProgressRepository.save(ReadProgress(it.id, user.id, 5, true)) }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import org.assertj.core.api.Assertions.assertThat
|
|||
import org.assertj.core.api.Assertions.catchThrowable
|
||||
import org.gotson.komga.domain.model.Author
|
||||
import org.gotson.komga.domain.model.BookMetadata
|
||||
import org.gotson.komga.domain.model.SeriesMetadata
|
||||
import org.gotson.komga.domain.model.makeBook
|
||||
import org.gotson.komga.domain.model.makeLibrary
|
||||
import org.gotson.komga.domain.model.makeSeries
|
||||
|
|
@ -223,4 +222,3 @@ class BookMetadataDaoTest(
|
|||
assertThat(found).isInstanceOf(Exception::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,10 +61,12 @@ class MediaDaoTest(
|
|||
val media = Media(
|
||||
status = Media.Status.READY,
|
||||
mediaType = "application/zip",
|
||||
pages = listOf(BookPage(
|
||||
fileName = "1.jpg",
|
||||
mediaType = "image/jpeg"
|
||||
)),
|
||||
pages = listOf(
|
||||
BookPage(
|
||||
fileName = "1.jpg",
|
||||
mediaType = "image/jpeg"
|
||||
)
|
||||
),
|
||||
files = listOf("ComicInfo.xml"),
|
||||
comment = "comment",
|
||||
bookId = book.id
|
||||
|
|
@ -108,10 +110,12 @@ class MediaDaoTest(
|
|||
val media = Media(
|
||||
status = Media.Status.READY,
|
||||
mediaType = "application/zip",
|
||||
pages = listOf(BookPage(
|
||||
fileName = "1.jpg",
|
||||
mediaType = "image/jpeg"
|
||||
)),
|
||||
pages = listOf(
|
||||
BookPage(
|
||||
fileName = "1.jpg",
|
||||
mediaType = "image/jpeg"
|
||||
)
|
||||
),
|
||||
files = listOf("ComicInfo.xml"),
|
||||
comment = "comment",
|
||||
bookId = book.id
|
||||
|
|
@ -124,10 +128,12 @@ class MediaDaoTest(
|
|||
copy(
|
||||
status = Media.Status.ERROR,
|
||||
mediaType = "application/rar",
|
||||
pages = listOf(BookPage(
|
||||
fileName = "2.png",
|
||||
mediaType = "image/png"
|
||||
)),
|
||||
pages = listOf(
|
||||
BookPage(
|
||||
fileName = "2.png",
|
||||
mediaType = "image/png"
|
||||
)
|
||||
),
|
||||
files = listOf("id.txt"),
|
||||
comment = "comment2"
|
||||
)
|
||||
|
|
@ -154,10 +160,12 @@ class MediaDaoTest(
|
|||
val media = Media(
|
||||
status = Media.Status.READY,
|
||||
mediaType = "application/zip",
|
||||
pages = listOf(BookPage(
|
||||
fileName = "1.jpg",
|
||||
mediaType = "image/jpeg"
|
||||
)),
|
||||
pages = listOf(
|
||||
BookPage(
|
||||
fileName = "1.jpg",
|
||||
mediaType = "image/jpeg"
|
||||
)
|
||||
),
|
||||
files = listOf("ComicInfo.xml"),
|
||||
comment = "comment",
|
||||
bookId = book.id
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ class ReadListDaoTest(
|
|||
)
|
||||
readListDao.insert(readList2)
|
||||
|
||||
|
||||
// when
|
||||
readListDao.removeBookFromAll(books.first().id)
|
||||
|
||||
|
|
@ -155,20 +154,26 @@ class ReadListDaoTest(
|
|||
val seriesLibrary2 = makeSeries("Series2", library2.id).also { seriesRepository.insert(it) }
|
||||
val bookLibrary2 = makeBook("Book2", libraryId = library2.id, seriesId = seriesLibrary2.id).also { bookRepository.insert(it) }
|
||||
|
||||
readListDao.insert(ReadList(
|
||||
name = "readListLibrary1",
|
||||
bookIds = listOf(bookLibrary1.id).toIndexedMap()
|
||||
))
|
||||
readListDao.insert(
|
||||
ReadList(
|
||||
name = "readListLibrary1",
|
||||
bookIds = listOf(bookLibrary1.id).toIndexedMap()
|
||||
)
|
||||
)
|
||||
|
||||
readListDao.insert(ReadList(
|
||||
name = "readListLibrary2",
|
||||
bookIds = listOf(bookLibrary2.id).toIndexedMap()
|
||||
))
|
||||
readListDao.insert(
|
||||
ReadList(
|
||||
name = "readListLibrary2",
|
||||
bookIds = listOf(bookLibrary2.id).toIndexedMap()
|
||||
)
|
||||
)
|
||||
|
||||
readListDao.insert(ReadList(
|
||||
name = "readListLibraryBoth",
|
||||
bookIds = listOf(bookLibrary1.id, bookLibrary2.id).toIndexedMap()
|
||||
))
|
||||
readListDao.insert(
|
||||
ReadList(
|
||||
name = "readListLibraryBoth",
|
||||
bookIds = listOf(bookLibrary1.id, bookLibrary2.id).toIndexedMap()
|
||||
)
|
||||
)
|
||||
|
||||
// when
|
||||
val foundLibrary1Filtered = readListDao.findAllByLibraries(listOf(library.id), listOf(library.id), pageable = Pageable.unpaged()).content
|
||||
|
|
|
|||
|
|
@ -65,12 +65,14 @@ class ReadProgressDaoTest(
|
|||
fun `given book without user progress when saving progress then progress is saved`() {
|
||||
val now = LocalDateTime.now()
|
||||
|
||||
readProgressDao.save(ReadProgress(
|
||||
book1.id,
|
||||
user1.id,
|
||||
5,
|
||||
false
|
||||
))
|
||||
readProgressDao.save(
|
||||
ReadProgress(
|
||||
book1.id,
|
||||
user1.id,
|
||||
5,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
val readProgressList = readProgressDao.findByUserId(user1.id)
|
||||
|
||||
|
|
@ -87,21 +89,25 @@ class ReadProgressDaoTest(
|
|||
|
||||
@Test
|
||||
fun `given book with user progress when saving progress then progress is updated`() {
|
||||
readProgressDao.save(ReadProgress(
|
||||
book1.id,
|
||||
user1.id,
|
||||
5,
|
||||
false
|
||||
))
|
||||
readProgressDao.save(
|
||||
ReadProgress(
|
||||
book1.id,
|
||||
user1.id,
|
||||
5,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
val modificationDate = LocalDateTime.now()
|
||||
|
||||
readProgressDao.save(ReadProgress(
|
||||
book1.id,
|
||||
user1.id,
|
||||
10,
|
||||
true
|
||||
))
|
||||
readProgressDao.save(
|
||||
ReadProgress(
|
||||
book1.id,
|
||||
user1.id,
|
||||
10,
|
||||
true
|
||||
)
|
||||
)
|
||||
|
||||
val readProgressList = readProgressDao.findByUserId(user1.id)
|
||||
|
||||
|
|
|
|||
|
|
@ -144,20 +144,26 @@ class SeriesCollectionDaoTest(
|
|||
val seriesLibrary1 = makeSeries("Series1", library.id).also { seriesRepository.insert(it) }
|
||||
val seriesLibrary2 = makeSeries("Series2", library2.id).also { seriesRepository.insert(it) }
|
||||
|
||||
collectionDao.insert(SeriesCollection(
|
||||
name = "collectionLibrary1",
|
||||
seriesIds = listOf(seriesLibrary1.id)
|
||||
))
|
||||
collectionDao.insert(
|
||||
SeriesCollection(
|
||||
name = "collectionLibrary1",
|
||||
seriesIds = listOf(seriesLibrary1.id)
|
||||
)
|
||||
)
|
||||
|
||||
collectionDao.insert(SeriesCollection(
|
||||
name = "collectionLibrary2",
|
||||
seriesIds = listOf(seriesLibrary2.id)
|
||||
))
|
||||
collectionDao.insert(
|
||||
SeriesCollection(
|
||||
name = "collectionLibrary2",
|
||||
seriesIds = listOf(seriesLibrary2.id)
|
||||
)
|
||||
)
|
||||
|
||||
collectionDao.insert(SeriesCollection(
|
||||
name = "collectionLibraryBoth",
|
||||
seriesIds = listOf(seriesLibrary1.id, seriesLibrary2.id)
|
||||
))
|
||||
collectionDao.insert(
|
||||
SeriesCollection(
|
||||
name = "collectionLibraryBoth",
|
||||
seriesIds = listOf(seriesLibrary1.id, seriesLibrary2.id)
|
||||
)
|
||||
)
|
||||
|
||||
// when
|
||||
val foundLibrary1Filtered = collectionDao.findAllByLibraries(listOf(library.id), listOf(library.id), pageable = Pageable.unpaged()).content
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ class SeriesDaoTest(
|
|||
libraryRepository.deleteAll()
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `given a series when inserting then it is persisted`() {
|
||||
val now = LocalDateTime.now()
|
||||
|
|
|
|||
|
|
@ -68,10 +68,12 @@ class SeriesDtoDaoTest(
|
|||
(1..4).map { makeSeries("$it", library.id) }
|
||||
.forEach { series ->
|
||||
val created = seriesLifecycle.createSeries(series)
|
||||
seriesLifecycle.addBooks(created,
|
||||
seriesLifecycle.addBooks(
|
||||
created,
|
||||
(1..3).map {
|
||||
makeBook("$it", seriesId = created.id, libraryId = library.id)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val series = seriesRepository.findAll().sortedBy { it.name }
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ class SeriesMetadataDaoTest(
|
|||
libraryRepository.deleteAll()
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `given a seriesMetadata when inserting then it is persisted`() {
|
||||
val series = makeSeries("Series", libraryId = library.id).also { seriesRepository.insert(it) }
|
||||
|
|
@ -60,7 +59,7 @@ class SeriesMetadataDaoTest(
|
|||
publisher = "publisher",
|
||||
ageRating = 18,
|
||||
genres = setOf("Action", "Adventure"),
|
||||
tags = setOf("tag","another"),
|
||||
tags = setOf("tag", "another"),
|
||||
language = "en",
|
||||
titleLock = true,
|
||||
titleSortLock = true,
|
||||
|
|
@ -197,7 +196,6 @@ class SeriesMetadataDaoTest(
|
|||
seriesMetadataDao.insert(metadata)
|
||||
val created = seriesMetadataDao.findById(metadata.seriesId)
|
||||
|
||||
|
||||
val modificationDate = LocalDateTime.now()
|
||||
|
||||
val updated = with(created) {
|
||||
|
|
|
|||
|
|
@ -284,6 +284,5 @@ class ComicInfoProviderTest {
|
|||
assertThat(collections).isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,11 +43,13 @@ class LocalArtworkProviderTest {
|
|||
|
||||
(thumbsFiles + thumbsDashFiles + invalidFiles).forEach { Files.createFile(root.resolve(it)) }
|
||||
|
||||
val book = spyk(Book(
|
||||
name = "Book",
|
||||
url = bookFile.toUri().toURL(),
|
||||
fileLastModified = LocalDateTime.now()
|
||||
))
|
||||
val book = spyk(
|
||||
Book(
|
||||
name = "Book",
|
||||
url = bookFile.toUri().toURL(),
|
||||
fileLastModified = LocalDateTime.now()
|
||||
)
|
||||
)
|
||||
every { book.path() } returns bookFile
|
||||
|
||||
// when
|
||||
|
|
@ -75,11 +77,13 @@ class LocalArtworkProviderTest {
|
|||
|
||||
(thumbsFiles + invalidFiles).forEach { Files.createFile(seriesPath.resolve(it)) }
|
||||
|
||||
val series = spyk(Series(
|
||||
name = "Series",
|
||||
url = seriesFile.toUri().toURL(),
|
||||
fileLastModified = LocalDateTime.now()
|
||||
))
|
||||
val series = spyk(
|
||||
Series(
|
||||
name = "Series",
|
||||
url = seriesFile.toUri().toURL(),
|
||||
fileLastModified = LocalDateTime.now()
|
||||
)
|
||||
)
|
||||
every { series.path() } returns seriesFile
|
||||
|
||||
// when
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ class BookControllerTest(
|
|||
jsonPath("$.content.length()") { value(1) }
|
||||
jsonPath("$.content[0].name") { value("1") }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -331,10 +330,12 @@ class BookControllerTest(
|
|||
|
||||
val book = bookRepository.findAll().first()
|
||||
mediaRepository.findById(book.id).let {
|
||||
mediaRepository.update(it.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = listOf(BookPage("file", "image/jpeg"))
|
||||
))
|
||||
mediaRepository.update(
|
||||
it.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = listOf(BookPage("file", "image/jpeg"))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
mockMvc.get("/api/v1/books/${book.id}/pages/$page")
|
||||
|
|
@ -363,33 +364,32 @@ class BookControllerTest(
|
|||
val second = bookRepository.findAll(BookSearch(searchTerm = "2")).first().id
|
||||
val third = bookRepository.findAll(BookSearch(searchTerm = "3")).first().id
|
||||
|
||||
mockMvc.get("/api/v1/books/${first}/previous")
|
||||
mockMvc.get("/api/v1/books/$first/previous")
|
||||
.andExpect { status { isNotFound() } }
|
||||
mockMvc.get("/api/v1/books/${first}/next")
|
||||
mockMvc.get("/api/v1/books/$first/next")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
jsonPath("$.name") { value("2") }
|
||||
}
|
||||
|
||||
mockMvc.get("/api/v1/books/${second}/previous")
|
||||
mockMvc.get("/api/v1/books/$second/previous")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
jsonPath("$.name") { value("1") }
|
||||
}
|
||||
mockMvc.get("/api/v1/books/${second}/next")
|
||||
mockMvc.get("/api/v1/books/$second/next")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
jsonPath("$.name") { value("3") }
|
||||
}
|
||||
|
||||
mockMvc.get("/api/v1/books/${third}/previous")
|
||||
mockMvc.get("/api/v1/books/$third/previous")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
jsonPath("$.name") { value("2") }
|
||||
}
|
||||
mockMvc.get("/api/v1/books/${third}/next")
|
||||
mockMvc.get("/api/v1/books/$third/next")
|
||||
.andExpect { status { isNotFound() } }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -475,11 +475,13 @@ class BookControllerTest(
|
|||
}
|
||||
|
||||
val book = bookRepository.findAll().first()
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(100),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
))
|
||||
bookLifecycle.addThumbnailForBook(
|
||||
ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(100),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
)
|
||||
)
|
||||
|
||||
val url = "/api/v1/books/${book.id}/thumbnail"
|
||||
|
||||
|
|
@ -532,22 +534,26 @@ class BookControllerTest(
|
|||
}
|
||||
|
||||
val book = bookRepository.findAll().first()
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(1),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
))
|
||||
bookLifecycle.addThumbnailForBook(
|
||||
ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(1),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
)
|
||||
)
|
||||
|
||||
val url = "/api/v1/books/${book.id}/thumbnail"
|
||||
|
||||
val response = mockMvc.get(url).andReturn().response
|
||||
|
||||
Thread.sleep(100)
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(1),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
))
|
||||
bookLifecycle.addThumbnailForBook(
|
||||
ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(1),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
)
|
||||
)
|
||||
|
||||
mockMvc.get(url) {
|
||||
headers {
|
||||
|
|
@ -573,11 +579,13 @@ class BookControllerTest(
|
|||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = [
|
||||
"""{"title":""}""",
|
||||
"""{"number":""}""",
|
||||
"""{"authors":"[{"name":""}]"}"""
|
||||
])
|
||||
@ValueSource(
|
||||
strings = [
|
||||
"""{"title":""}""",
|
||||
"""{"number":""}""",
|
||||
"""{"authors":"[{"name":""}]"}"""
|
||||
]
|
||||
)
|
||||
@WithMockCustomUser(roles = [ROLE_ADMIN])
|
||||
fun `given invalid json when updating metadata then raise validation error`(jsonString: String) {
|
||||
mockMvc.patch("/api/v1/books/1/metadata") {
|
||||
|
|
@ -628,7 +636,7 @@ class BookControllerTest(
|
|||
}
|
||||
""".trimIndent()
|
||||
|
||||
mockMvc.patch("/api/v1/books/${bookId}/metadata") {
|
||||
mockMvc.patch("/api/v1/books/$bookId/metadata") {
|
||||
contentType = MediaType.APPLICATION_JSON
|
||||
content = jsonString
|
||||
}.andExpect {
|
||||
|
|
@ -698,7 +706,7 @@ class BookControllerTest(
|
|||
}
|
||||
""".trimIndent()
|
||||
|
||||
mockMvc.patch("/api/v1/books/${bookId}/metadata") {
|
||||
mockMvc.patch("/api/v1/books/$bookId/metadata") {
|
||||
contentType = MediaType.APPLICATION_JSON
|
||||
content = jsonString
|
||||
}.andExpect {
|
||||
|
|
@ -746,7 +754,7 @@ class BookControllerTest(
|
|||
}
|
||||
""".trimIndent()
|
||||
|
||||
mockMvc.patch("/api/v1/books/${bookId}/metadata") {
|
||||
mockMvc.patch("/api/v1/books/$bookId/metadata") {
|
||||
contentType = MediaType.APPLICATION_JSON
|
||||
content = jsonString
|
||||
}.andExpect {
|
||||
|
|
@ -769,11 +777,13 @@ class BookControllerTest(
|
|||
inner class ReadProgress {
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = [
|
||||
"""{"completed": false}""",
|
||||
"""{}""",
|
||||
"""{"page":0}"""
|
||||
])
|
||||
@ValueSource(
|
||||
strings = [
|
||||
"""{"completed": false}""",
|
||||
"""{}""",
|
||||
"""{"page":0}"""
|
||||
]
|
||||
)
|
||||
@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") {
|
||||
|
|
@ -796,10 +806,12 @@ class BookControllerTest(
|
|||
|
||||
val book = bookRepository.findAll().first()
|
||||
mediaRepository.findById(book.id).let { media ->
|
||||
mediaRepository.update(media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
))
|
||||
mediaRepository.update(
|
||||
media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val jsonString = """
|
||||
|
|
@ -835,10 +847,12 @@ class BookControllerTest(
|
|||
|
||||
val book = bookRepository.findAll().first()
|
||||
mediaRepository.findById(book.id).let { media ->
|
||||
mediaRepository.update(media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
))
|
||||
mediaRepository.update(
|
||||
media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val jsonString = """
|
||||
|
|
@ -874,10 +888,12 @@ class BookControllerTest(
|
|||
|
||||
val book = bookRepository.findAll().first()
|
||||
mediaRepository.findById(book.id).let { media ->
|
||||
mediaRepository.update(media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
))
|
||||
mediaRepository.update(
|
||||
media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val jsonString = """
|
||||
|
|
@ -894,7 +910,6 @@ class BookControllerTest(
|
|||
status { isNoContent() }
|
||||
}
|
||||
|
||||
|
||||
mockMvc.delete("/api/v1/books/${book.id}/read-progress") {
|
||||
contentType = MediaType.APPLICATION_JSON
|
||||
}.andExpect {
|
||||
|
|
@ -920,37 +935,42 @@ class BookControllerTest(
|
|||
|
||||
val book = bookRepository.findAll().first()
|
||||
mediaRepository.findById(book.id).let { media ->
|
||||
mediaRepository.update(media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
))
|
||||
mediaRepository.update(
|
||||
media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val jsonString = """
|
||||
{
|
||||
"completed": true
|
||||
}
|
||||
""".trimIndent()
|
||||
""".trimIndent()
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.patch("/api/v1/books/${book.id}/read-progress")
|
||||
.with(user(KomgaPrincipal(user)))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(jsonString)
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders
|
||||
.patch("/api/v1/books/${book.id}/read-progress")
|
||||
.with(user(KomgaPrincipal(user)))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(jsonString)
|
||||
)
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.get("/api/v1/books")
|
||||
.with(user(KomgaPrincipal(user)))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
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)
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders
|
||||
.get("/api/v1/books")
|
||||
.with(user(KomgaPrincipal(user2)))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
).andExpect(
|
||||
jsonPath("$.totalElements").value(2)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ class LibraryControllerTest(
|
|||
jsonPath("$[0].root") { value("") }
|
||||
}
|
||||
|
||||
mockMvc.get("${route}/${library.id}")
|
||||
mockMvc.get("$route/${library.id}")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
jsonPath("$.root") { value("") }
|
||||
|
|
@ -126,7 +126,7 @@ class LibraryControllerTest(
|
|||
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")) }
|
||||
|
|
|
|||
|
|
@ -79,20 +79,26 @@ class ReadListControllerTest(
|
|||
}
|
||||
|
||||
private fun makeReadLists() {
|
||||
rlLib1 = readListLifecycle.addReadList(ReadList(
|
||||
name = "Lib1",
|
||||
bookIds = booksLibrary1.map { it.id }.toIndexedMap()
|
||||
))
|
||||
rlLib1 = readListLifecycle.addReadList(
|
||||
ReadList(
|
||||
name = "Lib1",
|
||||
bookIds = booksLibrary1.map { it.id }.toIndexedMap()
|
||||
)
|
||||
)
|
||||
|
||||
rlLib2 = readListLifecycle.addReadList(ReadList(
|
||||
name = "Lib2",
|
||||
bookIds = booksLibrary2.map { it.id }.toIndexedMap()
|
||||
))
|
||||
rlLib2 = readListLifecycle.addReadList(
|
||||
ReadList(
|
||||
name = "Lib2",
|
||||
bookIds = booksLibrary2.map { it.id }.toIndexedMap()
|
||||
)
|
||||
)
|
||||
|
||||
rlLibBoth = readListLifecycle.addReadList(ReadList(
|
||||
name = "Lib1+2",
|
||||
bookIds = (booksLibrary1 + booksLibrary2).map { it.id }.toIndexedMap()
|
||||
))
|
||||
rlLibBoth = readListLifecycle.addReadList(
|
||||
ReadList(
|
||||
name = "Lib1+2",
|
||||
bookIds = (booksLibrary1 + booksLibrary2).map { it.id }.toIndexedMap()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
|
@ -213,31 +219,31 @@ 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() } }
|
||||
}
|
||||
|
||||
|
|
@ -250,31 +256,31 @@ 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() } }
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +452,6 @@ class ReadListControllerTest(
|
|||
jsonPath("$.bookIds.length()") { value(5) }
|
||||
}
|
||||
|
||||
|
||||
mockMvc.patch("/api/v1/readlists/${rlLibBoth.id}") {
|
||||
contentType = MediaType.APPLICATION_JSON
|
||||
content = """{"bookIds":["${booksLibrary1.first().id}"]}"""
|
||||
|
|
|
|||
|
|
@ -74,20 +74,26 @@ class SeriesCollectionControllerTest(
|
|||
}
|
||||
|
||||
private fun makeCollections() {
|
||||
colLib1 = collectionLifecycle.addCollection(SeriesCollection(
|
||||
name = "Lib1",
|
||||
seriesIds = seriesLibrary1.map { it.id }
|
||||
))
|
||||
colLib1 = collectionLifecycle.addCollection(
|
||||
SeriesCollection(
|
||||
name = "Lib1",
|
||||
seriesIds = seriesLibrary1.map { it.id }
|
||||
)
|
||||
)
|
||||
|
||||
colLib2 = collectionLifecycle.addCollection(SeriesCollection(
|
||||
name = "Lib2",
|
||||
seriesIds = seriesLibrary2.map { it.id }
|
||||
))
|
||||
colLib2 = collectionLifecycle.addCollection(
|
||||
SeriesCollection(
|
||||
name = "Lib2",
|
||||
seriesIds = seriesLibrary2.map { it.id }
|
||||
)
|
||||
)
|
||||
|
||||
colLibBoth = collectionLifecycle.addCollection(SeriesCollection(
|
||||
name = "Lib1+2",
|
||||
seriesIds = (seriesLibrary1 + seriesLibrary2).map { it.id }
|
||||
))
|
||||
colLibBoth = collectionLifecycle.addCollection(
|
||||
SeriesCollection(
|
||||
name = "Lib1+2",
|
||||
seriesIds = (seriesLibrary1 + seriesLibrary2).map { it.id }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
|
@ -318,7 +324,6 @@ class SeriesCollectionControllerTest(
|
|||
jsonPath("$.seriesIds.length()") { value(5) }
|
||||
}
|
||||
|
||||
|
||||
mockMvc.patch("/api/v1/collections/${colLib2.id}") {
|
||||
contentType = MediaType.APPLICATION_JSON
|
||||
content = """{"name":"newName"}"""
|
||||
|
|
@ -332,7 +337,6 @@ class SeriesCollectionControllerTest(
|
|||
jsonPath("$.seriesIds.length()") { value(5) }
|
||||
}
|
||||
|
||||
|
||||
mockMvc.patch("/api/v1/collections/${colLibBoth.id}") {
|
||||
contentType = MediaType.APPLICATION_JSON
|
||||
content = """{"seriesIds":["${seriesLibrary1.first().id}"]}"""
|
||||
|
|
|
|||
|
|
@ -351,12 +351,14 @@ class SeriesControllerTest(
|
|||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = [
|
||||
"""{"title":""}""",
|
||||
"""{"titleSort":""}""",
|
||||
"""{"ageRating":-1}""",
|
||||
"""{"language":"japanese"}"""
|
||||
])
|
||||
@ValueSource(
|
||||
strings = [
|
||||
"""{"title":""}""",
|
||||
"""{"titleSort":""}""",
|
||||
"""{"ageRating":-1}""",
|
||||
"""{"language":"japanese"}"""
|
||||
]
|
||||
)
|
||||
@WithMockCustomUser(roles = [ROLE_ADMIN])
|
||||
fun `given invalid json when updating metadata then raise validation error`(jsonString: String) {
|
||||
mockMvc.patch("/api/v1/series/1/metadata") {
|
||||
|
|
@ -502,11 +504,13 @@ class SeriesControllerTest(
|
|||
}
|
||||
|
||||
bookRepository.findAll().first().let { book ->
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(1),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
))
|
||||
bookLifecycle.addThumbnailForBook(
|
||||
ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(1),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val url = "/api/v1/series/${createdSeries.id}/thumbnail"
|
||||
|
|
@ -534,11 +538,13 @@ class SeriesControllerTest(
|
|||
}
|
||||
|
||||
bookRepository.findAll().forEach { book ->
|
||||
bookLifecycle.addThumbnailForBook(ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(1),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
))
|
||||
bookLifecycle.addThumbnailForBook(
|
||||
ThumbnailBook(
|
||||
thumbnail = Random.nextBytes(1),
|
||||
bookId = book.id,
|
||||
type = ThumbnailBook.Type.GENERATED
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val url = "/api/v1/series/${createdSeries.id}/thumbnail"
|
||||
|
|
@ -575,10 +581,12 @@ class SeriesControllerTest(
|
|||
|
||||
bookRepository.findAll().forEach { book ->
|
||||
mediaRepository.findById(book.id).let { media ->
|
||||
mediaRepository.update(media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
))
|
||||
mediaRepository.update(
|
||||
media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -615,10 +623,12 @@ class SeriesControllerTest(
|
|||
|
||||
bookRepository.findAll().forEach { book ->
|
||||
mediaRepository.findById(book.id).let { media ->
|
||||
mediaRepository.update(media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
))
|
||||
mediaRepository.update(
|
||||
media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -664,10 +674,12 @@ class SeriesControllerTest(
|
|||
|
||||
bookRepository.findAll().forEach { book ->
|
||||
mediaRepository.findById(book.id).let { media ->
|
||||
mediaRepository.update(media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
))
|
||||
mediaRepository.update(
|
||||
media.copy(
|
||||
status = Media.Status.READY,
|
||||
pages = (1..10).map { BookPage("$it", "image/jpeg") }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue