feat(api): batch update book metadata

This commit is contained in:
Gauthier Roebroeck 2021-08-20 14:55:37 +08:00
parent 2ddfec2e5c
commit ae9a19af62
2 changed files with 54 additions and 28 deletions

View file

@ -11,7 +11,6 @@ import org.gotson.komga.application.events.EventPublisher
import org.gotson.komga.application.tasks.HIGHEST_PRIORITY
import org.gotson.komga.application.tasks.HIGH_PRIORITY
import org.gotson.komga.application.tasks.TaskReceiver
import org.gotson.komga.domain.model.Author
import org.gotson.komga.domain.model.BookSearchWithReadProgress
import org.gotson.komga.domain.model.DomainEvent
import org.gotson.komga.domain.model.ImageConversionException
@ -40,6 +39,7 @@ import org.gotson.komga.interfaces.rest.dto.BookMetadataUpdateDto
import org.gotson.komga.interfaces.rest.dto.PageDto
import org.gotson.komga.interfaces.rest.dto.ReadListDto
import org.gotson.komga.interfaces.rest.dto.ReadProgressUpdateDto
import org.gotson.komga.interfaces.rest.dto.patch
import org.gotson.komga.interfaces.rest.dto.restrictUrl
import org.gotson.komga.interfaces.rest.dto.toDto
import org.gotson.komga.interfaces.rest.persistence.BookDtoRepository
@ -452,39 +452,37 @@ class BookController(
@PathVariable bookId: String,
@Parameter(description = "Metadata fields to update. Set a field to null to unset the metadata. You can omit fields you don't want to update.")
@Valid @RequestBody newMetadata: BookMetadataUpdateDto,
@AuthenticationPrincipal principal: KomgaPrincipal
) =
bookMetadataRepository.findByIdOrNull(bookId)?.let { existing ->
val updated = with(newMetadata) {
existing.copy(
title = title ?: existing.title,
titleLock = titleLock ?: existing.titleLock,
summary = if (isSet("summary")) summary ?: "" else existing.summary,
summaryLock = summaryLock ?: existing.summaryLock,
number = number ?: existing.number,
numberLock = numberLock ?: existing.numberLock,
numberSort = numberSort ?: existing.numberSort,
numberSortLock = numberSortLock ?: existing.numberSortLock,
releaseDate = if (isSet("releaseDate")) releaseDate else existing.releaseDate,
releaseDateLock = releaseDateLock ?: existing.releaseDateLock,
authors = if (isSet("authors")) {
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()
} else existing.tags,
tagsLock = tagsLock ?: existing.tagsLock,
isbn = if (isSet("isbn")) isbn?.filter { it.isDigit() } ?: "" else existing.isbn,
isbnLock = isbnLock ?: existing.isbnLock
)
}
val updated = existing.patch(newMetadata)
bookMetadataRepository.update(updated)
taskReceiver.aggregateSeriesMetadata(bookRepository.findByIdOrNull(bookId)!!.seriesId)
bookRepository.findByIdOrNull(bookId)?.let { eventPublisher.publishEvent(DomainEvent.BookUpdated(it)) }
bookRepository.findByIdOrNull(bookId)?.let { updatedBook ->
taskReceiver.aggregateSeriesMetadata(updatedBook.seriesId)
updatedBook.let { eventPublisher.publishEvent(DomainEvent.BookUpdated(it)) }
}
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
@PatchMapping("api/v1/books/metadata")
@PreAuthorize("hasRole('$ROLE_ADMIN')")
@ResponseStatus(HttpStatus.NO_CONTENT)
fun updateBatchMetadata(
@Parameter(description = "A map of book IDs which values are the metadata fields to update. Set a field to null to unset the metadata. You can omit fields you don't want to update.")
@Valid @RequestBody newMetadatas: Map<String, BookMetadataUpdateDto>,
) {
val updatedBooks = newMetadatas.mapNotNull { (bookId, newMetadata) ->
bookMetadataRepository.findByIdOrNull(bookId)?.let { existing ->
val updated = existing.patch(newMetadata)
bookMetadataRepository.update(updated)
bookRepository.findByIdOrNull(bookId)
}
}
updatedBooks.forEach { eventPublisher.publishEvent(DomainEvent.BookUpdated(it)) }
updatedBooks.map { it.seriesId }.distinct().forEach { taskReceiver.aggregateSeriesMetadata(it) }
}
@PatchMapping("api/v1/books/{bookId}/read-progress")
@ResponseStatus(HttpStatus.NO_CONTENT)
fun markReadProgress(

View file

@ -1,5 +1,7 @@
package org.gotson.komga.interfaces.rest.dto
import org.gotson.komga.domain.model.Author
import org.gotson.komga.domain.model.BookMetadata
import org.gotson.komga.infrastructure.validation.NullOrBlankOrISBN
import org.gotson.komga.infrastructure.validation.NullOrNotBlank
import java.time.LocalDate
@ -70,3 +72,29 @@ class AuthorUpdateDto {
@get:NotBlank
val role: String? = null
}
fun BookMetadata.patch(patch: BookMetadataUpdateDto) =
patch.let {
this.copy(
title = patch.title ?: this.title,
titleLock = patch.titleLock ?: this.titleLock,
summary = if (patch.isSet("summary")) patch.summary ?: "" else this.summary,
summaryLock = patch.summaryLock ?: this.summaryLock,
number = patch.number ?: this.number,
numberLock = patch.numberLock ?: this.numberLock,
numberSort = patch.numberSort ?: this.numberSort,
numberSortLock = patch.numberSortLock ?: this.numberSortLock,
releaseDate = if (patch.isSet("releaseDate")) patch.releaseDate else this.releaseDate,
releaseDateLock = patch.releaseDateLock ?: this.releaseDateLock,
authors = if (patch.isSet("authors")) {
if (patch.authors != null) patch.authors!!.map { Author(it.name ?: "", it.role ?: "") } else emptyList()
} else this.authors,
authorsLock = patch.authorsLock ?: this.authorsLock,
tags = if (patch.isSet("tags")) {
if (patch.tags != null) patch.tags!! else emptySet()
} else this.tags,
tagsLock = patch.tagsLock ?: this.tagsLock,
isbn = if (patch.isSet("isbn")) patch.isbn?.filter { it.isDigit() } ?: "" else this.isbn,
isbnLock = patch.isbnLock ?: this.isbnLock
)
}