Skip to content

Commit

Permalink
feat: add Series Metadata status
Browse files Browse the repository at this point in the history
updatable via API

linked to #48
  • Loading branch information
gotson committed Jan 21, 2020
1 parent f046bab commit f522142
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package db.migration

import org.flywaydb.core.api.migration.BaseJavaMigration
import org.flywaydb.core.api.migration.Context
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.datasource.SingleConnectionDataSource
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

class V20200121154334__create_series_metadata_from_series : BaseJavaMigration() {
override fun migrate(context: Context) {
val jdbcTemplate = JdbcTemplate(SingleConnectionDataSource(context.connection, true))

val seriesIds = jdbcTemplate.queryForList("SELECT id FROM series", Long::class.java)

val now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"))
seriesIds.forEach { seriesId ->
val metadataId = jdbcTemplate.queryForObject("SELECT NEXTVAL('hibernate_sequence')", Int::class.java)
jdbcTemplate.execute("INSERT INTO series_metadata (ID, CREATED_DATE, LAST_MODIFIED_DATE, STATUS) VALUES ($metadataId, '$now', '$now', 'ONGOING')")
jdbcTemplate.execute("UPDATE series SET metadata_id = $metadataId WHERE id = $seriesId")
}
}
}
5 changes: 5 additions & 0 deletions komga/src/main/kotlin/org/gotson/komga/domain/model/Series.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import javax.persistence.Id
import javax.persistence.JoinColumn
import javax.persistence.ManyToOne
import javax.persistence.OneToMany
import javax.persistence.OneToOne
import javax.persistence.Table
import javax.validation.constraints.NotBlank
import javax.validation.constraints.NotNull
Expand Down Expand Up @@ -63,6 +64,10 @@ class Series(
_books.forEachIndexed { index, book -> book.number = index + 1F }
}

@OneToOne(optional = false, orphanRemoval = true, cascade = [CascadeType.ALL], fetch = FetchType.LAZY)
@JoinColumn(name = "metadata_id", nullable = false)
var metadata: SeriesMetadata = SeriesMetadata()

