Skip to content

Commit

Permalink
Reformat
Browse files Browse the repository at this point in the history
  • Loading branch information
Ziedelth committed Dec 21, 2023
1 parent 587d132 commit b90806f
Show file tree
Hide file tree
Showing 51 changed files with 611 additions and 136 deletions.
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ dependencies {
implementation("io.ktor:ktor-server-netty-jvm:$ktor_version")
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-okhttp:$ktor_version")
implementation("io.github.smiley4:ktor-swagger-ui:2.7.2")
implementation("org.hibernate.orm:hibernate-core:6.4.1.Final")
implementation("org.hibernate.search:hibernate-search-mapper-orm:7.1.0.Alpha1")
implementation("org.hibernate.search:hibernate-search-backend-lucene:7.1.0.Alpha1")
Expand All @@ -56,6 +57,7 @@ dependencies {
implementation("com.mortennobel:java-image-scaling:0.8.6")
implementation("io.ktor:ktor-client-okhttp-jvm:2.3.7")
testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")
testImplementation("io.ktor:ktor-client-mock:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
testImplementation("com.h2database:h2:2.2.224")
}
Expand Down
29 changes: 20 additions & 9 deletions src/main/kotlin/fr/shikkanime/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,33 @@ fun main() {

Constant.injector.getInstance(MemberService::class.java).initDefaultAdminUser()

runBlocking {
val httpResponse = HttpRequest().get("https://beta-api.ziedelth.fr/episodes/country/fr/page/1/limit/30")
// Sync episodes from Jais
if (false) {
val episodes = mutableListOf<Episode>()

if (httpResponse.status.isSuccess()) {
val episodes =
AbstractConverter.convert(ObjectParser.fromJson(httpResponse.bodyAsText(), Array<EpisodeDto>::class.java).toList(), Episode::class.java)
episodes.filter { it.uuid == null }.forEach { episodeService.save(it) }
(141 downTo 1).forEach {
runBlocking {
val httpResponse = HttpRequest().get("https://beta-api.ziedelth.fr/episodes/country/fr/page/$it/limit/30")

if (httpResponse.status.isSuccess()) {
episodes.addAll(
AbstractConverter.convert(
ObjectParser.fromJson(httpResponse.bodyAsText(), Array<EpisodeDto>::class.java).toList(),
Episode::class.java
)
)
}
}
}

episodes.filter { it.uuid == null || it.platform?.name != "Disney+" }.forEach { episodeService.save(it) }
}

println("Starting jobs...")
JobManager.scheduleJob("*/10 * * * * ?", MetricJob::class.java)
JobManager.scheduleJob("0 */5 * * * ?", GCJob::class.java)
JobManager.scheduleJob("0 * * * * ?", FetchEpisodesJob::class.java)
JobManager.scheduleJob("0 */5 * * * ?", SavingImageCacheJob::class.java)
JobManager.scheduleJob("0 */15 * * * ?", BackupJob::class.java)
JobManager.scheduleJob("0 0 * * * ?", SavingImageCacheJob::class.java)
JobManager.scheduleJob("0 */10 * * * ?", GarbageCollectorJob::class.java)
JobManager.start()

println("Starting server...")
Expand Down
13 changes: 9 additions & 4 deletions src/main/kotlin/fr/shikkanime/controllers/AdminController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ import fr.shikkanime.dtos.MemberDto
import fr.shikkanime.entities.enums.Link
import fr.shikkanime.services.MemberService
import fr.shikkanime.utils.Constant
import fr.shikkanime.utils.routes.*
import fr.ziedelth.utils.routes.method.Get
import fr.ziedelth.utils.routes.method.Post
import fr.shikkanime.utils.routes.AdminSessionAuthenticated
import fr.shikkanime.utils.routes.Controller
import fr.shikkanime.utils.routes.Path
import fr.shikkanime.utils.routes.Response
import fr.shikkanime.utils.routes.method.Get
import fr.shikkanime.utils.routes.method.Post
import fr.shikkanime.utils.routes.param.BodyParam
import fr.shikkanime.utils.routes.param.QueryParam
import io.ktor.http.*

@Controller("/admin")
Expand All @@ -18,7 +23,7 @@ class AdminController {

@Path
@Get
private fun home(@QueryParam error: String?): Response {
private fun home(@QueryParam("error") error: String?): Response {
return Response.template(
"admin/login.ftl",
"Login",
Expand Down
140 changes: 122 additions & 18 deletions src/main/kotlin/fr/shikkanime/controllers/api/AnimeController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,142 @@ package fr.shikkanime.controllers.api
import com.google.inject.Inject
import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.AnimeDto
import fr.shikkanime.dtos.MessageDto
import fr.shikkanime.entities.SortParameter
import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.services.AnimeService
import fr.shikkanime.services.ImageService
import fr.shikkanime.utils.routes.Cached
import fr.shikkanime.utils.routes.Controller
import fr.shikkanime.utils.routes.Path
import fr.shikkanime.utils.routes.Response
import fr.ziedelth.utils.routes.method.Get
import fr.shikkanime.utils.routes.*
import fr.shikkanime.utils.routes.method.Get
import fr.shikkanime.utils.routes.openapi.OpenAPI
import fr.shikkanime.utils.routes.openapi.OpenAPIResponse
import fr.shikkanime.utils.routes.param.PathParam
import fr.shikkanime.utils.routes.param.QueryParam
import io.ktor.http.*
import java.util.*

@Controller("/api/animes")
@Controller("/api/v1/animes")
class AnimeController {
@Inject
private lateinit var animeService: AnimeService

@Path("/image/{uuid}")
@Path
@Get
@Cached(maxAgeSeconds = 3600)
private fun getImage(uuid: UUID): Response {
val anime = animeService.find(uuid) ?: return Response.notFound("Anime not found")
val image = ImageService[anime.uuid!!] ?: return Response.notFound("Image not found")
return Response.multipart(image.bytes, ContentType.parse("image/webp"))
@OpenAPI(
"Get animes",
[
OpenAPIResponse(
200,
"Animes found",
Array<AnimeDto>::class,
),
OpenAPIResponse(
409,
"You can't use simulcast and name at the same time OR You can't use sort and desc with name",
MessageDto::class
),
]
)
private fun getAll(
@QueryParam("name") name: String?,
@QueryParam("country") countryParam: CountryCode?,
@QueryParam("simulcast") simulcastParam: UUID?,
@QueryParam("page") pageParam: Int?,
@QueryParam("limit") limitParam: Int?,
@QueryParam("sort") sortParam: String?,
@QueryParam("desc") descParam: String?,
): Response {
if (simulcastParam != null && name != null) {
return Response.conflict(
MessageDto(
MessageDto.Type.ERROR,
"You can't use simulcast and name at the same time",
)
)
}

if (name != null && (sortParam != null || descParam != null)) {
return Response.conflict(
MessageDto(
MessageDto.Type.ERROR,
"You can't use sort and desc with name",
)
)
}

val country = countryParam ?: CountryCode.FR
val page = pageParam ?: 1
var limit = limitParam ?: 15
if (limit < 1) limit = 1
if (limit > 30) limit = 30

val sortParameters = mutableListOf<SortParameter>()

if (!sortParam.isNullOrBlank()) {
val sortParams = sortParam.split(",")
val descParams = descParam?.split(",") ?: listOf()

sortParams.forEach { sort ->
val desc = descParams.contains(sort)
sortParameters.add(SortParameter(sort, if (desc) SortParameter.Order.DESC else SortParameter.Order.ASC))
}
}

val list = if (!name.isNullOrBlank()) {
animeService.findByName(name, country, page, limit)
} else if (simulcastParam != null) {
animeService.findBySimulcast(simulcastParam, country, sortParameters, page, limit)
} else {
animeService.findAll(sortParameters, page, limit)
}

return Response.ok(AbstractConverter.convert(list, AnimeDto::class.java))
}

@Path("/search/{countryCode}/{name}")
@Path("/{uuid}")
@Get
private fun searchByCountryCodeAndName(countryCode: CountryCode?, name: String): Response {
if (countryCode == null) {
return Response.badRequest("Country code is null")
}
@OpenAPI(
"Get anime",
[
OpenAPIResponse(
200,
"Anime found",
AnimeDto::class,
),
OpenAPIResponse(
404,
"Anime not found",
MessageDto::class,
),
]
)
private fun getAnime(@PathParam("uuid") uuid: UUID): Response {
val anime = animeService.find(uuid) ?: return Response.notFound(MessageDto(MessageDto.Type.ERROR, "Anime not found"))
return Response.ok(AbstractConverter.convert(anime, AnimeDto::class.java))
}

return Response.ok(AbstractConverter.convert(animeService.findByName(countryCode, name), AnimeDto::class.java))
@Path("/{uuid}/image")
@Get
@Cached(maxAgeSeconds = 3600)
@OpenAPI(
"Get anime image",
[
OpenAPIResponse(
200,
"Image found",
ByteArray::class,
"image/webp"
),
OpenAPIResponse(
404,
"Anime not found OR Anime image not found",
MessageDto::class,
),
]
)
private fun getAnimeImage(@PathParam("uuid") uuid: UUID): Response {
val anime = animeService.find(uuid) ?: return Response.notFound(MessageDto(MessageDto.Type.ERROR, "Anime not found"))
val image = ImageService[anime.uuid!!] ?: return Response.notFound(MessageDto(MessageDto.Type.ERROR, "Anime image not found"))
return Response.multipart(image.bytes, ContentType.parse("image/webp"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package fr.shikkanime.controllers.api

import com.google.inject.Inject
import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.MessageDto
import fr.shikkanime.dtos.MetricDto
import fr.shikkanime.services.MetricService
import fr.shikkanime.utils.routes.AdminSessionAuthenticated
import fr.shikkanime.utils.routes.Controller
import fr.shikkanime.utils.routes.Path
import fr.shikkanime.utils.routes.Response
import fr.ziedelth.utils.routes.method.Get
import fr.shikkanime.utils.routes.method.Get
import fr.shikkanime.utils.routes.openapi.OpenAPI
import fr.shikkanime.utils.routes.openapi.OpenAPIResponse
import java.time.ZonedDateTime

@Controller("/api/metrics")
Expand All @@ -19,6 +22,21 @@ class MetricController {
@Path
@Get
@AdminSessionAuthenticated
@OpenAPI(
"Get metrics",
[
OpenAPIResponse(
200,
"Metrics found",
Array<MetricDto>::class,
),
OpenAPIResponse(
401,
"You are not authenticated",
MessageDto::class
),
]
)
private fun getMetrics(): Response {
val oneHourAgo = ZonedDateTime.now().minusHours(1)
return Response.ok(AbstractConverter.convert(metricService.findAllAfter(oneHourAgo), MetricDto::class.java))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package fr.shikkanime.controllers.api

import com.google.inject.Inject
import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.SimulcastDto
import fr.shikkanime.services.SimulcastService
import fr.shikkanime.utils.routes.*
import fr.shikkanime.utils.routes.method.Get
import fr.shikkanime.utils.routes.openapi.OpenAPI
import fr.shikkanime.utils.routes.openapi.OpenAPIResponse
import io.ktor.http.*
import java.util.*

@Controller("/api/v1/simulcasts")
class SimulcastController {
@Inject
private lateinit var simulcastService: SimulcastService

@Path
@Get
@OpenAPI(
"Get simulcasts",
[
OpenAPIResponse(
200,
"Simulcasts found",
Array<SimulcastDto>::class,
),
]
)
private fun getAll(): Response {
return Response.ok(AbstractConverter.convert(simulcastService.findAll(), SimulcastDto::class.java))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.AnimeDto
import fr.shikkanime.dtos.SimulcastDto
import fr.shikkanime.entities.Anime
import org.hibernate.Hibernate
import java.time.format.DateTimeFormatter

class AnimeToAnimeDtoConverter : AbstractConverter<Anime, AnimeDto>() {
override fun convert(from: Anime): AnimeDto {
return AnimeDto(
uuid = from.uuid,
releaseDateTime = from.releaseDateTime.format(DateTimeFormatter.ISO_DATE_TIME),
image = from.image,
countryCode = from.countryCode!!,
name = from.name!!,
description = from.description,
simulcasts = convert(from.simulcasts, SimulcastDto::class.java)
simulcasts = if (Hibernate.isInitialized(from.simulcasts)) convert(from.simulcasts, SimulcastDto::class.java) else null,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class JaisAnimeToAnimeConverter : AbstractConverter<AnimeDto, Anime>() {
private lateinit var animeService: AnimeService

override fun convert(from: AnimeDto): Anime {
val findByName = animeService.findByName(CountryCode.FR, from.name)
val findByName = animeService.findByLikeName(CountryCode.FR, from.name)

if (findByName.isNotEmpty()) {
return findByName.first()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class MemberToUnsecuredMemberDtoConverter : AbstractConverter<Member, UnsecuredM
uuid = from.uuid,
creationDateTime = from.creationDateTime.format(DateTimeFormatter.ISO_DATE_TIME),
username = from.username!!,
password = from.password!!,
encryptedPassword = from.encryptedPassword!!,
role = from.role,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ class MetricToMetricDtoConverter : AbstractConverter<Metric, MetricDto>() {
@Inject
private lateinit var metricService: MetricService

private fun Double.toDoublePoint() = String.format("%.2f", this)

override fun convert(from: Metric): MetricDto {
val minusHours = from.date.minusHours(1)

Expand All @@ -26,7 +24,6 @@ class MetricToMetricDtoConverter : AbstractConverter<Metric, MetricDto>() {
averageCpuLoad = metricService.getAverageCpuLoad(minusHours, from.date).times(100).toString().replace(',', '.'),
memoryUsage = (from.memoryUsage / 1024.0 / 1024.0).toString().replace(',', '.'),
averageMemoryUsage = metricService.getAverageMemoryUsage(minusHours, from.date).div(1024).div(1024).toString().replace(',', '.'),
databaseSize = (from.databaseSize / 1024.0 / 1024.0).toDoublePoint(),
date = from.date.withZoneSameInstant(utcZone).format(dateFormatter)
)
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/kotlin/fr/shikkanime/dtos/MessageDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package fr.shikkanime.dtos

import java.io.Serializable

data class MessageDto(
val type: Type,
val message: String,
val data: Any? = null,
) : Serializable {
enum class Type {
INFO,
SUCCESS,
WARNING,
ERROR
}
}
Loading

0 comments on commit b90806f

Please sign in to comment.