Skip to content

Commit

Permalink
refactor(backend): move PodcastService to non Reactive API
Browse files Browse the repository at this point in the history
Related to #231
  • Loading branch information
davinkevin committed Aug 3, 2024
1 parent cc55e7e commit c172f34
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 262 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class PodcastHandler(
fun findById(r: ServerRequest): ServerResponse {
val id = r.pathVariable("id").let(UUID::fromString)

val podcast = podcastService.findById(id).block()!!
val podcast = podcastService.findById(id)
?: return ServerResponse.notFound().build()

val body = podcast.toHAL()

Expand All @@ -40,7 +41,6 @@ class PodcastHandler(

fun findAll(@Suppress("UNUSED_PARAMETER") r: ServerRequest): ServerResponse {
val podcasts = podcastService.findAll()
.collectList().block()!!
.map(Podcast::toHAL)

val body = FindAllPodcastHAL(podcasts)
Expand All @@ -52,7 +52,7 @@ class PodcastHandler(
val creationRequest = r.body<PodcastCreationHAL>()
.toPodcastCreation()

val podcast = podcastService.save(creationRequest).block()!!
val podcast = podcastService.save(creationRequest)

return ServerResponse.ok().body(podcast.toHAL())
}
Expand All @@ -61,15 +61,15 @@ class PodcastHandler(
val updateRequest = r.body<PodcastUpdateHAL>()
.toPodcastUpdate()

val podcast = podcastService.update(updateRequest).block()!!
val podcast = podcastService.update(updateRequest)

return ServerResponse.ok().body(podcast.toHAL())
}

fun delete(r: ServerRequest): ServerResponse {
val id = r.pathVariable("id").let(UUID::fromString)

podcastService.deleteById(id).block()
podcastService.deleteById(id)

return ServerResponse.noContent().build()
}
Expand All @@ -78,7 +78,8 @@ class PodcastHandler(
val host = r.extractHost()
val id = r.pathVariable("id").let(UUID::fromString)

val podcast = podcastService.findById(id).block()!!
val podcast = podcastService.findById(id)
?: return ServerResponse.notFound().build()

log.debug("the url of the podcast cover is {}", podcast.cover.url)

Expand All @@ -92,9 +93,9 @@ class PodcastHandler(
return ServerResponse.seeOther(uri).build()
}

fun findStatByPodcastIdAndPubDate(r: ServerRequest): ServerResponse = statsBy(r) { id, number -> podcastService.findStatByPodcastIdAndPubDate(id, number).collectList().block()!! }
fun findStatByPodcastIdAndDownloadDate(r: ServerRequest): ServerResponse = statsBy(r) { id, number -> podcastService.findStatByPodcastIdAndDownloadDate(id, number).collectList().block()!! }
fun findStatByPodcastIdAndCreationDate(r: ServerRequest): ServerResponse = statsBy(r) { id, number -> podcastService.findStatByPodcastIdAndCreationDate(id, number).collectList().block()!! }
fun findStatByPodcastIdAndPubDate(r: ServerRequest): ServerResponse = statsBy(r) { id, number -> podcastService.findStatByPodcastIdAndPubDate(id, number) }
fun findStatByPodcastIdAndDownloadDate(r: ServerRequest): ServerResponse = statsBy(r) { id, number -> podcastService.findStatByPodcastIdAndDownloadDate(id, number) }
fun findStatByPodcastIdAndCreationDate(r: ServerRequest): ServerResponse = statsBy(r) { id, number -> podcastService.findStatByPodcastIdAndCreationDate(id, number) }

private fun statsBy(r: ServerRequest, proj: (id: UUID, n: Int) -> List<NumberOfItemByDateWrapper>): ServerResponse {
val id = UUID.fromString(r.pathVariable("id"))
Expand All @@ -105,9 +106,9 @@ class PodcastHandler(
return ServerResponse.ok().body(stats)
}

fun findStatByTypeAndCreationDate(r: ServerRequest) = statsBy(r) { number -> podcastService.findStatByTypeAndCreationDate(number).collectList().block()!! }
fun findStatByTypeAndPubDate(r: ServerRequest) = statsBy(r) { number -> podcastService.findStatByTypeAndPubDate(number).collectList().block()!! }
fun findStatByTypeAndDownloadDate(r: ServerRequest) = statsBy(r) { number -> podcastService.findStatByTypeAndDownloadDate(number).collectList().block()!! }
fun findStatByTypeAndCreationDate(r: ServerRequest) = statsBy(r) { number -> podcastService.findStatByTypeAndCreationDate(number) }
fun findStatByTypeAndPubDate(r: ServerRequest) = statsBy(r) { number -> podcastService.findStatByTypeAndPubDate(number) }
fun findStatByTypeAndDownloadDate(r: ServerRequest) = statsBy(r) { number -> podcastService.findStatByTypeAndDownloadDate(number) }
private fun statsBy(r: ServerRequest, proj: (n: Int) -> List<StatsPodcastType>): ServerResponse {
val numberOfMonths = r.paramOrNull("numberOfMonths")?.toInt() ?: 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,94 +6,101 @@ import com.github.davinkevin.podcastserver.service.storage.FileStorageService
import com.github.davinkevin.podcastserver.service.storage.MovePodcastRequest
import com.github.davinkevin.podcastserver.tag.Tag
import com.github.davinkevin.podcastserver.tag.TagRepository
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.toFlux
import reactor.kotlin.core.publisher.toMono
import reactor.kotlin.core.util.function.component1
import reactor.kotlin.core.util.function.component2
import java.util.*

class PodcastService(
private val repository: PodcastRepository,
private val coverRepository: CoverRepository,
private val tagRepository: TagRepository,
private val fileService: FileStorageService
private val repository: PodcastRepository,
private val coverRepository: CoverRepository,
private val tagRepository: TagRepository,
private val fileService: FileStorageService
) {

fun findAll(): Flux<Podcast> = repository.findAll()
fun findById(id: UUID): Mono<Podcast> = repository.findById(id)

fun findStatByPodcastIdAndPubDate(id: UUID, numberOfMonths: Int) = repository.findStatByPodcastIdAndPubDate(id, numberOfMonths)
fun findStatByPodcastIdAndDownloadDate(id: UUID, numberOfMonths: Int) = repository.findStatByPodcastIdAndDownloadDate(id, numberOfMonths)
fun findStatByPodcastIdAndCreationDate(id: UUID, numberOfMonths: Int) = repository.findStatByPodcastIdAndCreationDate(id, numberOfMonths)

fun findStatByTypeAndCreationDate(numberOfMonths: Int) = repository.findStatByTypeAndCreationDate(numberOfMonths)
fun findStatByTypeAndPubDate(numberOfMonths: Int) = repository.findStatByTypeAndPubDate(numberOfMonths)
fun findStatByTypeAndDownloadDate(numberOfMonths: Int) = repository.findStatByTypeAndDownloadDate(numberOfMonths)

fun save(p: PodcastForCreation): Mono<Podcast> {

val oldTags = p.tags.toFlux().filter { it.id != null }.map { Tag(it.id!!, it.name) }
val newTags = p.tags.toFlux().filter { it.id == null }.flatMap { Mono.defer { tagRepository.save(it.name).toMono() } }

val tags = Flux.merge(oldTags, newTags).collectList()
val cover = coverRepository.save(p.cover)

return Mono.zip(tags, cover)
.flatMap { (t, c) -> repository.save(
title = p.title,
url = p.url?.toASCIIString(),
hasToBeDeleted = p.hasToBeDeleted,
type = p.type,
tags = t,
cover = c)
}
.delayUntil { fileService.downloadPodcastCover(it) }
fun findAll(): List<Podcast> = repository.findAll().collectList().block()!!
fun findById(id: UUID): Podcast? = repository.findById(id).block()

fun findStatByPodcastIdAndPubDate(id: UUID, numberOfMonths: Int): List<NumberOfItemByDateWrapper> =
repository.findStatByPodcastIdAndPubDate(id, numberOfMonths).collectList().block()!!
fun findStatByPodcastIdAndDownloadDate(id: UUID, numberOfMonths: Int): List<NumberOfItemByDateWrapper> =
repository.findStatByPodcastIdAndDownloadDate(id, numberOfMonths).collectList().block()!!
fun findStatByPodcastIdAndCreationDate(id: UUID, numberOfMonths: Int): List<NumberOfItemByDateWrapper> =
repository.findStatByPodcastIdAndCreationDate(id, numberOfMonths).collectList().block()!!

fun findStatByTypeAndCreationDate(numberOfMonths: Int): List<StatsPodcastType> =
repository.findStatByTypeAndCreationDate(numberOfMonths).collectList().block()!!
fun findStatByTypeAndPubDate(numberOfMonths: Int): List<StatsPodcastType> =
repository.findStatByTypeAndPubDate(numberOfMonths).collectList().block()!!
fun findStatByTypeAndDownloadDate(numberOfMonths: Int): List<StatsPodcastType> =
repository.findStatByTypeAndDownloadDate(numberOfMonths).collectList().block()!!

fun save(p: PodcastForCreation): Podcast {
val oldTags = p.tags.filter { it.id != null }.map { Tag(it.id!!, it.name) }
val newTags = p.tags.filter { it.id == null }.map { tagRepository.save(it.name) }

val tags = oldTags + newTags
val cover = coverRepository.save(p.cover).block()!!

val podcast = repository.save(
title = p.title,
url = p.url?.toASCIIString(),
hasToBeDeleted = p.hasToBeDeleted,
type = p.type,
tags = tags,
cover = cover
).block()!!

fileService.downloadPodcastCover(podcast).block()

return podcast
}

fun update(updatePodcast: PodcastForUpdate): Mono<Podcast> = findById(updatePodcast.id).flatMap { p ->
fun update(updatePodcast: PodcastForUpdate): Podcast {
val p = findById(updatePodcast.id)
?: error("Trying to upgrade a non existent podcast")

val oldTags = updatePodcast.tags.toFlux().filter { it.id != null }.map { Tag(it.id!!, it.name) }
val newTags = updatePodcast.tags.toFlux().filter { it.id == null }.flatMap { Mono.defer { tagRepository.save(it.name).toMono() } }
val tags = Flux.merge(oldTags, newTags).collectList()
val oldTags = updatePodcast.tags.filter { it.id != null }.map { Tag(it.id!!, it.name) }
val newTags = updatePodcast.tags.filter { it.id == null }.map { tagRepository.save(it.name) }
val tags = oldTags + newTags

val newCover = updatePodcast.cover
val oldCover = p.cover
val cover =
if (!newCover.url.toASCIIString().startsWith("/") && oldCover.url != newCover.url)
coverRepository.save(newCover).delayUntil {
fileService.downloadPodcastCover(p.copy(cover = Cover(it.id, it.url, it.height, it.width)))
}
else Cover(oldCover.id, oldCover.url, oldCover.height, oldCover.width).toMono()

val title =
if (p.title != updatePodcast.title) {
val movePodcastDetails = MovePodcastRequest(
id = updatePodcast.id,
from = p.title,
to = updatePodcast.title
)
fileService.movePodcast(movePodcastDetails)
} else Mono.empty()

Mono.zip(tags, cover)
.flatMap { (t, c) ->
repository.update(
id = updatePodcast.id,
title = updatePodcast.title,
url = updatePodcast.url?.toASCIIString(),
hasToBeDeleted = updatePodcast.hasToBeDeleted,
tags = t,
cover = c)
}
.delayUntil { title }

val isLocalCover = newCover.url.toASCIIString().startsWith("/")
val coversAreIdentical = oldCover.url != newCover.url
val cover = if (!isLocalCover && coversAreIdentical)
coverRepository.save(newCover).block()!!.also {
fileService
.downloadPodcastCover(p.copy(cover = Cover(it.id, it.url, it.height, it.width)))
.block()
}
else Cover(oldCover.id, oldCover.url, oldCover.height, oldCover.width)

val podcast = repository.update(
id = updatePodcast.id,
title = updatePodcast.title,
url = updatePodcast.url?.toASCIIString(),
hasToBeDeleted = updatePodcast.hasToBeDeleted,
tags = tags,
cover = cover
).block()!!

val podcastTitleHasChanged = p.title != updatePodcast.title
if (podcastTitleHasChanged) {
val movePodcastDetails = MovePodcastRequest(
id = updatePodcast.id,
from = p.title,
to = updatePodcast.title
)
fileService.movePodcast(movePodcastDetails).block()
}

return podcast
}

fun deleteById(id: UUID): Mono<Void> =
repository
.deleteById(id)
.delayUntil { fileService.deletePodcast(it) }
.then()
fun deleteById(id: UUID) {
repository
.deleteById(id)
.delayUntil { fileService.deletePodcast(it) }
.block()
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class PodcastXmlHandler(
fun opml(r: ServerRequest): ServerResponse {
val host = r.extractHost()

val podcasts = podcastService.findAll().collectList().block()!!
val podcasts = podcastService.findAll()

val outlines = podcasts
.map { OpmlOutline(OpmlOutline.Podcast(it.id, it.title, it.description), host) }
Expand Down Expand Up @@ -59,7 +59,8 @@ class PodcastXmlHandler(
page = itemPageable,
podcastId = podcastId
)
val podcast = podcastService.findById(podcastId).block()!!
val podcast = podcastService.findById(podcastId)
?: return ServerResponse.notFound().build()

val items = page.content.map { it.toRssItem(host) }
val rss = podcast.toRssChannel(callUrl)
Expand Down
Loading

0 comments on commit c172f34

Please sign in to comment.