style: apply ktlint to whole project

This commit is contained in:
Gauthier Roebroeck 2021-01-08 16:33:37 +08:00
parent 6b769884ed
commit 52ce9a575a
76 changed files with 537 additions and 500 deletions

View file

@ -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>

View file

@ -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(
}
}
}

View file

@ -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))
}
}

View file

@ -15,4 +15,3 @@ class BookSearchWithReadProgress(
val tags: Collection<String>? = null,
val readStatus: Collection<ReadStatus>? = null
) : BookSearch(libraryIds, seriesIds, searchTerm, mediaStatus)

View file

@ -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?

View file

@ -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" }

View file

@ -72,6 +72,4 @@ class KomgaUserLifecycle(
it.expireNow()
}
}
}

View file

@ -109,5 +109,4 @@ class LibraryScanner(
}
}.also { logger.info { "Library updated in $it" } }
}
}

View file

@ -42,5 +42,4 @@ class MetadataApplier {
genres = getIfNotLocked(genres, patch.genres, genresLock)
)
}
}

View file

@ -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
}
}

View file

@ -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

View file

@ -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:")

View file

@ -7,4 +7,4 @@ import org.springframework.context.annotation.Profile
@Profile("dev")
@Configuration
@ImportResource("classpath:h2server.xml")
class DevelopmentConfiguration
class DevelopmentConfiguration

View file

@ -11,7 +11,6 @@ import javax.imageio.ImageIO
import javax.imageio.spi.IIORegistry
import javax.imageio.spi.ImageReaderSpi
private val logger = KotlinLogging.logger {}
@Service

View file

@ -6,7 +6,6 @@ import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
import javax.imageio.ImageIO
@Service
class MosaicGenerator {

View file

@ -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)

View file

@ -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()

View file

@ -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)

View file

@ -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

View file

@ -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()
}

View file

@ -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,

View file

@ -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()

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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()

View file

@ -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
)
}

View file

@ -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),

View file

@ -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 ->

View file

@ -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 },

View file

@ -116,5 +116,4 @@ class ComicInfo {
@JsonProperty(value = "AgeRating", defaultValue = "Unknown")
var ageRating: AgeRating? = null
}

View file

@ -109,5 +109,4 @@ class EpubMetadataProvider(
null
}
}
}

View file

@ -65,5 +65,4 @@ class LocalArtworkProvider(
}.toList()
}
}
}

View file

@ -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()

View file

@ -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

View file

@ -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")
)
)
}

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -7,7 +7,6 @@ import javax.validation.constraints.NotBlank
import javax.validation.constraints.Null
import kotlin.reflect.KClass
@ConstraintComposition(CompositionType.OR)
@Constraint(validatedBy = [])
@Null

View file

@ -7,7 +7,6 @@ import javax.validation.constraints.NotEmpty
import javax.validation.constraints.Null
import kotlin.reflect.KClass
@ConstraintComposition(CompositionType.OR)
@Constraint(validatedBy = [])
@Null

View file

@ -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

View file

@ -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) {

View file

@ -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(

View file

@ -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
}
}

View file

@ -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)
}

View file

@ -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(

View file

@ -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)
}

View file

@ -127,4 +127,3 @@ class UserController(
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
}
}

View file

@ -72,4 +72,3 @@ data class ReadProgressDto(
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
val lastModified: LocalDateTime
)

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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

View file

@ -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())

View file

@ -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)

View file

@ -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")
}
}
}

View file

@ -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

View file

@ -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)) }

View file

@ -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)
}
}

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -41,7 +41,6 @@ class SeriesDaoTest(
libraryRepository.deleteAll()
}
@Test
fun `given a series when inserting then it is persisted`() {
val now = LocalDateTime.now()

View file

@ -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 }

View file

@ -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) {

View file

@ -284,6 +284,5 @@ class ComicInfoProviderTest {
assertThat(collections).isEmpty()
}
}
}
}

View file

@ -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

View file

@ -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)
)

View file

@ -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")) }

View file

@ -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}"]}"""

View file

@ -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}"]}"""

View file

@ -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") }
)
)
}
}