mirror of
https://github.com/gotson/komga.git
synced 2025-12-21 16:03:03 +01:00
parent
2f7d2a447f
commit
3ca50d7b34
5 changed files with 49 additions and 19 deletions
|
|
@ -28,6 +28,7 @@ class SeriesDtoDao(
|
|||
private val s = Tables.SERIES
|
||||
private val b = Tables.BOOK
|
||||
private val d = Tables.SERIES_METADATA
|
||||
private val r = Tables.READ_PROGRESS
|
||||
|
||||
private val groupFields = arrayOf(
|
||||
*s.fields(),
|
||||
|
|
@ -40,28 +41,29 @@ class SeriesDtoDao(
|
|||
"lastModifiedDate" to s.LAST_MODIFIED_DATE
|
||||
)
|
||||
|
||||
override fun findAll(search: SeriesSearch, pageable: Pageable): Page<SeriesDto> {
|
||||
override fun findAll(search: SeriesSearch, userId: Long, pageable: Pageable): Page<SeriesDto> {
|
||||
val conditions = search.toCondition()
|
||||
|
||||
return findAll(conditions, pageable)
|
||||
return findAll(conditions, userId, pageable)
|
||||
}
|
||||
|
||||
override fun findRecentlyUpdated(search: SeriesSearch, pageable: Pageable): Page<SeriesDto> {
|
||||
override fun findRecentlyUpdated(search: SeriesSearch, userId: Long, pageable: Pageable): Page<SeriesDto> {
|
||||
val conditions = search.toCondition()
|
||||
.and(s.CREATED_DATE.ne(s.LAST_MODIFIED_DATE))
|
||||
|
||||
return findAll(conditions, pageable)
|
||||
return findAll(conditions, userId, pageable)
|
||||
}
|
||||
|
||||
override fun findByIdOrNull(seriesId: Long): SeriesDto? =
|
||||
override fun findByIdOrNull(seriesId: Long, userId: Long): SeriesDto? =
|
||||
selectBase()
|
||||
.where(s.ID.eq(seriesId))
|
||||
.and(readProgressCondition(userId))
|
||||
.groupBy(*groupFields)
|
||||
.fetchAndMap()
|
||||
.firstOrNull()
|
||||
|
||||
|
||||
private fun findAll(conditions: Condition, pageable: Pageable): Page<SeriesDto> {
|
||||
private fun findAll(conditions: Condition, userId: Long, pageable: Pageable): Page<SeriesDto> {
|
||||
val count = dsl.selectCount()
|
||||
.from(s)
|
||||
.leftJoin(d).on(s.ID.eq(d.SERIES_ID))
|
||||
|
|
@ -72,6 +74,7 @@ class SeriesDtoDao(
|
|||
|
||||
val dtos = selectBase()
|
||||
.where(conditions)
|
||||
.and(readProgressCondition(userId))
|
||||
.groupBy(*groupFields)
|
||||
.orderBy(orderBy)
|
||||
.limit(pageable.pageSize)
|
||||
|
|
@ -87,18 +90,23 @@ class SeriesDtoDao(
|
|||
|
||||
private fun selectBase() =
|
||||
dsl.select(*groupFields)
|
||||
.select(DSL.count(b.ID).`as`("bookCount"))
|
||||
.select(DSL.count(b.ID).`as`("booksCount"))
|
||||
.select(DSL.count(r.COMPLETED).`as`("booksReadCount"))
|
||||
.from(s)
|
||||
.leftJoin(b).on(s.ID.eq(b.SERIES_ID))
|
||||
.leftJoin(d).on(s.ID.eq(d.SERIES_ID))
|
||||
.leftJoin(r).on(b.ID.eq(r.BOOK_ID))
|
||||
|
||||
private fun readProgressCondition(userId: Long): Condition = r.USER_ID.eq(userId).or(r.USER_ID.isNull)
|
||||
|
||||
private fun ResultQuery<Record>.fetchAndMap() =
|
||||
fetch()
|
||||
.map { r ->
|
||||
val sr = r.into(s)
|
||||
val dr = r.into(d)
|
||||
val bookCount = r["bookCount"] as Int
|
||||
sr.toDto(bookCount, dr.toDto())
|
||||
val booksCount = r["booksCount"] as Int
|
||||
val booksReadCount = r["booksReadCount"] as Int
|
||||
sr.toDto(booksCount, booksReadCount, dr.toDto())
|
||||
}
|
||||
|
||||
private fun SeriesSearch.toCondition(): Condition {
|
||||
|
|
@ -111,7 +119,7 @@ class SeriesDtoDao(
|
|||
return c
|
||||
}
|
||||
|
||||
private fun SeriesRecord.toDto(bookCount: Int, metadata: SeriesMetadataDto) =
|
||||
private fun SeriesRecord.toDto(booksCount: Int, booksReadCount: Int, metadata: SeriesMetadataDto) =
|
||||
SeriesDto(
|
||||
id = id,
|
||||
libraryId = libraryId,
|
||||
|
|
@ -120,7 +128,8 @@ class SeriesDtoDao(
|
|||
created = createdDate.toUTC(),
|
||||
lastModified = lastModifiedDate.toUTC(),
|
||||
fileLastModified = fileLastModified.toUTC(),
|
||||
booksCount = bookCount,
|
||||
booksCount = booksCount,
|
||||
booksReadCount = booksReadCount,
|
||||
metadata = metadata
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class SeriesController(
|
|||
metadataStatus = metadataStatus ?: emptyList()
|
||||
)
|
||||
|
||||
return seriesDtoRepository.findAll(seriesSearch, pageRequest)
|
||||
return seriesDtoRepository.findAll(seriesSearch, principal.user.id, pageRequest)
|
||||
.map { it.restrictUrl(!principal.user.roleAdmin) }
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +104,7 @@ class SeriesController(
|
|||
|
||||
return seriesDtoRepository.findAll(
|
||||
SeriesSearch(libraryIds = libraryIds),
|
||||
principal.user.id,
|
||||
pageRequest
|
||||
).map { it.restrictUrl(!principal.user.roleAdmin) }
|
||||
}
|
||||
|
|
@ -125,6 +126,7 @@ class SeriesController(
|
|||
|
||||
return seriesDtoRepository.findAll(
|
||||
SeriesSearch(libraryIds = libraryIds),
|
||||
principal.user.id,
|
||||
pageRequest
|
||||
).map { it.restrictUrl(!principal.user.roleAdmin) }
|
||||
}
|
||||
|
|
@ -146,6 +148,7 @@ class SeriesController(
|
|||
|
||||
return seriesDtoRepository.findRecentlyUpdated(
|
||||
SeriesSearch(libraryIds = libraryIds),
|
||||
principal.user.id,
|
||||
pageRequest
|
||||
).map { it.restrictUrl(!principal.user.roleAdmin) }
|
||||
}
|
||||
|
|
@ -155,7 +158,7 @@ class SeriesController(
|
|||
@AuthenticationPrincipal principal: KomgaPrincipal,
|
||||
@PathVariable(name = "seriesId") id: Long
|
||||
): SeriesDto =
|
||||
seriesDtoRepository.findByIdOrNull(id)?.let {
|
||||
seriesDtoRepository.findByIdOrNull(id, principal.user.id)?.let {
|
||||
if (!principal.user.canAccessLibrary(it.libraryId)) throw ResponseStatusException(HttpStatus.UNAUTHORIZED)
|
||||
it.restrictUrl(!principal.user.roleAdmin)
|
||||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
|
|
@ -227,7 +230,8 @@ class SeriesController(
|
|||
fun updateMetadata(
|
||||
@PathVariable seriesId: Long,
|
||||
@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: SeriesMetadataUpdateDto
|
||||
@Valid @RequestBody newMetadata: SeriesMetadataUpdateDto,
|
||||
@AuthenticationPrincipal principal: KomgaPrincipal
|
||||
): SeriesDto =
|
||||
seriesMetadataRepository.findByIdOrNull(seriesId)?.let { existing ->
|
||||
val updated = with(newMetadata) {
|
||||
|
|
@ -241,7 +245,7 @@ class SeriesController(
|
|||
)
|
||||
}
|
||||
seriesMetadataRepository.update(updated)
|
||||
seriesDtoRepository.findByIdOrNull(seriesId)!!
|
||||
seriesDtoRepository.findByIdOrNull(seriesId, principal.user.id)!!
|
||||
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
|
||||
|
||||
@PostMapping("{seriesId}/read-progress")
|
||||
|
|
|
|||
|
|
@ -15,8 +15,11 @@ data class SeriesDto(
|
|||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
val fileLastModified: LocalDateTime,
|
||||
val booksCount: Int,
|
||||
val booksReadCount: Int,
|
||||
val metadata: SeriesMetadataDto
|
||||
)
|
||||
) {
|
||||
val booksUnreadCount: Int = booksCount - booksReadCount
|
||||
}
|
||||
|
||||
fun SeriesDto.restrictUrl(restrict: Boolean) =
|
||||
if (restrict) copy(url = "") else this
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import org.springframework.data.domain.Page
|
|||
import org.springframework.data.domain.Pageable
|
||||
|
||||
interface SeriesDtoRepository {
|
||||
fun findAll(search: SeriesSearch, pageable: Pageable): Page<SeriesDto>
|
||||
fun findRecentlyUpdated(search: SeriesSearch, pageable: Pageable): Page<SeriesDto>
|
||||
fun findByIdOrNull(seriesId: Long): SeriesDto?
|
||||
fun findAll(search: SeriesSearch, userId: Long, pageable: Pageable): Page<SeriesDto>
|
||||
fun findRecentlyUpdated(search: SeriesSearch, userId: Long, pageable: Pageable): Page<SeriesDto>
|
||||
fun findByIdOrNull(seriesId: Long, userId: Long): SeriesDto?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -510,6 +510,13 @@ class SeriesControllerTest(
|
|||
status { isNoContent }
|
||||
}
|
||||
|
||||
mockMvc.get("/api/v1/series/${series.id}")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
jsonPath("$.booksUnreadCount") { value(0) }
|
||||
jsonPath("$.booksReadCount") { value(2) }
|
||||
}
|
||||
|
||||
mockMvc.get("/api/v1/series/${series.id}/books")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
|
|
@ -548,6 +555,13 @@ class SeriesControllerTest(
|
|||
status { isNoContent }
|
||||
}
|
||||
|
||||
mockMvc.get("/api/v1/series/${series.id}")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
jsonPath("$.booksUnreadCount") { value(2) }
|
||||
jsonPath("$.booksReadCount") { value(0) }
|
||||
}
|
||||
|
||||
mockMvc.get("/api/v1/series/${series.id}/books")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
|
|
|
|||
Loading…
Reference in a new issue