init {
this.books = books.toList()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.gotson.komga.domain.model

import org.hibernate.annotations.Cache
import org.hibernate.annotations.CacheConcurrencyStrategy
import javax.persistence.Cacheable
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.EnumType
import javax.persistence.Enumerated
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.Table

@Entity
@Table(name = "series_metadata")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "cache.series_metadata")
class SeriesMetadata(
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
var status: Status = Status.ONGOING

) : AuditableEntity() {
@Id
@GeneratedValue
@Column(name = "id", nullable = false, unique = true)
val id: Long = 0

enum class Status {
ENDED, ONGOING, ABANDONED, HIATUS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.gotson.komga.domain.persistence.SeriesRepository
import org.gotson.komga.infrastructure.security.KomgaPrincipal
import org.gotson.komga.interfaces.rest.dto.BookDto
import org.gotson.komga.interfaces.rest.dto.SeriesDto
import org.gotson.komga.interfaces.rest.dto.SeriesMetadataUpdateDto
import org.gotson.komga.interfaces.rest.dto.toDto
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
Expand All @@ -26,8 +27,10 @@ import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.ResponseStatus
Expand All @@ -49,16 +52,16 @@ class SeriesController(

@GetMapping
fun getAllSeries(
@AuthenticationPrincipal principal: KomgaPrincipal,
@RequestParam(name = "search", required = false) searchTerm: String?,
@RequestParam(name = "library_id", required = false) libraryIds: List<Long>?,
page: Pageable
@AuthenticationPrincipal principal: KomgaPrincipal,
@RequestParam(name = "search", required = false) searchTerm: String?,
@RequestParam(name = "library_id", required = false) libraryIds: List<Long>?,
page: Pageable
): Page<SeriesDto> {
val pageRequest = PageRequest.of(
page.pageNumber,
page.pageSize,
if (page.sort.isSorted) page.sort
else Sort.by(Sort.Order.asc("name").ignoreCase())
page.pageNumber,
page.pageSize,
if (page.sort.isSorted) page.sort
else Sort.by(Sort.Order.asc("name").ignoreCase())
)

return mutableListOf<Specification<Series>>().let { specs ->
Expand Down Expand Up @@ -94,13 +97,13 @@ class SeriesController(
// all updated series, whether newly added or updated
@GetMapping("/latest")
fun getLatestSeries(
@AuthenticationPrincipal principal: KomgaPrincipal,
page: Pageable
@AuthenticationPrincipal principal: KomgaPrincipal,
page: Pageable
): Page<SeriesDto> {
val pageRequest = PageRequest.of(
page.pageNumber,
page.pageSize,
Sort.by(Sort.Direction.DESC, "lastModifiedDate")
page.pageNumber,
page.pageSize,
Sort.by(Sort.Direction.DESC, "lastModifiedDate")
)

return if (principal.user.sharedAllLibraries) {
Expand All @@ -113,13 +116,13 @@ class SeriesController(
// new series only, doesn't contain existing updated series
@GetMapping("/new")
fun getNewSeries(
@AuthenticationPrincipal principal: KomgaPrincipal,
page: Pageable
@AuthenticationPrincipal principal: KomgaPrincipal,
page: Pageable
): Page<SeriesDto> {
val pageRequest = PageRequest.of(
page.pageNumber,
page.pageSize,
Sort.by(Sort.Direction.DESC, "createdDate")
page.pageNumber,
page.pageSize,
Sort.by(Sort.Direction.DESC, "createdDate")
)

return if (principal.user.sharedAllLibraries) {
Expand All @@ -132,13 +135,13 @@ class SeriesController(
// updated series only, doesn't contain new series
@GetMapping("/updated")
fun getUpdatedSeries(
@AuthenticationPrincipal principal: KomgaPrincipal,
page: Pageable
@AuthenticationPrincipal principal: KomgaPrincipal,
page: Pageable
): Page<SeriesDto> {
val pageRequest = PageRequest.of(
page.pageNumber,
page.pageSize,
Sort.by(Sort.Direction.DESC, "lastModifiedDate")
page.pageNumber,
page.pageSize,
Sort.by(Sort.Direction.DESC, "lastModifiedDate")
)

return if (principal.user.sharedAllLibraries) {
Expand All @@ -150,41 +153,41 @@ class SeriesController(

@GetMapping("{seriesId}")
fun getOneSeries(
@AuthenticationPrincipal principal: KomgaPrincipal,
@PathVariable(name = "seriesId") id: Long
@AuthenticationPrincipal principal: KomgaPrincipal,
@PathVariable(name = "seriesId") id: Long
): SeriesDto =
seriesRepository.findByIdOrNull(id)?.let {
if (!principal.user.canAccessSeries(it)) throw ResponseStatusException(HttpStatus.UNAUTHORIZED)
it.toDto(includeUrl = principal.user.isAdmin())
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
seriesRepository.findByIdOrNull(id)?.let {
if (!principal.user.canAccessSeries(it)) throw ResponseStatusException(HttpStatus.UNAUTHORIZED)
it.toDto(includeUrl = principal.user.isAdmin())
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)

@GetMapping(value = ["{seriesId}/thumbnail"], produces = [MediaType.IMAGE_JPEG_VALUE])
fun getSeriesThumbnail(
@AuthenticationPrincipal principal: KomgaPrincipal,
request: WebRequest,
@PathVariable(name = "seriesId") id: Long
@AuthenticationPrincipal principal: KomgaPrincipal,
request: WebRequest,
@PathVariable(name = "seriesId") id: Long
): ResponseEntity<ByteArray> =
seriesRepository.findByIdOrNull(id)?.let { series ->
if (!principal.user.canAccessSeries(series)) throw ResponseStatusException(HttpStatus.UNAUTHORIZED)
seriesRepository.findByIdOrNull(id)?.let { series ->
if (!principal.user.canAccessSeries(series)) throw ResponseStatusException(HttpStatus.UNAUTHORIZED)

series.books.minBy { it.number }?.let { firstBook ->
bookController.getBookThumbnail(principal, request, firstBook.id)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
series.books.minBy { it.number }?.let { firstBook ->
bookController.getBookThumbnail(principal, request, firstBook.id)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)

@GetMapping("{seriesId}/books")
fun getAllBooksBySeries(
@AuthenticationPrincipal principal: KomgaPrincipal,
@PathVariable(name = "seriesId") id: Long,
@RequestParam(name = "media_status", required = false) mediaStatus: List<Media.Status>?,
page: Pageable
@AuthenticationPrincipal principal: KomgaPrincipal,
@PathVariable(name = "seriesId") id: Long,
@RequestParam(name = "media_status", required = false) mediaStatus: List<Media.Status>?,
page: Pageable
): Page<BookDto> {
seriesRepository.findByIdOrNull(id)?.let {
if (!principal.user.canAccessSeries(it)) throw ResponseStatusException(HttpStatus.UNAUTHORIZED)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)

val pageRequest = PageRequest.of(
page.pageNumber,
page.pageNumber,
page.pageSize,
if (page.sort.isSorted) page.sort
else Sort.by(Sort.Order.asc("number"))
Expand All @@ -208,4 +211,16 @@ class SeriesController(
}
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
}

@PatchMapping("{seriesId}/metadata")
@PreAuthorize("hasRole('ROLE_ADMIN')")
fun updateMetadata(
@PathVariable seriesId: Long,
@RequestBody newMetadata: SeriesMetadataUpdateDto
): SeriesDto =
seriesRepository.findByIdOrNull(seriesId)?.let { series ->
newMetadata.status?.let { series.metadata.status = newMetadata.status }
seriesRepository.save(series).toDto(includeUrl = true)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,16 @@ data class SeriesDto(
val lastModified: LocalDateTime?,
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
val fileLastModified: LocalDateTime,
val booksCount: Int
val booksCount: Int,
val metadata: SeriesMetadataDto
)

data class SeriesMetadataDto(
val status: String,
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
val created: LocalDateTime?,
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
val lastModified: LocalDateTime?
)

fun Series.toDto(includeUrl: Boolean) = SeriesDto(
Expand All @@ -26,5 +35,10 @@ fun Series.toDto(includeUrl: Boolean) = SeriesDto(
created = createdDate?.toUTC(),
lastModified = lastModifiedDate?.toUTC(),
fileLastModified = fileLastModified.toUTC(),
booksCount = books.size
booksCount = books.size,
metadata = SeriesMetadataDto(
status = metadata.status.name,
created = metadata.createdDate?.toUTC(),
lastModified = metadata.lastModifiedDate?.toUTC()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.gotson.komga.interfaces.rest.dto

import org.gotson.komga.domain.model.SeriesMetadata

data class SeriesMetadataUpdateDto(
val status: SeriesMetadata.Status?
)
11 changes: 11 additions & 0 deletions komga/src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ caffeine.jcache {
}
}

cache.series_metadata {
monitoring {
statistics = true
}
policy {
maximum {
size = 500
}
}
}

default-update-timestamps-region {
monitoring {
statistics = true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
create table series_metadata
(
id bigint not null,
created_date timestamp not null,
last_modified_date timestamp not null,
status varchar not null,
primary key (id)
);

alter table series
add (metadata_id bigint);

alter table series
add constraint fk_series_series_metadata_metadata_id foreign key (metadata_id) references series_metadata (id);

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
alter table series
alter column metadata_id set not null;

0 comments on commit f522142

Please sign in to comment.