Include pagination with types in rankings and directory

v5 v5.3.0
Jéluchu 7 months ago
parent 5d1b33e1e8
commit df6baa761b

@ -8,10 +8,13 @@ sealed class ErrorMessages(val message: String) {
data object InvalidMalId : ErrorMessages("The provided id of malId is invalid")
data object InvalidDay : ErrorMessages("Invalid 'day' parameter. Valid values are: ${Day.entries.joinToString(", ") { it.name.lowercase() }}")
data object InvalidAnimeType : ErrorMessages("Invalid 'type' parameter. Valid values are: ${AnimeTypes.entries.joinToString(", ") { it.name.lowercase() }}")
data object InvalidMangaType : ErrorMessages("Invalid 'type' parameter. Valid values are: ${MangaTypes.entries.joinToString(", ") { it.name.lowercase() }}")
data object InvalidSizeAndPage : ErrorMessages("Invalid page and size parameters")
data object InvalidTopAnimeType : ErrorMessages("Invalid 'type' parameter. Valid values are: $animeTypesErrorList")
data object InvalidTopAnimeFilterType : ErrorMessages("Invalid 'type' parameter. Valid values are: $animeFilterTypesErrorList")
data object InvalidTopMangaType : ErrorMessages("Invalid 'type' parameter. Valid values are: $mangaTypesErrorList")
data object InvalidTopMangaFilterType : ErrorMessages("Invalid 'type' parameter. Valid values are: $mangaFilterTypesErrorList")
data object InvalidInput : ErrorMessages("Invalid input provided")
data object InvalidValueTopPage : ErrorMessages("Value 26 is higher than the configured '25' max value")
data object UnauthorizedMongo : ErrorMessages("Check the MongoDb Connection String to be able to correctly access this request.")
}

@ -0,0 +1,12 @@
package com.jeluchu.core.models
import kotlinx.serialization.Serializable
@Serializable
data class PaginationResponse<T>(
val page: Int = 0,
val size: Int = 0,
val totalPages: Int = 0,
val totalItems: Int = 0,
val data: List<T> = emptyList()
)

@ -37,7 +37,7 @@ data class CharacterData(
top: String
) = CharacterTopEntity(
malId = malId,
image = images?.webp?.large.orEmpty(),
image = images?.jpg?.generic.orEmpty(),
name = name,
nameKanji = nameKanji,
top = top,

@ -46,7 +46,7 @@ data class PeopleData(
top: String
) = PeopleTopEntity(
malId = malId,
image = images?.webp?.large.orEmpty(),
image = images?.jpg?.generic.orEmpty(),
name = name,
givenName = givenName,
familyName = familyName,

@ -29,7 +29,7 @@ object Routes {
const val CHARACTER = "/characters"
const val LAST_EPISODES = "/lastEpisodes"
const val ID = "/{id}"
const val TYPE = "/{type}"
const val ANIME_TYPE = "/{type}"
const val DAY = "/{day}"
const val TOP_CHARACTER = "/top/character"
const val RANKINGS = "/{type}/{filter}/{page}"

@ -6,9 +6,11 @@ import com.jeluchu.features.anime.models.anime.*
import com.jeluchu.features.anime.models.directory.AnimeDirectoryEntity
import com.jeluchu.features.anime.models.directory.AnimeTypeEntity
import com.jeluchu.features.rankings.models.AnimeTopEntity
import com.jeluchu.features.rankings.models.CharacterTopEntity
import com.jeluchu.features.rankings.models.MangaTopEntity
import com.jeluchu.features.rankings.models.PeopleTopEntity
import com.jeluchu.features.schedule.models.DayEntity
import org.bson.Document
import java.sql.Timestamp
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
@ -231,7 +233,7 @@ fun documentToScheduleDayEntity(doc: Document) = DayEntity(
title = doc.getStringSafe("title")
)
fun documentToTopEntity(doc: Document) = AnimeTopEntity(
fun documentToAnimeTopEntity(doc: Document) = AnimeTopEntity(
malId = doc.getIntSafe("malId"),
rank = doc.getIntSafe("rank"),
score = doc.getFloatSafe("score"),
@ -247,6 +249,41 @@ fun documentToTopEntity(doc: Document) = AnimeTopEntity(
page = doc.getIntSafe("page"),
)
fun documentToMangaTopEntity(doc: Document) = MangaTopEntity(
malId = doc.getIntSafe("malId"),
rank = doc.getIntSafe("rank"),
score = doc.getDoubleSafe("score"),
title = doc.getStringSafe("title"),
image = doc.getStringSafe("image"),
url = doc.getStringSafe("url"),
volumes = doc.getIntSafe("volumes"),
chapters = doc.getIntSafe("chapters"),
status = doc.getStringSafe("status"),
type = doc.getStringSafe("type"),
subtype = doc.getStringSafe("subtype"),
page = doc.getIntSafe("page"),
)
fun documentToPeopleTopEntity(doc: Document) = PeopleTopEntity(
malId = doc.getIntSafe("malId"),
name = doc.getStringSafe("name"),
givenName = doc.getStringSafe("givenName"),
familyName = doc.getStringSafe("familyName"),
image = doc.getStringSafe("image"),
birthday = doc.getStringSafe("birthday"),
page = doc.getIntSafe("page"),
top = doc.getStringSafe("top"),
)
fun documentToCharacterTopEntity(doc: Document) = CharacterTopEntity(
malId = doc.getIntSafe("malId"),
name = doc.getStringSafe("name"),
nameKanji = doc.getStringSafe("nameKanji"),
image = doc.getStringSafe("image"),
top = doc.getStringSafe("top"),
page = doc.getIntSafe("page"),
)
fun documentToAnimeTypeEntity(doc: Document) = AnimeTypeEntity(
score = doc.getString("score"),
malId = doc.getIntSafe("malId"),

@ -19,6 +19,6 @@ fun Route.animeEndpoints(
route(Routes.DIRECTORY) {
getToJson { service.getDirectory(call) }
getToJson(Routes.TYPE) { directoryService.getAnimeByType(call) }
getToJson(Routes.ANIME_TYPE) { directoryService.getAnimeByType(call) }
}
}

@ -1,12 +1,15 @@
package com.jeluchu.features.anime.services
import com.jeluchu.core.connection.RestClient
import com.jeluchu.core.enums.AnimeTypes
import com.jeluchu.core.enums.Day
import com.jeluchu.core.enums.TimeUnit
import com.jeluchu.core.enums.parseAnimeType
import com.jeluchu.core.extensions.needsUpdate
import com.jeluchu.core.extensions.update
import com.jeluchu.core.messages.ErrorMessages
import com.jeluchu.core.models.ErrorResponse
import com.jeluchu.core.models.PaginationResponse
import com.jeluchu.core.models.animeflv.lastepisodes.LastEpisodeData.Companion.toEpisodeEntity
import com.jeluchu.core.models.animeflv.lastepisodes.LastEpisodes
import com.jeluchu.core.models.jikan.anime.AnimeData.Companion.toDayEntity
@ -14,10 +17,7 @@ import com.jeluchu.core.utils.BaseUrls
import com.jeluchu.core.utils.Collections
import com.jeluchu.core.utils.Endpoints
import com.jeluchu.core.utils.TimerKey
import com.jeluchu.features.anime.mappers.documentToAnimeDirectoryEntity
import com.jeluchu.features.anime.mappers.documentToLastEpisodesEntity
import com.jeluchu.features.anime.mappers.documentToMoreInfoEntity
import com.jeluchu.features.anime.mappers.documentToScheduleDayEntity
import com.jeluchu.features.anime.mappers.*
import com.jeluchu.features.schedule.models.ScheduleEntity
import com.mongodb.client.MongoDatabase
import com.mongodb.client.model.Filters
@ -36,10 +36,46 @@ class AnimeService(
private val lastEpisodesCollection = database.getCollection(Collections.LAST_EPISODES)
suspend fun getDirectory(call: RoutingCall) = try {
val elements = directoryCollection.find().toList()
val directory = elements.map { documentToAnimeDirectoryEntity(it) }
val json = Json.encodeToString(directory)
call.respond(HttpStatusCode.OK, json)
val type = call.request.queryParameters["type"].orEmpty()
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1
val size = call.request.queryParameters["size"]?.toIntOrNull() ?: 10
if (page < 1 || size < 1) call.respond(HttpStatusCode.BadRequest, ErrorMessages.InvalidSizeAndPage.message)
val skipCount = (page - 1) * size
if (parseAnimeType(type) == null) {
val animes = directoryCollection
.find()
.skip(skipCount)
.limit(size)
.toList()
val elements = animes.map { documentToAnimeDirectoryEntity(it) }
val response = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
} else {
val animes = directoryCollection
.find(Filters.eq("type", type.uppercase()))
.skip(skipCount)
.limit(size)
.toList()
val elements = animes.map { documentToAnimeTypeEntity(it) }
val response = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
}
} catch (ex: Exception) {
call.respond(HttpStatusCode.Unauthorized, ErrorResponse(ErrorMessages.UnauthorizedMongo.message))
}
@ -87,5 +123,10 @@ class AnimeService(
val directory = map { documentToLastEpisodesEntity(it) }
return Json.encodeToString(directory)
}
private fun List<Document>.documentAnimeTypeMapper(): String {
val directory = map { documentToAnimeTypeEntity(it) }
return Json.encodeToString(directory)
}
}

@ -6,6 +6,7 @@ import com.jeluchu.core.extensions.needsUpdate
import com.jeluchu.core.extensions.update
import com.jeluchu.core.messages.ErrorMessages
import com.jeluchu.core.models.ErrorResponse
import com.jeluchu.core.models.PaginationResponse
import com.jeluchu.core.utils.Collections
import com.jeluchu.core.utils.TimerKey
import com.jeluchu.features.anime.mappers.documentToAnimeTypeEntity
@ -25,7 +26,13 @@ class DirectoryService(
private val directory = database.getCollection(Collections.ANIME_DETAILS)
suspend fun getAnimeByType(call: RoutingCall) {
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1
val size = call.request.queryParameters["size"]?.toIntOrNull() ?: 10
val param = call.parameters["type"] ?: throw IllegalArgumentException(ErrorMessages.InvalidAnimeType.message)
if (page < 1 || size < 1) call.respond(HttpStatusCode.BadRequest, ErrorMessages.InvalidSizeAndPage.message)
val skipCount = (page - 1) * size
if (parseAnimeType(param) == null) call.respond(
HttpStatusCode.BadRequest,
ErrorResponse(ErrorMessages.InvalidAnimeType.message)
@ -42,16 +49,39 @@ class DirectoryService(
val collection = database.getCollection(timerKey)
collection.deleteMany(Document())
val animes = directory.find(Filters.eq("type", param.uppercase())).toList()
val animes = directory
.find(Filters.eq("type", param.uppercase()))
.skip(skipCount)
.limit(size)
.toList()
val animeTypes = animes.map { documentToAnimeTypeEntity(it) }
val documents = animeTypes.map { anime -> Document.parse(Json.encodeToString(anime)) }
if (documents.isNotEmpty()) collection.insertMany(documents)
timers.update(timerKey)
call.respond(HttpStatusCode.OK, Json.encodeToString(animeTypes))
val response = PaginationResponse(
page = page,
size = size,
data = animeTypes,
totalItems = directory.countDocuments().toInt()
)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
} else {
val elements = directory.find().toList()
call.respond(HttpStatusCode.OK, elements.documentAnimeTypeMapper())
val elements = directory.find()
.skip(skipCount)
.limit(size)
.toList()
val response = PaginationResponse(
page = page,
size = size,
totalItems = directory.countDocuments().toInt(),
data = elements.map { documentToAnimeTypeEntity(it) }
)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
}
}

@ -11,15 +11,15 @@ fun Route.rankingsEndpoints(
service: RankingsService = RankingsService(mongoDatabase)
) = route(Routes.TOP) {
route(Routes.ANIME) {
getToJson(Routes.RANKINGS) { service.getAnimeRanking(call) }
getToJson { service.getAnimeRanking(call) }
}
route(Routes.MANGA) {
getToJson(Routes.RANKINGS) { service.getMangaRanking(call) }
getToJson { service.getMangaRanking(call) }
}
route(Routes.PEOPLE) {
getToJson(Routes.PAGE) { service.getPeopleRanking(call) }
getToJson { service.getPeopleRanking(call) }
}
route(Routes.CHARACTER) {
getToJson(Routes.PAGE) { service.getCharacterRanking(call) }
getToJson { service.getCharacterRanking(call) }
}
}

@ -6,6 +6,7 @@ import com.jeluchu.core.extensions.needsUpdate
import com.jeluchu.core.extensions.update
import com.jeluchu.core.messages.ErrorMessages
import com.jeluchu.core.models.ErrorResponse
import com.jeluchu.core.models.PaginationResponse
import com.jeluchu.core.models.jikan.anime.AnimeData.Companion.toAnimeTopEntity
import com.jeluchu.core.models.jikan.character.CharacterSearch
import com.jeluchu.core.models.jikan.manga.MangaData.Companion.toMangaTopEntity
@ -17,7 +18,10 @@ import com.jeluchu.core.utils.BaseUrls
import com.jeluchu.core.utils.Collections
import com.jeluchu.core.utils.Endpoints
import com.jeluchu.core.utils.parseDataToDocuments
import com.jeluchu.features.anime.mappers.documentToTopEntity
import com.jeluchu.features.anime.mappers.documentToAnimeTopEntity
import com.jeluchu.features.anime.mappers.documentToCharacterTopEntity
import com.jeluchu.features.anime.mappers.documentToMangaTopEntity
import com.jeluchu.features.anime.mappers.documentToPeopleTopEntity
import com.jeluchu.features.rankings.models.AnimeTopEntity
import com.jeluchu.features.rankings.models.CharacterTopEntity
import com.jeluchu.features.rankings.models.MangaTopEntity
@ -41,13 +45,15 @@ class RankingsService(
private val characterRanking = database.getCollection(Collections.CHARACTER_RANKING)
suspend fun getAnimeRanking(call: RoutingCall) {
val paramType = call.parameters["type"] ?: throw IllegalArgumentException(ErrorMessages.InvalidTopAnimeType.message)
val paramPage = call.parameters["page"]?.toInt() ?: throw IllegalArgumentException(ErrorMessages.InvalidMalId.message)
val paramFilter = call.parameters["filter"] ?: throw IllegalArgumentException(ErrorMessages.InvalidTopAnimeFilterType.message)
if (parseAnimeType(paramType) == null) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidTopAnimeType.message))
if (parseAnimeFilterType(paramFilter) == null) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidTopAnimeFilterType.message))
val filter = call.request.queryParameters["filter"] ?: "airing"
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1
val size = call.request.queryParameters["size"]?.toIntOrNull() ?: 25
val type = call.parameters["type"] ?: throw IllegalArgumentException(ErrorMessages.InvalidTopAnimeType.message)
val timerKey = "${Collections.ANIME_RANKING}_${paramType}_${paramFilter}_${paramPage}"
if (size > 25) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidValueTopPage.message))
if (parseAnimeType(type) == null) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidTopAnimeType.message))
val timerKey = "${Collections.ANIME_RANKING}_${type}_${filter}_${page}"
val needsUpdate = timers.needsUpdate(
amount = 30,
@ -55,19 +61,22 @@ class RankingsService(
unit = TimeUnit.DAY
)
if (page < 1 || size < 1) call.respond(HttpStatusCode.BadRequest, ErrorMessages.InvalidSizeAndPage.message)
val skipCount = (page - 1) * size
if (needsUpdate) {
animeRanking.deleteMany(
Filters.and(
Filters.eq("page", paramPage),
Filters.eq("type", paramType),
Filters.eq("subtype", paramFilter)
Filters.eq("page", page),
Filters.eq("type", type),
Filters.eq("subtype", filter)
)
)
val params = mutableListOf<String>()
params.add("type=$paramType")
params.add("page=$paramPage")
params.add("filter=$paramFilter")
params.add("type=$type")
params.add("page=$page")
params.add("filter=$filter")
val response = RestClient.request(
BaseUrls.JIKAN + Endpoints.TOP_ANIME + "?${params.joinToString("&")}",
@ -75,9 +84,9 @@ class RankingsService(
).data?.map { anime ->
anime.toAnimeTopEntity(
top = "anime",
page = paramPage,
type = paramType,
subType = paramFilter
page = page,
type = type,
subType = filter
)
}
@ -85,42 +94,66 @@ class RankingsService(
if (documentsToInsert.isNotEmpty()) animeRanking.insertMany(documentsToInsert)
timers.update(timerKey)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
val elements = documentsToInsert.map { documentToAnimeTopEntity(it) }
val paginationResponse = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(paginationResponse))
} else {
val elements = animeRanking.find().toList()
val directory = elements.map { documentToTopEntity(it) }
val json = Json.encodeToString(directory)
call.respond(HttpStatusCode.OK, json)
val animes = animeRanking
.find(Filters.eq("type", type.lowercase()))
.skip(skipCount)
.limit(size)
.toList()
val elements = animes.map { documentToAnimeTopEntity(it) }
val response = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
}
}
suspend fun getMangaRanking(call: RoutingCall) {
val paramType = call.parameters["type"] ?: throw IllegalArgumentException(ErrorMessages.InvalidTopMangaType.message)
val paramPage = call.parameters["page"]?.toInt() ?: throw IllegalArgumentException(ErrorMessages.InvalidMalId.message)
val paramFilter = call.parameters["filter"] ?: throw IllegalArgumentException(ErrorMessages.InvalidTopMangaFilterType.message)
if (parseMangaType(paramType) == null) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidTopMangaType.message))
if (parseMangaFilterType(paramFilter) == null) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidTopMangaFilterType.message))
val filter = call.request.queryParameters["filter"] ?: "publishing"
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1
val size = call.request.queryParameters["size"]?.toIntOrNull() ?: 25
val type = call.parameters["type"] ?: throw IllegalArgumentException(ErrorMessages.InvalidTopMangaType.message)
if (size > 25) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidValueTopPage.message))
if (parseMangaType(type) == null) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidTopAnimeType.message))
val timerKey = "${Collections.MANGA_RANKING}_${type}_${filter}_${page}"
val timerKey = "${Collections.MANGA_RANKING}_${paramType}_${paramFilter}_${paramPage}"
val needsUpdate = timers.needsUpdate(
amount = 30,
key = timerKey,
unit = TimeUnit.DAY
)
if (page < 1 || size < 1) call.respond(HttpStatusCode.BadRequest, ErrorMessages.InvalidSizeAndPage.message)
val skipCount = (page - 1) * size
if (needsUpdate) {
mangaRanking.deleteMany(
Filters.and(
Filters.eq("page", paramPage),
Filters.eq("type", paramType),
Filters.eq("subtype", paramFilter)
Filters.eq("page", page),
Filters.eq("type", type),
Filters.eq("subtype", filter)
)
)
val params = mutableListOf<String>()
params.add("type=$paramType")
params.add("page=$paramPage")
params.add("filter=$paramFilter")
params.add("type=$type")
params.add("page=$page")
params.add("filter=$filter")
val response = RestClient.request(
BaseUrls.JIKAN + Endpoints.TOP_MANGA + "?${params.joinToString("&")}",
@ -128,9 +161,9 @@ class RankingsService(
).data?.map { anime ->
anime.toMangaTopEntity(
top = "manga",
page = paramPage,
type = paramType,
subType = paramFilter
page = page,
type = type,
subType = filter
)
}
@ -138,32 +171,58 @@ class RankingsService(
if (documentsToInsert.isNotEmpty()) mangaRanking.insertMany(documentsToInsert)
timers.update(timerKey)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
val elements = documentsToInsert.map { documentToMangaTopEntity(it) }
val paginationResponse = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(paginationResponse))
} else {
val elements = mangaRanking.find().toList()
val directory = elements.map { documentToTopEntity(it) }
val json = Json.encodeToString(directory)
call.respond(HttpStatusCode.OK, json)
val mangas = mangaRanking
.find(Filters.eq("type", type.lowercase()))
.skip(skipCount)
.limit(size)
.toList()
val elements = mangas.map { documentToMangaTopEntity(it) }
val response = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
}
}
suspend fun getPeopleRanking(call: RoutingCall) {
val paramPage = call.parameters["page"]?.toInt() ?: throw IllegalArgumentException(ErrorMessages.InvalidMalId.message)
val timerKey = "${Collections.PEOPLE_RANKING}_${paramPage}"
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1
val size = call.request.queryParameters["size"]?.toIntOrNull() ?: 25
if (size > 25) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidValueTopPage.message))
val timerKey = "${Collections.PEOPLE_RANKING}_${page}"
val needsUpdate = timers.needsUpdate(
amount = 30,
key = timerKey,
unit = TimeUnit.DAY
)
if (needsUpdate) { peopleRanking.deleteMany(Filters.and(Filters.eq("page", paramPage)))
if (page < 1 || size < 1) call.respond(HttpStatusCode.BadRequest, ErrorMessages.InvalidSizeAndPage.message)
val skipCount = (page - 1) * size
if (needsUpdate) {
peopleRanking.deleteMany(Filters.and(Filters.eq("page", page)))
val response = RestClient.request(
BaseUrls.JIKAN + Endpoints.TOP_PEOPLE + "?page=$paramPage",
BaseUrls.JIKAN + Endpoints.TOP_PEOPLE + "?page=$page",
PeopleSearch.serializer()
).data?.map { anime ->
anime.toPeopleTopEntity(
top = "people",
page = paramPage
page = page
)
}
@ -171,32 +230,58 @@ class RankingsService(
if (documentsToInsert.isNotEmpty()) peopleRanking.insertMany(documentsToInsert)
timers.update(timerKey)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
val elements = documentsToInsert.map { documentToPeopleTopEntity(it) }
val paginationResponse = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(paginationResponse))
} else {
val elements = peopleRanking.find().toList()
val directory = elements.map { documentToTopEntity(it) }
val json = Json.encodeToString(directory)
call.respond(HttpStatusCode.OK, json)
val peoples = peopleRanking
.find()
.skip(skipCount)
.limit(size)
.toList()
val elements = peoples.map { documentToPeopleTopEntity(it) }
val response = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
}
}
suspend fun getCharacterRanking(call: RoutingCall) {
val paramPage = call.parameters["page"]?.toInt() ?: throw IllegalArgumentException(ErrorMessages.InvalidMalId.message)
val timerKey = "${Collections.CHARACTER_RANKING}_${paramPage}"
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1
val size = call.request.queryParameters["size"]?.toIntOrNull() ?: 25
if (size > 25) call.respond(HttpStatusCode.BadRequest, ErrorResponse(ErrorMessages.InvalidValueTopPage.message))
val timerKey = "${Collections.CHARACTER_RANKING}_${page}"
val needsUpdate = timers.needsUpdate(
amount = 30,
key = timerKey,
unit = TimeUnit.DAY
)
if (needsUpdate) { characterRanking.deleteMany(Filters.and(Filters.eq("page", paramPage)))
if (page < 1 || size < 1) call.respond(HttpStatusCode.BadRequest, ErrorMessages.InvalidSizeAndPage.message)
val skipCount = (page - 1) * size
if (needsUpdate) {
characterRanking.deleteMany(Filters.and(Filters.eq("page", page)))
val response = RestClient.request(
BaseUrls.JIKAN + Endpoints.TOP_CHARACTER + "?page=$paramPage",
BaseUrls.JIKAN + Endpoints.TOP_CHARACTER + "?page=$page",
CharacterSearch.serializer()
).data?.map { anime ->
anime.toCharacterTopEntity(
top = "character",
page = paramPage
page = page
)
}
@ -204,12 +289,30 @@ class RankingsService(
if (documentsToInsert.isNotEmpty()) characterRanking.insertMany(documentsToInsert)
timers.update(timerKey)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
val elements = documentsToInsert.map { documentToCharacterTopEntity(it) }
val paginationResponse = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(paginationResponse))
} else {
val elements = characterRanking.find().toList()
val directory = elements.map { documentToTopEntity(it) }
val json = Json.encodeToString(directory)
call.respond(HttpStatusCode.OK, json)
val characters = characterRanking
.find()
.skip(skipCount)
.limit(size)
.toList()
val elements = characters.map { documentToCharacterTopEntity(it) }
val response = PaginationResponse(
page = page,
size = size,
data = elements
)
call.respond(HttpStatusCode.OK, Json.encodeToString(response))
}
}
}
Loading…
Cancel
Save