From f28c098d0b537a51e3de468cea81d358fce83f74 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 8 Nov 2022 13:57:02 +0100 Subject: [PATCH 01/35] Fix --- .../ziedelth/controllers/AnimeController.kt | 24 +++++++------------ .../ziedelth/controllers/CountryController.kt | 5 ++-- .../ziedelth/controllers/DeviceController.kt | 9 ++++--- .../DeviceRedirectionController.kt | 10 ++++---- .../ziedelth/controllers/DiaryController.kt | 3 +-- .../ziedelth/controllers/EpisodeController.kt | 12 ++++------ .../controllers/EpisodeTypeController.kt | 5 ++-- .../ziedelth/controllers/GenreController.kt | 5 ++-- .../fr/ziedelth/controllers/IController.kt | 12 ++++++++-- .../controllers/LangTypeController.kt | 5 ++-- .../ziedelth/controllers/MangaController.kt | 15 ++++-------- .../fr/ziedelth/controllers/NewsController.kt | 6 ++--- .../controllers/PlatformController.kt | 5 ++-- .../controllers/SimulcastController.kt | 3 +-- 14 files changed, 50 insertions(+), 69 deletions(-) diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index 03c2831..9035070 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -12,6 +12,7 @@ import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* +import io.ktor.util.pipeline.* import java.util.* object AnimeController : IController("/animes") { @@ -45,8 +46,7 @@ object AnimeController : IController("/animes") { val uuid = query.uniqueResult() ?: return@get call.respond(HttpStatusCode.NotFound) call.respond(mapOf("uuid" to uuid)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -60,7 +60,6 @@ object AnimeController : IController("/animes") { try { val query = session.createQuery( -// "FROM Anime a WHERE a.country.tag = :tag AND LOWER(name) LIKE CONCAT('%', :name, '%')", "SELECT DISTINCT anime FROM Episode e WHERE e.anime.country.tag = :tag AND LOWER(e.anime.name) LIKE CONCAT('%', :name, '%') ORDER BY e.anime.name", Anime::class.java ) @@ -68,8 +67,7 @@ object AnimeController : IController("/animes") { query.setParameter("name", name.lowercase()) call.respond(query.list() ?: HttpStatusCode.NotFound) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -110,7 +108,7 @@ object AnimeController : IController("/animes") { ) } catch (e: Exception) { e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + call.respond(HttpStatusCode.InternalServerError, e.message ?: UNKNOWN_MESSAGE_ERROR) } finally { session.close() } @@ -145,8 +143,7 @@ object AnimeController : IController("/animes") { query.maxResults = limit call.respond(query.list()) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -169,9 +166,9 @@ object AnimeController : IController("/animes") { } if (anime.isNullOrNotValid()) { - println("Missing parameters") + println(MISSING_PARAMETERS_MESSAGE_ERROR) println(anime) - call.respond(HttpStatusCode.BadRequest, "Missing parameters") + call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } @@ -196,8 +193,7 @@ object AnimeController : IController("/animes") { ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!) call.respond(HttpStatusCode.Created, savedAnime) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } @@ -261,9 +257,7 @@ object AnimeController : IController("/animes") { val transaction = session.beginTransaction() try { - session.createQuery("DELETE Anime WHERE uuid IN :list") - .setParameter("list", uuids) - .executeUpdate() + session.remove(animes) transaction.commit() } catch (e: Exception) { e.printStackTrace() diff --git a/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt b/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt index 016762b..ab4aefc 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt @@ -24,7 +24,7 @@ object CountryController : IController("/countries") { val country = call.receive() if (country.isNullOrNotValid()) { - call.respond(HttpStatusCode.BadRequest, "Missing parameters") + call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } @@ -40,8 +40,7 @@ object CountryController : IController("/countries") { call.respond(HttpStatusCode.Created, justSave(country)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/DeviceController.kt b/src/main/kotlin/fr/ziedelth/controllers/DeviceController.kt index 37ccd69..61ca74b 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/DeviceController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/DeviceController.kt @@ -16,7 +16,7 @@ object DeviceController : IController("/devices") { val newDevice = getBy("name", device.name) if (newDevice.isNullOrNotValid()) { - println("Missing parameters") + println(MISSING_PARAMETERS_MESSAGE_ERROR) println(device) return } @@ -53,9 +53,9 @@ object DeviceController : IController("/devices") { println("POST $prefix") if (device.isNullOrNotValid()) { - println("Missing parameters") + println(MISSING_PARAMETERS_MESSAGE_ERROR) println(device) - call.respond(HttpStatusCode.BadRequest, "Missing parameters") + call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } @@ -77,8 +77,7 @@ object DeviceController : IController("/devices") { val savedDevice = justSave(device) call.respond(HttpStatusCode.Created, savedDevice) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/DeviceRedirectionController.kt b/src/main/kotlin/fr/ziedelth/controllers/DeviceRedirectionController.kt index 802076d..c13e8b7 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/DeviceRedirectionController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/DeviceRedirectionController.kt @@ -54,7 +54,7 @@ object DeviceRedirectionController : IController("/devices/redirection") val episode = EpisodeController.getBy("id", episodeId) if (device == null || episode == null) { - println("Missing parameters") + println(MISSING_PARAMETERS_MESSAGE_ERROR) return@post call.respond(HttpStatusCode.BadRequest) } @@ -71,8 +71,7 @@ object DeviceRedirectionController : IController("/devices/redirection") call.respond(HttpStatusCode.Created, "$entityName created") } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } @@ -110,7 +109,7 @@ object DeviceRedirectionController : IController("/devices/redirection") val manga = MangaController.getBy("uuid", mangaId) if (device == null || manga == null) { - println("Missing parameters") + println(MISSING_PARAMETERS_MESSAGE_ERROR) call.respond(HttpStatusCode.BadRequest) return@post } @@ -128,8 +127,7 @@ object DeviceRedirectionController : IController("/devices/redirection") call.respond(HttpStatusCode.Created, "$entityName created") } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/DiaryController.kt b/src/main/kotlin/fr/ziedelth/controllers/DiaryController.kt index 5d743b9..f4223e2 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/DiaryController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/DiaryController.kt @@ -26,8 +26,7 @@ object DiaryController : IController("/diary") { val list = query.list()?.distinctBy { it.uuid } call.respond(list ?: HttpStatusCode.NotFound) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt index fc43eb7..b18b0af 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt @@ -57,8 +57,7 @@ object EpisodeController : IController("/episodes") { value = query.list() ) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -88,8 +87,7 @@ object EpisodeController : IController("/episodes") { query.maxResults = limit call.respond(query.list() ?: HttpStatusCode.NotFound) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -119,8 +117,7 @@ object EpisodeController : IController("/episodes") { query.maxResults = limit call.respond(query.list()) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -167,8 +164,7 @@ object EpisodeController : IController("/episodes") { call.respond(HttpStatusCode.Created, episodes) PluginManager.callEvent(EpisodesReleaseEvent(savedEpisodes)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt index 8685b2a..25c98a7 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt @@ -23,7 +23,7 @@ object EpisodeTypeController : IController("/episodetypes") { val episodeType = call.receive() if (episodeType.name.isNullOrBlank()) { - call.respond(HttpStatusCode.BadRequest, "Missing parameters") + call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } @@ -34,8 +34,7 @@ object EpisodeTypeController : IController("/episodetypes") { call.respond(HttpStatusCode.Created, justSave(episodeType)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt b/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt index f148bd2..5f2570f 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt @@ -23,7 +23,7 @@ object GenreController : IController("/genres") { val genre = call.receive() if (genre.name.isNullOrBlank()) { - call.respond(HttpStatusCode.BadRequest, "Missing parameters") + call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } @@ -34,8 +34,7 @@ object GenreController : IController("/genres") { call.respond(HttpStatusCode.Created, justSave(genre)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/IController.kt b/src/main/kotlin/fr/ziedelth/controllers/IController.kt index 4b15407..1f9a947 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/IController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/IController.kt @@ -10,12 +10,20 @@ import java.io.Serializable import java.lang.reflect.ParameterizedType import java.util.* +const val UNKNOWN_MESSAGE_ERROR = "Unknown error" +const val MISSING_PARAMETERS_MESSAGE_ERROR = "Missing parameters" + open class IController(val prefix: String) { val entityClass: Class = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class val entityName: String = entityClass.simpleName val uuidRequest: UUID = UUID.randomUUID() + suspend fun printError(call: ApplicationCall, e: Exception) { + e.printStackTrace() + call.respond(HttpStatusCode.InternalServerError, e.message ?: UNKNOWN_MESSAGE_ERROR) + } + private fun getAll(): MutableList { val session = Database.getSession() @@ -114,7 +122,7 @@ open class IController(val prefix: String) { val transaction = session.beginTransaction() try { - session.update(dtoIn) + session.persist(session.merge(dtoIn)) transaction.commit() } catch (e: Exception) { e.printStackTrace() @@ -133,7 +141,7 @@ open class IController(val prefix: String) { try { call.respond(this@IController.getAll()) } catch (e: Exception) { - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt b/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt index aef913c..141f6ce 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt @@ -23,7 +23,7 @@ object LangTypeController : IController("/langtypes") { val langType = call.receive() if (langType.name.isNullOrBlank()) { - call.respond(HttpStatusCode.BadRequest, "Missing parameters") + call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } @@ -34,8 +34,7 @@ object LangTypeController : IController("/langtypes") { call.respond(HttpStatusCode.Created, justSave(langType)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt index 8870e4f..8f08dbb 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt @@ -46,8 +46,7 @@ object MangaController : IController("/mangas") { query.setParameter("ean", ean) call.respond(query.uniqueResult() ?: return@get call.respond(HttpStatusCode.NotFound)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -84,8 +83,7 @@ object MangaController : IController("/mangas") { value = query.list() ) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -115,8 +113,7 @@ object MangaController : IController("/mangas") { query.maxResults = limit call.respond(query.list() ?: HttpStatusCode.NotFound) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -146,8 +143,7 @@ object MangaController : IController("/mangas") { query.maxResults = limit call.respond(query.list()) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -183,8 +179,7 @@ object MangaController : IController("/mangas") { call.respond(HttpStatusCode.Created, mangas) PluginManager.callEvent(MangasReleaseEvent(savedMangas)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt index f2861ed..3218feb 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt @@ -49,8 +49,7 @@ object NewsController : IController("/news") { value = query.list() ) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } @@ -85,8 +84,7 @@ object NewsController : IController("/news") { call.respond(HttpStatusCode.Created, news) PluginManager.callEvent(NewsReleaseEvent(savedNews)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt b/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt index 75153b8..dd1760b 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt @@ -24,7 +24,7 @@ object PlatformController : IController("/platforms") { val platform = call.receive() if (platform.name.isNullOrBlank() || platform.url.isNullOrBlank() || platform.image.isNullOrBlank()) { - call.respond(HttpStatusCode.BadRequest, "Missing parameters") + call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } @@ -35,8 +35,7 @@ object PlatformController : IController("/platforms") { call.respond(HttpStatusCode.Created, justSave(platform)) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt b/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt index 2d52625..06ad4d6 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt @@ -23,8 +23,7 @@ object SimulcastController : IController("/simulcasts") { query.setParameter("tag", country) call.respond(query.list()) } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: "Unknown error") + printError(call, e) } finally { session.close() } From a3933d6a1a934841df9343164c7bd45a529f54a7 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 8 Nov 2022 16:29:00 +0100 Subject: [PATCH 02/35] Fix --- pom.xml | 32 +++++ .../ziedelth/controllers/DeviceController.kt | 84 ----------- .../DeviceRedirectionController.kt | 134 ------------------ src/main/kotlin/fr/ziedelth/entities/Anime.kt | 1 + .../kotlin/fr/ziedelth/entities/Country.kt | 6 +- .../kotlin/fr/ziedelth/entities/Device.kt | 44 ------ .../kotlin/fr/ziedelth/entities/Episode.kt | 1 + .../fr/ziedelth/entities/EpisodeType.kt | 6 +- src/main/kotlin/fr/ziedelth/entities/Genre.kt | 6 +- .../kotlin/fr/ziedelth/entities/LangType.kt | 6 +- src/main/kotlin/fr/ziedelth/entities/Manga.kt | 1 + src/main/kotlin/fr/ziedelth/entities/News.kt | 1 + .../kotlin/fr/ziedelth/entities/Platform.kt | 6 +- .../kotlin/fr/ziedelth/entities/Simulcast.kt | 4 +- .../DeviceEpisodeRedirection.kt | 37 ----- .../DeviceMangaRedirection.kt | 37 ----- .../kotlin/fr/ziedelth/plugins/Routing.kt | 4 - .../ziedelth/repositories/AnimeRepository.kt | 7 + .../fr/ziedelth/repositories/IRepository.kt | 56 ++++++++ .../repositories/AnimeRepositoryTest.kt | 58 ++++++++ .../kotlin/fr/ziedelth/utils/DatabaseTest.kt | 53 +++++++ src/test/resources/hibernate.cfg.xml | 16 +++ 22 files changed, 238 insertions(+), 362 deletions(-) delete mode 100644 src/main/kotlin/fr/ziedelth/controllers/DeviceController.kt delete mode 100644 src/main/kotlin/fr/ziedelth/controllers/DeviceRedirectionController.kt delete mode 100644 src/main/kotlin/fr/ziedelth/entities/Device.kt delete mode 100644 src/main/kotlin/fr/ziedelth/entities/device_redirections/DeviceEpisodeRedirection.kt delete mode 100644 src/main/kotlin/fr/ziedelth/entities/device_redirections/DeviceMangaRedirection.kt create mode 100644 src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt create mode 100644 src/main/kotlin/fr/ziedelth/repositories/IRepository.kt create mode 100644 src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/utils/DatabaseTest.kt create mode 100644 src/test/resources/hibernate.cfg.xml diff --git a/pom.xml b/pom.xml index 4242c24..23c36ea 100644 --- a/pom.xml +++ b/pom.xml @@ -47,6 +47,12 @@ ${junit-jupiter.version} test + + com.h2database + h2 + 2.1.214 + test + io.ktor ktor-server-core-jvm @@ -202,6 +208,32 @@ ${kotlin.compiler.jvmTarget} + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.9.1.2184 + + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + + prepare-agent + + prepare-agent + + test-compile + + + report + + report + + test + + + \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/controllers/DeviceController.kt b/src/main/kotlin/fr/ziedelth/controllers/DeviceController.kt deleted file mode 100644 index 61ca74b..0000000 --- a/src/main/kotlin/fr/ziedelth/controllers/DeviceController.kt +++ /dev/null @@ -1,84 +0,0 @@ -package fr.ziedelth.controllers - -import com.google.gson.Gson -import com.google.gson.JsonObject -import fr.ziedelth.entities.Device -import fr.ziedelth.entities.isNullOrNotValid -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import java.util.* - -object DeviceController : IController("/devices") { - private fun update(device: Device) { - val newDevice = getBy("name", device.name) - - if (newDevice.isNullOrNotValid()) { - println(MISSING_PARAMETERS_MESSAGE_ERROR) - println(device) - return - } - - newDevice!!.os = device.os - newDevice.model = device.model - newDevice.updatedAt = Calendar.getInstance() - justUpdate(newDevice) - } - - fun update(name: String, device: Device? = null) { - val newDevice = device ?: getBy("name", name) ?: return - newDevice.updatedAt = Calendar.getInstance() - justUpdate(newDevice) - } - - fun Routing.getDevices() { - route(prefix) { - create() - } - } - - private fun Route.create() { - post { - try { - val gson = Gson().fromJson(call.receiveText(), JsonObject::class.java) - - val device = Device( - name = gson.get("name")?.asString, - os = gson.get("os")?.asString, - model = gson.get("model")?.asString - ) - - println("POST $prefix") - - if (device.isNullOrNotValid()) { - println(MISSING_PARAMETERS_MESSAGE_ERROR) - println(device) - call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) - return@post - } - - if (isExists("name", device.name)) { - println("$entityName already exists, updating") - - try { - update(device) - call.respond(HttpStatusCode.OK, "$entityName updated") - } catch (e: Exception) { - println("Error while updating $entityName") - println(e) - call.respond(HttpStatusCode.InternalServerError, "Error while updating $entityName") - } - - return@post - } - - val savedDevice = justSave(device) - call.respond(HttpStatusCode.Created, savedDevice) - } catch (e: Exception) { - printError(call, e) - } - } - } -} diff --git a/src/main/kotlin/fr/ziedelth/controllers/DeviceRedirectionController.kt b/src/main/kotlin/fr/ziedelth/controllers/DeviceRedirectionController.kt deleted file mode 100644 index c13e8b7..0000000 --- a/src/main/kotlin/fr/ziedelth/controllers/DeviceRedirectionController.kt +++ /dev/null @@ -1,134 +0,0 @@ -package fr.ziedelth.controllers - -import fr.ziedelth.entities.Device -import fr.ziedelth.entities.Episode -import fr.ziedelth.entities.Manga -import fr.ziedelth.entities.device_redirections.DeviceEpisodeRedirection -import fr.ziedelth.entities.device_redirections.DeviceMangaRedirection -import fr.ziedelth.utils.Database -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import java.util.* - -object DeviceRedirectionController : IController("/devices/redirection") { - fun Route.getRedirection() { - route(prefix) { - episode() - manga() - } - } - - private fun getEpisodeRedirection(device: Device, episode: Episode): DeviceEpisodeRedirection? { - val session = Database.getSession() - - try { - val query = session.createQuery( - "FROM DeviceEpisodeRedirection WHERE device = :device AND episode = :episode", - DeviceEpisodeRedirection::class.java - ) - query.maxResults = 1 - query.setParameter("device", device) - query.setParameter("episode", episode) - return query.uniqueResult() - } catch (e: Exception) { - return null - } finally { - session.close() - } - } - - private fun Route.episode() { - post("/episode") { - try { - val deviceName = call.request.header("Device") ?: return@post call.respond(HttpStatusCode.BadRequest) - val episodeId = UUID.fromString( - call.request.header("Episode") ?: return@post call.respond( - HttpStatusCode.BadRequest - ) - ) - println("POST $prefix/episode") - val device = DeviceController.getBy("name", deviceName) - val episode = EpisodeController.getBy("id", episodeId) - - if (device == null || episode == null) { - println(MISSING_PARAMETERS_MESSAGE_ERROR) - return@post call.respond(HttpStatusCode.BadRequest) - } - - DeviceController.update(deviceName, device) - - val redirection = getEpisodeRedirection(device, episode) - - if (redirection != null) { - redirection.timestamp = Calendar.getInstance() - justUpdate(redirection) - } else { - justSave(DeviceEpisodeRedirection(device = device, episode = episode)) - } - - call.respond(HttpStatusCode.Created, "$entityName created") - } catch (e: Exception) { - printError(call, e) - } - } - } - - private fun getMangaRedirection(device: Device, manga: Manga): DeviceMangaRedirection? { - val session = Database.getSession() - - try { - val query = session.createQuery( - "FROM DeviceMangaRedirection WHERE device = :device AND manga = :manga", - DeviceMangaRedirection::class.java - ) - query.maxResults = 1 - query.setParameter("device", device) - query.setParameter("manga", manga) - return query.uniqueResult() - } catch (e: Exception) { - return null - } finally { - session.close() - } - } - - private fun Route.manga() { - post("/manga") { - try { - val deviceName = call.request.header("Device") ?: return@post call.respond(HttpStatusCode.BadRequest) - val mangaId = UUID.fromString( - call.request.header("Manga") ?: return@post call.respond( - HttpStatusCode.BadRequest - ) - ) - println("POST $prefix/manga") - val device = DeviceController.getBy("name", deviceName) - val manga = MangaController.getBy("uuid", mangaId) - - if (device == null || manga == null) { - println(MISSING_PARAMETERS_MESSAGE_ERROR) - call.respond(HttpStatusCode.BadRequest) - return@post - } - - DeviceController.update(deviceName, device) - - val redirection = getMangaRedirection(device, manga) - - if (redirection != null) { - redirection.timestamp = Calendar.getInstance() - justUpdate(redirection) - } else { - justSave(DeviceMangaRedirection(device = device, manga = manga)) - } - - call.respond(HttpStatusCode.Created, "$entityName created") - } catch (e: Exception) { - printError(call, e) - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/entities/Anime.kt b/src/main/kotlin/fr/ziedelth/entities/Anime.kt index 1a7a995..2dba50e 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Anime.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Anime.kt @@ -12,6 +12,7 @@ import java.util.* fun Anime?.isNullOrNotValid() = this == null || this.isNotValid() @Entity +@Table(name = "anime") data class Anime( @Id @GeneratedValue diff --git a/src/main/kotlin/fr/ziedelth/entities/Country.kt b/src/main/kotlin/fr/ziedelth/entities/Country.kt index 0bea844..6b19255 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Country.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Country.kt @@ -1,9 +1,6 @@ package fr.ziedelth.entities -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.Id +import jakarta.persistence.* import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -11,6 +8,7 @@ import java.util.* fun Country?.isNullOrNotValid() = this == null || this.isNotValid() @Entity +@Table(name = "country") data class Country( @Id @GeneratedValue diff --git a/src/main/kotlin/fr/ziedelth/entities/Device.kt b/src/main/kotlin/fr/ziedelth/entities/Device.kt deleted file mode 100644 index 4c17bfe..0000000 --- a/src/main/kotlin/fr/ziedelth/entities/Device.kt +++ /dev/null @@ -1,44 +0,0 @@ -package fr.ziedelth.entities - -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.Id -import org.hibernate.Hibernate -import java.io.Serializable -import java.util.* - -fun Device?.isNullOrNotValid() = this == null || this.isNotValid() - -@Entity -data class Device( - @Id - @GeneratedValue - val uuid: UUID = UUID.randomUUID(), - @Column(nullable = false, unique = true) - var name: String? = null, - @Column(nullable = false) - var os: String? = null, - @Column(nullable = false) - var model: String? = null, - @Column(nullable = false, name = "created_at") - val createdAt: Calendar = Calendar.getInstance(), - @Column(nullable = false, name = "updated_at") - var updatedAt: Calendar = Calendar.getInstance(), -) : Serializable { - fun isNotValid(): Boolean = name.isNullOrBlank() || os.isNullOrBlank() || model.isNullOrBlank() - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Device - - return uuid != null && uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , name = $name , os = $os , model = $model , createdAt = $createdAt , updatedAt = $updatedAt )" - } -} diff --git a/src/main/kotlin/fr/ziedelth/entities/Episode.kt b/src/main/kotlin/fr/ziedelth/entities/Episode.kt index 923d6e3..da17dc0 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Episode.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Episode.kt @@ -10,6 +10,7 @@ import java.util.* fun Episode?.isNullOrNotValid() = this == null || this.isNotValid() @Entity +@Table(name = "episode") data class Episode( @Id @GeneratedValue diff --git a/src/main/kotlin/fr/ziedelth/entities/EpisodeType.kt b/src/main/kotlin/fr/ziedelth/entities/EpisodeType.kt index ef576d8..f29bda6 100644 --- a/src/main/kotlin/fr/ziedelth/entities/EpisodeType.kt +++ b/src/main/kotlin/fr/ziedelth/entities/EpisodeType.kt @@ -1,9 +1,6 @@ package fr.ziedelth.entities -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.Id +import jakarta.persistence.* import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -11,6 +8,7 @@ import java.util.* fun EpisodeType?.isNullOrNotValid() = this == null || this.isNotValid() @Entity +@Table(name = "episodetype") data class EpisodeType( @Id @GeneratedValue diff --git a/src/main/kotlin/fr/ziedelth/entities/Genre.kt b/src/main/kotlin/fr/ziedelth/entities/Genre.kt index c4eb7c3..80fd7f5 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Genre.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Genre.kt @@ -1,9 +1,6 @@ package fr.ziedelth.entities -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.Id +import jakarta.persistence.* import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -11,6 +8,7 @@ import java.util.* fun Genre?.isNullOrNotValid() = this == null || this.isNotValid() @Entity +@Table(name = "genre") data class Genre( @Id @GeneratedValue diff --git a/src/main/kotlin/fr/ziedelth/entities/LangType.kt b/src/main/kotlin/fr/ziedelth/entities/LangType.kt index f863feb..63ed77b 100644 --- a/src/main/kotlin/fr/ziedelth/entities/LangType.kt +++ b/src/main/kotlin/fr/ziedelth/entities/LangType.kt @@ -1,9 +1,6 @@ package fr.ziedelth.entities -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.Id +import jakarta.persistence.* import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -11,6 +8,7 @@ import java.util.* fun LangType?.isNullOrNotValid() = this == null || this.isNotValid() @Entity +@Table(name = "langtype") data class LangType( @Id @GeneratedValue diff --git a/src/main/kotlin/fr/ziedelth/entities/Manga.kt b/src/main/kotlin/fr/ziedelth/entities/Manga.kt index 400eba8..9079b36 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Manga.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Manga.kt @@ -10,6 +10,7 @@ import java.util.* fun Manga?.isNullOrNotValid() = this == null || this.isNotValid() @Entity +@Table(name = "manga") data class Manga( @Id @GeneratedValue diff --git a/src/main/kotlin/fr/ziedelth/entities/News.kt b/src/main/kotlin/fr/ziedelth/entities/News.kt index 634ccfe..1694972 100644 --- a/src/main/kotlin/fr/ziedelth/entities/News.kt +++ b/src/main/kotlin/fr/ziedelth/entities/News.kt @@ -10,6 +10,7 @@ import java.util.* fun News?.isNullOrNotValid() = this == null || this.isNotValid() @Entity +@Table(name = "news") data class News( @Id @GeneratedValue diff --git a/src/main/kotlin/fr/ziedelth/entities/Platform.kt b/src/main/kotlin/fr/ziedelth/entities/Platform.kt index 8f7006b..e823e6e 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Platform.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Platform.kt @@ -1,9 +1,6 @@ package fr.ziedelth.entities -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.Id +import jakarta.persistence.* import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -11,6 +8,7 @@ import java.util.* fun Platform?.isNullOrNotValid() = this == null || this.isNotValid() @Entity +@Table(name = "platform") data class Platform( @Id @GeneratedValue diff --git a/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt b/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt index 86304ca..b1bd6b3 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt @@ -8,14 +8,14 @@ import java.util.* fun Simulcast?.isNullOrNotValid() = this == null || this.isNotValid() @Entity -@Table(uniqueConstraints = [UniqueConstraint(columnNames = arrayOf("season", "year"))]) +@Table(name = "simulcast", uniqueConstraints = [UniqueConstraint(columnNames = arrayOf("season", "year"))]) data class Simulcast( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), @Column(nullable = false) val season: String? = null, - @Column(nullable = false) + @Column(nullable = false, name = "\"year\"") val year: Int? = null ) : Serializable { fun isNotValid(): Boolean = season.isNullOrBlank() || year == null diff --git a/src/main/kotlin/fr/ziedelth/entities/device_redirections/DeviceEpisodeRedirection.kt b/src/main/kotlin/fr/ziedelth/entities/device_redirections/DeviceEpisodeRedirection.kt deleted file mode 100644 index b743f76..0000000 --- a/src/main/kotlin/fr/ziedelth/entities/device_redirections/DeviceEpisodeRedirection.kt +++ /dev/null @@ -1,37 +0,0 @@ -package fr.ziedelth.entities.device_redirections - -import fr.ziedelth.entities.Device -import fr.ziedelth.entities.Episode -import jakarta.persistence.* -import org.hibernate.Hibernate -import java.io.Serializable -import java.util.* - -@Entity -@Table(name = "device_episode_redirection") -data class DeviceEpisodeRedirection( - @Id - @GeneratedValue - val uuid: UUID = UUID.randomUUID(), - @Column(nullable = false) - var timestamp: Calendar = Calendar.getInstance(), - @ManyToOne(optional = false) - val device: Device? = null, - @ManyToOne(optional = false) - val episode: Episode? = null, -) : Serializable { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as DeviceEpisodeRedirection - - return uuid != null && uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid )" - } -} diff --git a/src/main/kotlin/fr/ziedelth/entities/device_redirections/DeviceMangaRedirection.kt b/src/main/kotlin/fr/ziedelth/entities/device_redirections/DeviceMangaRedirection.kt deleted file mode 100644 index 8104ca2..0000000 --- a/src/main/kotlin/fr/ziedelth/entities/device_redirections/DeviceMangaRedirection.kt +++ /dev/null @@ -1,37 +0,0 @@ -package fr.ziedelth.entities.device_redirections - -import fr.ziedelth.entities.Device -import fr.ziedelth.entities.Manga -import jakarta.persistence.* -import org.hibernate.Hibernate -import java.io.Serializable -import java.util.* - -@Entity -@Table(name = "device_manga_redirection") -data class DeviceMangaRedirection( - @Id - @GeneratedValue - val uuid: UUID = UUID.randomUUID(), - @Column(nullable = false) - var timestamp: Calendar = Calendar.getInstance(), - @ManyToOne(optional = false) - val device: Device? = null, - @ManyToOne(optional = false) - val manga: Manga? = null, -) : Serializable { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as DeviceMangaRedirection - - return uuid != null && uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , timestamp = $timestamp , device = $device , manga = $manga )" - } -} diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index 4a064e1..2514bb9 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -2,8 +2,6 @@ package fr.ziedelth.plugins import fr.ziedelth.controllers.AnimeController.getAnimes import fr.ziedelth.controllers.CountryController.getCountries -import fr.ziedelth.controllers.DeviceController.getDevices -import fr.ziedelth.controllers.DeviceRedirectionController.getRedirection import fr.ziedelth.controllers.DiaryController.getDiary import fr.ziedelth.controllers.EpisodeController.getEpisodes import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes @@ -35,8 +33,6 @@ fun Application.configureRouting() { getEpisodes() getNews() getMangas() - getDevices() - getRedirection() getDiary() } } diff --git a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt new file mode 100644 index 0000000..c2f29e0 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt @@ -0,0 +1,7 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.Anime +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class AnimeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt new file mode 100644 index 0000000..ed4e2ae --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt @@ -0,0 +1,56 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.utils.Database +import org.hibernate.Session +import java.lang.reflect.ParameterizedType +import java.util.UUID + +open class IRepository(val getSession: () -> Session = { Database.getSession() }) { + private val entityClass: Class = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class + private val entityName: String = entityClass.simpleName + + fun find(uuid: UUID): T? { + val session = getSession.invoke() + val entity = session.find(entityClass, uuid) + session.close() + return entity + } + + fun getAll(): MutableList { + val session = getSession.invoke() + val list = session.createQuery("FROM $entityName", entityClass).list() + session.close() + return list + } + + fun save(entity: T): T { + val session = getSession.invoke() + val transaction = session.beginTransaction() + + try { + session.persist(session.merge(entity)) + transaction.commit() + return entity + } catch (e: Exception) { + transaction.rollback() + throw e + } finally { + session.close() + } + } + + fun delete(entity: T) { + val session = getSession.invoke() + val transaction = session.beginTransaction() + + try { + session.remove(session.merge(entity)) + transaction.commit() + } catch (e: Exception) { + transaction.rollback() + throw e + } finally { + session.close() + } + } +} diff --git a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt new file mode 100644 index 0000000..60577f6 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt @@ -0,0 +1,58 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.Anime +import fr.ziedelth.entities.Country +import fr.ziedelth.utils.DatabaseTest +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.util.* +import kotlin.test.expect + +internal class AnimeRepositoryTest { + private val animeRepository = AnimeRepository { DatabaseTest.getSession() } + + @BeforeEach + fun tearUp() { + val anime = Anime(country = Country(tag = "fr", name = "France"), name = "One Piece", image = "hello") + animeRepository.save(anime) + } + + @AfterEach + fun tearDown() { + DatabaseTest.clean() + } + + @Test + fun getAll() { + val animes = animeRepository.getAll() + expect(1) { animes.size } + } + + @Test + fun find() { + val anime = animeRepository.find(UUID.randomUUID()) + expect(null) { anime } + } + + @Test + fun save() { + assertThrows { animeRepository.save(Anime(country = Country(tag = "fr", name = "France"), name = "Naruto", image = "hello")) } + + val anime = Anime(country = Country(tag = "us", name = "United States"), name = "Naruto", image = "hello") + animeRepository.save(anime) + + expect(2) { animeRepository.getAll().size } + checkNotNull { anime.uuid } + expect("Naruto") { anime.name } + } + + @Test + fun delete() { + assertThrows { animeRepository.delete(Anime(country = Country(tag = "fr", name = "France"), name = "Naruto", image = "hello")) } + + animeRepository.delete(animeRepository.getAll().first()) + expect(0) { animeRepository.getAll().size } + } +} diff --git a/src/test/kotlin/fr/ziedelth/utils/DatabaseTest.kt b/src/test/kotlin/fr/ziedelth/utils/DatabaseTest.kt new file mode 100644 index 0000000..6bd7b19 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/utils/DatabaseTest.kt @@ -0,0 +1,53 @@ +package fr.ziedelth.utils + +import org.hibernate.Session +import org.hibernate.SessionFactory +import org.hibernate.boot.registry.StandardServiceRegistryBuilder +import org.hibernate.cfg.Configuration +import org.reflections.Reflections +import java.io.File +import java.io.Serializable +import kotlin.system.exitProcess + +object DatabaseTest { + private var sessionFactory: SessionFactory + + init { + try { + val file = File(javaClass.classLoader.getResource("hibernate.cfg.xml")?.file ?: throw Exception("hibernate.cfg.xml not found")) + + Configuration().let { configuration -> + getEntities().forEach { configuration.addAnnotatedClass(it) } + + configuration.configure(file) + sessionFactory = configuration.buildSessionFactory( + StandardServiceRegistryBuilder().applySettings(configuration.properties).build() + ) + } + } catch (e: Exception) { + e.printStackTrace() + exitProcess(1) + } + } + + private fun getEntities(): MutableSet> = + Reflections("fr.ziedelth.entities").getSubTypesOf(Serializable::class.java) + + fun getSessionFactory() = sessionFactory + fun getSession(): Session = sessionFactory.openSession() + + fun clean() { + val session = getSession() + val transaction = session.beginTransaction() + + try { + getEntities().forEach { session.createQuery("DELETE FROM ${it.simpleName}").executeUpdate() } + transaction.commit() + } catch (e: Exception) { + transaction.rollback() + throw e + } finally { + session.close() + } + } +} \ No newline at end of file diff --git a/src/test/resources/hibernate.cfg.xml b/src/test/resources/hibernate.cfg.xml new file mode 100644 index 0000000..f6eb3fc --- /dev/null +++ b/src/test/resources/hibernate.cfg.xml @@ -0,0 +1,16 @@ + + + + + + org.h2.Driver + jdbc:h2:mem:test;DATABASE_TO_UPPER=false + + + org.hibernate.dialect.H2Dialect + true + create-drop + + \ No newline at end of file From 18960f480c65c35da2d99e20e06a1721a2cbd066 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 8 Nov 2022 21:14:20 +0100 Subject: [PATCH 03/35] fix --- pom.xml | 7 +- .../ziedelth/controllers/AnimeController.kt | 263 +++++++----------- .../ziedelth/controllers/CountryController.kt | 20 +- .../ziedelth/controllers/EpisodeController.kt | 9 +- .../fr/ziedelth/controllers/IController.kt | 18 +- .../ziedelth/controllers/MangaController.kt | 9 +- .../fr/ziedelth/controllers/NewsController.kt | 9 +- src/main/kotlin/fr/ziedelth/entities/Anime.kt | 18 +- .../kotlin/fr/ziedelth/entities/Country.kt | 18 +- .../kotlin/fr/ziedelth/entities/Episode.kt | 28 +- .../fr/ziedelth/entities/EpisodeType.kt | 18 +- src/main/kotlin/fr/ziedelth/entities/Genre.kt | 18 +- .../kotlin/fr/ziedelth/entities/LangType.kt | 18 +- src/main/kotlin/fr/ziedelth/entities/Manga.kt | 28 +- src/main/kotlin/fr/ziedelth/entities/News.kt | 28 +- .../kotlin/fr/ziedelth/entities/Platform.kt | 18 +- .../fr/ziedelth/entities/Platformeable.kt | 13 + .../kotlin/fr/ziedelth/entities/Simulcast.kt | 18 +- .../kotlin/fr/ziedelth/plugins/Routing.kt | 21 +- .../ziedelth/repositories/AnimeRepository.kt | 56 +++- .../repositories/CountryRepository.kt | 7 + .../fr/ziedelth/repositories/IRepository.kt | 40 ++- .../repositories/SimulcastRepository.kt | 7 + .../repositories/AnimeRepositoryTest.kt | 136 ++++++++- .../repositories/CountryRepositoryTest.kt | 106 +++++++ .../kotlin/fr/ziedelth/utils/DatabaseTest.kt | 6 +- src/test/resources/hibernate.cfg.xml | 2 +- 27 files changed, 534 insertions(+), 405 deletions(-) create mode 100644 src/main/kotlin/fr/ziedelth/entities/Platformeable.kt create mode 100644 src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt create mode 100644 src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt create mode 100644 src/test/kotlin/fr/ziedelth/repositories/CountryRepositoryTest.kt diff --git a/pom.xml b/pom.xml index 23c36ea..0d7ca1a 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,6 @@ maven-compiler-plugin ${kotlin.compiler.jvmTarget} - ${kotlin.compiler.jvmTarget} @@ -217,6 +216,12 @@ org.jacoco jacoco-maven-plugin 0.8.8 + + + fr/ziedelth/entities/* + fr/ziedelth/plugins/* + + prepare-agent diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index 9035070..e0d514b 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -3,7 +3,8 @@ package fr.ziedelth.controllers import com.google.gson.Gson import fr.ziedelth.entities.Anime import fr.ziedelth.entities.isNullOrNotValid -import fr.ziedelth.utils.Database +import fr.ziedelth.repositories.AnimeRepository +import fr.ziedelth.repositories.CountryRepository import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache import fr.ziedelth.utils.RequestCache @@ -15,9 +16,10 @@ import io.ktor.server.routing.* import io.ktor.util.pipeline.* import java.util.* -object AnimeController : IController("/animes") { - fun Routing.getAnimes() { - route(prefix) { +class AnimeController(private val countryRepository: CountryRepository, private val animeRepository: AnimeRepository) : + IController("/animes") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { search() getWithPage() getWatchlistWithPage() @@ -33,119 +35,52 @@ object AnimeController : IController("/animes") { val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) val hash = call.parameters["hash"] ?: return@get call.respond(HttpStatusCode.BadRequest) println("GET $prefix/country/$country/search/hash/$hash") - val session = Database.getSession() - - try { - val query = session.createQuery( - "SELECT a.uuid FROM Anime a JOIN a.hashes h WHERE a.country.tag = :tag AND h = :hash", - UUID::class.java - ) - query.maxResults = 1 - query.setParameter("tag", country) - query.setParameter("hash", hash) - val uuid = query.uniqueResult() ?: return@get call.respond(HttpStatusCode.NotFound) - call.respond(mapOf("uuid" to uuid)) - } catch (e: Exception) { - printError(call, e) - } finally { - session.close() - } + call.respond(mapOf("uuid" to animeRepository.findByHash(country, hash))) } get("/name/{name}") { val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) val name = call.parameters["name"] ?: return@get call.respond(HttpStatusCode.BadRequest) println("GET $prefix/country/$country/search/name/$name") - val session = Database.getSession() - - try { - val query = session.createQuery( - "SELECT DISTINCT anime FROM Episode e WHERE e.anime.country.tag = :tag AND LOWER(e.anime.name) LIKE CONCAT('%', :name, '%') ORDER BY e.anime.name", - Anime::class.java - ) - query.setParameter("tag", country) - query.setParameter("name", name.lowercase()) - call.respond(query.list() ?: HttpStatusCode.NotFound) - } catch (e: Exception) { - printError(call, e) - } finally { - session.close() - } + call.respond(animeRepository.findByName(country, name)) } } } private fun Route.getWithPage() { get("/country/{country}/simulcast/{simulcast}/page/{page}/limit/{limit}") { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val simulcast = call.parameters["simulcast"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val page = call.parameters["page"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - val limit = call.parameters["limit"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - if (page < 1 || limit < 1) return@get call.respond(HttpStatusCode.BadRequest) - if (limit > 30) return@get call.respond(HttpStatusCode.BadRequest) - println("GET $prefix/country/$country/simulcast/$simulcast/page/$page/limit/$limit") - val request = RequestCache.get(uuidRequest, country, page, limit, simulcast) - - if (request == null || request.isExpired()) { - val session = Database.getSession() - - try { - val query = session.createQuery( - "FROM Anime a JOIN a.simulcasts s WHERE a.country.tag = :tag AND s.uuid = :simulcast ORDER BY a.name", - Anime::class.java - ) - query.setParameter("tag", country) - query.setParameter("simulcast", UUID.fromString(simulcast)) - query.firstResult = (limit * page) - limit - query.maxResults = limit - request?.update(query.list()) ?: RequestCache.put( - uuidRequest, - country, - page, - limit, - simulcast, - query.list() - ) - } catch (e: Exception) { - e.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, e.message ?: UNKNOWN_MESSAGE_ERROR) - } finally { - session.close() + try { + val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val simulcast = call.parameters["simulcast"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val (page, limit) = getPageAndLimit() + println("GET $prefix/country/$country/simulcast/$simulcast/page/$page/limit/$limit") + val request = RequestCache.get(uuidRequest, country, page, limit, simulcast) + + if (request == null || request.isExpired()) { + val list = animeRepository.getByPage(country, UUID.fromString(simulcast), page, limit) + request?.update(list) ?: RequestCache.put(uuidRequest, country, page, limit, simulcast, list) } - } - call.respond( - RequestCache.get(uuidRequest, country, page, limit, simulcast)?.value ?: HttpStatusCode.NotFound - ) + call.respond( + RequestCache.get(uuidRequest, country, page, limit, simulcast)?.value ?: HttpStatusCode.NotFound + ) + } catch (e: Exception) { + printError(call, e) + } } } private fun Route.getWatchlistWithPage() { post("/watchlist/page/{page}/limit/{limit}") { - val watchlist = call.receive() - val page = call.parameters["page"]?.toInt() ?: return@post call.respond(HttpStatusCode.BadRequest) - val limit = call.parameters["limit"]?.toInt() ?: return@post call.respond(HttpStatusCode.BadRequest) - if (page < 1 || limit < 1) return@post call.respond(HttpStatusCode.BadRequest) - if (limit > 30) return@post call.respond(HttpStatusCode.BadRequest) - println("POST $prefix/watchlist/page/$page/limit/$limit") - val session = Database.getSession() - try { + val watchlist = call.receive() + val (page, limit) = getPageAndLimit() + println("POST $prefix/watchlist/page/$page/limit/$limit") val dataFromGzip = Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } - - val query = session.createQuery( - "FROM $entityName WHERE uuid IN :list ORDER BY name", - entityClass - ) - query.setParameter("list", dataFromGzip) - query.firstResult = (limit * page) - limit - query.maxResults = limit - call.respond(query.list()) + call.respond(animeRepository.findAllByPage(dataFromGzip, page, limit)) } catch (e: Exception) { printError(call, e) - } finally { - session.close() } } } @@ -157,8 +92,9 @@ object AnimeController : IController("/animes") { try { val anime = call.receive() - anime.country = CountryController.getBy("uuid", anime.country?.uuid) ?: return@post run { + anime.country = countryRepository.find(anime.country!!.uuid) ?: return@post run { println("Country not found") + call.respond( HttpStatusCode.BadRequest, "Country not found" @@ -172,13 +108,14 @@ object AnimeController : IController("/animes") { return@post } - if (isExists("name", anime.name)) { + if (animeRepository.exists("name", anime.name)) { println("$entityName already exists") call.respond(HttpStatusCode.Conflict, "$entityName already exists") return@post } val hash = anime.hash() + if (contains("hashes", hash)) { println("$entityName already exists") call.respond(HttpStatusCode.Conflict, "$entityName already exists") @@ -189,7 +126,7 @@ object AnimeController : IController("/animes") { anime.hashes.add(hash!!) } - val savedAnime = justSave(anime) + val savedAnime = animeRepository.save(anime) ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!) call.respond(HttpStatusCode.Created, savedAnime) } catch (e: Exception) { @@ -200,73 +137,73 @@ object AnimeController : IController("/animes") { private fun Route.merge() { put("/merge") { - // Get list of uuids - val uuids = call.receive>().map { UUID.fromString(it) } - println("PUT $prefix/merge") - // Get anime - val animes = uuids.mapNotNull { getBy("uuid", it) } - - if (animes.isEmpty()) { - println("Anime not found") - call.respond(HttpStatusCode.NotFound, "Anime not found") - return@put - } - - // Get all countries - val countries = animes.map { it.country }.distinctBy { it?.uuid } - - if (countries.size > 1) { - println("Anime has different countries") - call.respond(HttpStatusCode.BadRequest, "Anime has different countries") - return@put - } - - // Get all hashes - val hashes = animes.map { it.hashes }.flatten().distinct().toMutableSet() - // Get all genres - val genres = animes.map { it.genres }.flatten().distinctBy { it.uuid }.toMutableSet() - // Get all simulcasts - val simulcasts = animes.map { it.simulcasts }.flatten().distinctBy { it.uuid }.toMutableSet() - // Get all episodes - val episodes = - animes.map { EpisodeController.getAllBy("anime.uuid", it.uuid) }.flatten().distinctBy { it.uuid } - .toMutableSet() - // Get all mangas - val mangas = animes.map { MangaController.getAllBy("anime.uuid", it.uuid) }.flatten().distinctBy { it.uuid } - .toMutableSet() - - val firstAnime = animes.first() - val mergedAnime = Anime( - country = countries.first(), - name = "${animes.first().name} (${animes.size})", - releaseDate = firstAnime.releaseDate, - image = firstAnime.image, - description = firstAnime.description, - hashes = hashes, - genres = genres, - simulcasts = simulcasts - ) - - val savedAnime = justSave(mergedAnime) - ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!) - episodes.map { it.copy(anime = savedAnime) }.map { EpisodeController.justSave(it) } - mangas.map { it.copy(anime = savedAnime) }.map { MangaController.justSave(it) } - - // Delete animes - val session = Database.getSession() - val transaction = session.beginTransaction() - - try { - session.remove(animes) - transaction.commit() - } catch (e: Exception) { - e.printStackTrace() - println("Error while deleting $prefix : ${e.message}") - transaction.rollback() - throw e - } finally { - session.close() - } +// // Get list of uuids +// val uuids = call.receive>().map { UUID.fromString(it) } +// println("PUT $prefix/merge") +// // Get anime +// val animes = uuids.mapNotNull { getBy("uuid", it) } +// +// if (animes.isEmpty()) { +// println("Anime not found") +// call.respond(HttpStatusCode.NotFound, "Anime not found") +// return@put +// } +// +// // Get all countries +// val countries = animes.map { it.country }.distinctBy { it?.uuid } +// +// if (countries.size > 1) { +// println("Anime has different countries") +// call.respond(HttpStatusCode.BadRequest, "Anime has different countries") +// return@put +// } +// +// // Get all hashes +// val hashes = animes.map { it.hashes }.flatten().distinct().toMutableSet() +// // Get all genres +// val genres = animes.map { it.genres }.flatten().distinctBy { it.uuid }.toMutableSet() +// // Get all simulcasts +// val simulcasts = animes.map { it.simulcasts }.flatten().distinctBy { it.uuid }.toMutableSet() +// // Get all episodes +// val episodes = +// animes.map { EpisodeController.getAllBy("anime.uuid", it.uuid) }.flatten().distinctBy { it.uuid } +// .toMutableSet() +// // Get all mangas +// val mangas = animes.map { MangaController.getAllBy("anime.uuid", it.uuid) }.flatten().distinctBy { it.uuid } +// .toMutableSet() +// +// val firstAnime = animes.first() +// val mergedAnime = Anime( +// country = countries.first(), +// name = "${animes.first().name} (${animes.size})", +// releaseDate = firstAnime.releaseDate, +// image = firstAnime.image, +// description = firstAnime.description, +// hashes = hashes, +// genres = genres, +// simulcasts = simulcasts +// ) +// +// val savedAnime = justSave(mergedAnime) +// ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!) +// episodes.map { it.copy(anime = savedAnime) }.map { EpisodeController.justSave(it) } +// mangas.map { it.copy(anime = savedAnime) }.map { MangaController.justSave(it) } +// +// // Delete animes +// val session = Database.getSession() +// val transaction = session.beginTransaction() +// +// try { +// session.remove(animes) +// transaction.commit() +// } catch (e: Exception) { +// e.printStackTrace() +// println("Error while deleting $prefix : ${e.message}") +// transaction.rollback() +// throw e +// } finally { +// session.close() +// } } } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt b/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt index ab4aefc..a20be6f 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt @@ -2,20 +2,28 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.Country import fr.ziedelth.entities.isNullOrNotValid +import fr.ziedelth.repositories.CountryRepository import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -object CountryController : IController("/countries") { - fun Routing.getCountries() { - route(prefix) { +class CountryController(private val countryRepository: CountryRepository) : IController("/countries") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { getAll() create() } } + override fun Route.getAll() { + get { + println("GET $prefix") + call.respond(countryRepository.getAll()) + } + } + private fun Route.create() { post { println("POST $prefix") @@ -28,17 +36,17 @@ object CountryController : IController("/countries") { return@post } - if (isExists("tag", country.tag!!)) { + if (countryRepository.exists("tag", country.tag)) { call.respond(HttpStatusCode.Conflict, "$entityName already exists") return@post } - if (isExists("name", country.name!!)) { + if (countryRepository.exists("name", country.name)) { call.respond(HttpStatusCode.Conflict, "$entityName already exists") return@post } - call.respond(HttpStatusCode.Created, justSave(country)) + call.respond(HttpStatusCode.Created, countryRepository.save(country)) } catch (e: Exception) { printError(call, e) } diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt index b18b0af..1fc7503 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt @@ -5,6 +5,7 @@ import fr.ziedelth.entities.Episode import fr.ziedelth.entities.Simulcast import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.EpisodesReleaseEvent +import fr.ziedelth.repositories.AnimeRepository import fr.ziedelth.utils.Database import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache @@ -17,9 +18,9 @@ import io.ktor.server.response.* import io.ktor.server.routing.* import java.util.* -object EpisodeController : IController("/episodes") { - fun Routing.getEpisodes() { - route(prefix) { +class EpisodeController(private val animeRepository: AnimeRepository) : IController("/episodes") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { getWithPage() getAnimeWithPage() getWatchlistWithPage() @@ -127,7 +128,7 @@ object EpisodeController : IController("/episodes") { private fun merge(episode: Episode) { episode.platform = PlatformController.getBy("uuid", episode.platform!!.uuid) ?: throw Exception("Platform not found") - episode.anime = AnimeController.getBy("uuid", episode.anime!!.uuid) ?: throw Exception("Anime not found") + episode.anime = animeRepository.find(episode.anime!!.uuid) ?: throw Exception("Anime not found") episode.episodeType = EpisodeTypeController.getBy("uuid", episode.episodeType!!.uuid) ?: throw Exception("EpisodeType not found") episode.langType = diff --git a/src/main/kotlin/fr/ziedelth/controllers/IController.kt b/src/main/kotlin/fr/ziedelth/controllers/IController.kt index 1f9a947..37b0973 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/IController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/IController.kt @@ -6,6 +6,7 @@ import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* +import io.ktor.util.pipeline.* import java.io.Serializable import java.lang.reflect.ParameterizedType import java.util.* @@ -19,6 +20,21 @@ open class IController(val prefix: String) { val entityName: String = entityClass.simpleName val uuidRequest: UUID = UUID.randomUUID() + fun PipelineContext.getPageAndLimit(): Pair { + val page = call.parameters["page"]?.toInt() ?: throw IllegalArgumentException("Page is not valid") + val limit = call.parameters["limit"]?.toInt() ?: throw IllegalArgumentException("Limit is not valid") + + if (page < 1 || limit < 1) { + throw IllegalArgumentException("Page or limit is not valid") + } + + if (limit > 30) { + throw IllegalArgumentException("Limit is too high") + } + + return Pair(page, limit) + } + suspend fun printError(call: ApplicationCall, e: Exception) { e.printStackTrace() call.respond(HttpStatusCode.InternalServerError, e.message ?: UNKNOWN_MESSAGE_ERROR) @@ -134,7 +150,7 @@ open class IController(val prefix: String) { } } - fun Route.getAll() { + open fun Route.getAll() { get { println("GET $prefix") diff --git a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt index 8f08dbb..789cbca 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt @@ -4,6 +4,7 @@ import com.google.gson.Gson import fr.ziedelth.entities.Manga import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.MangasReleaseEvent +import fr.ziedelth.repositories.AnimeRepository import fr.ziedelth.utils.Database import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache @@ -16,9 +17,9 @@ import io.ktor.server.response.* import io.ktor.server.routing.* import java.util.* -object MangaController : IController("/mangas") { - fun Routing.getMangas() { - route(prefix) { +class MangaController(private val animeRepository: AnimeRepository) : IController("/mangas") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { search() getWithPage() getAnimeWithPage() @@ -154,7 +155,7 @@ object MangaController : IController("/mangas") { private fun merge(manga: Manga) { manga.platform = PlatformController.getBy("uuid", manga.platform!!.uuid) ?: throw Exception("Platform not found") - manga.anime = AnimeController.getBy("uuid", manga.anime!!.uuid) ?: throw Exception("Anime not found") + manga.anime = animeRepository.find(manga.anime!!.uuid) ?: throw Exception("Anime not found") if (manga.isNullOrNotValid()) { throw Exception("Manga is not valid") diff --git a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt index 3218feb..f69d877 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt @@ -3,6 +3,7 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.News import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.NewsReleaseEvent +import fr.ziedelth.repositories.CountryRepository import fr.ziedelth.utils.Database import fr.ziedelth.utils.RequestCache import fr.ziedelth.utils.plugins.PluginManager @@ -12,9 +13,9 @@ import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -object NewsController : IController("/news") { - fun Routing.getNews() { - route(prefix) { +class NewsController(private val countryRepository: CountryRepository) : IController("/news") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { getWithPage() create() } @@ -61,7 +62,7 @@ object NewsController : IController("/news") { private fun merge(news: News) { news.platform = PlatformController.getBy("uuid", news.platform!!.uuid) ?: throw Exception("Platform not found") - news.country = CountryController.getBy("uuid", news.country!!.uuid) ?: throw Exception("Country not found") + news.country = countryRepository.find(news.country!!.uuid) ?: throw Exception("Country not found") if (news.isNullOrNotValid()) { throw Exception("News is not valid") diff --git a/src/main/kotlin/fr/ziedelth/entities/Anime.kt b/src/main/kotlin/fr/ziedelth/entities/Anime.kt index 2dba50e..d013768 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Anime.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Anime.kt @@ -3,7 +3,6 @@ package fr.ziedelth.entities import fr.ziedelth.utils.DATE_FORMAT_REGEX import fr.ziedelth.utils.toISO8601 import jakarta.persistence.* -import org.hibernate.Hibernate import org.hibernate.annotations.LazyCollection import org.hibernate.annotations.LazyCollectionOption import java.io.Serializable @@ -13,7 +12,7 @@ fun Anime?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "anime") -data class Anime( +class Anime( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), @@ -83,19 +82,4 @@ data class Anime( DATE_FORMAT_REGEX ) ) || image.isNullOrBlank() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Anime - - return uuid != null && uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , country = $country , name = $name , releaseDate = $releaseDate , image = $image , description = $description , hashes = $hashes )" - } } diff --git a/src/main/kotlin/fr/ziedelth/entities/Country.kt b/src/main/kotlin/fr/ziedelth/entities/Country.kt index 6b19255..c66b61f 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Country.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Country.kt @@ -1,7 +1,6 @@ package fr.ziedelth.entities import jakarta.persistence.* -import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -9,7 +8,7 @@ fun Country?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "country") -data class Country( +class Country( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), @@ -19,19 +18,4 @@ data class Country( val name: String? = null ) : Serializable { fun isNotValid(): Boolean = tag.isNullOrBlank() || name.isNullOrBlank() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Country - - return uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , tag = $tag , name = $name )" - } } diff --git a/src/main/kotlin/fr/ziedelth/entities/Episode.kt b/src/main/kotlin/fr/ziedelth/entities/Episode.kt index da17dc0..76f92ff 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Episode.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Episode.kt @@ -3,7 +3,6 @@ package fr.ziedelth.entities import fr.ziedelth.utils.DATE_FORMAT_REGEX import fr.ziedelth.utils.toISO8601 import jakarta.persistence.* -import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -11,17 +10,11 @@ fun Episode?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "episode") -data class Episode( +class Episode( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), - @ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) - @JoinColumn( - name = "platform_uuid", - nullable = false, - foreignKey = ForeignKey(foreignKeyDefinition = "FOREIGN KEY (platform_uuid) REFERENCES platform(uuid) ON DELETE CASCADE") - ) - var platform: Platform? = null, + platform: Platform? = null, @ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) @JoinColumn( name = "anime_uuid", @@ -59,24 +52,9 @@ data class Episode( val image: String? = null, @Column(nullable = false) val duration: Long = -1 -) : Serializable { +) : Platformeable(platform), Serializable { fun isNotValid(): Boolean = platform.isNullOrNotValid() || anime.isNullOrNotValid() || episodeType.isNullOrNotValid() || langType.isNullOrNotValid() || hash.isNullOrBlank() || ( releaseDate.isBlank() || !releaseDate.matches(DATE_FORMAT_REGEX) ) || season == null || number == null || url.isNullOrBlank() || image.isNullOrBlank() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Episode - - return uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , platform = $platform , anime = $anime , episodeType = $episodeType , langType = $langType , hash = $hash , releaseDate = $releaseDate , season = $season , number = $number , title = $title , url = $url , image = $image , duration = $duration )" - } } diff --git a/src/main/kotlin/fr/ziedelth/entities/EpisodeType.kt b/src/main/kotlin/fr/ziedelth/entities/EpisodeType.kt index f29bda6..b121cc6 100644 --- a/src/main/kotlin/fr/ziedelth/entities/EpisodeType.kt +++ b/src/main/kotlin/fr/ziedelth/entities/EpisodeType.kt @@ -1,7 +1,6 @@ package fr.ziedelth.entities import jakarta.persistence.* -import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -9,7 +8,7 @@ fun EpisodeType?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "episodetype") -data class EpisodeType( +class EpisodeType( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), @@ -17,19 +16,4 @@ data class EpisodeType( val name: String? = null ) : Serializable { fun isNotValid(): Boolean = name.isNullOrBlank() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as EpisodeType - - return uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , name = $name )" - } } diff --git a/src/main/kotlin/fr/ziedelth/entities/Genre.kt b/src/main/kotlin/fr/ziedelth/entities/Genre.kt index 80fd7f5..d2d1632 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Genre.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Genre.kt @@ -1,7 +1,6 @@ package fr.ziedelth.entities import jakarta.persistence.* -import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -9,7 +8,7 @@ fun Genre?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "genre") -data class Genre( +class Genre( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), @@ -17,19 +16,4 @@ data class Genre( val name: String? = null ) : Serializable { fun isNotValid(): Boolean = name.isNullOrBlank() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Genre - - return uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , name = $name )" - } } diff --git a/src/main/kotlin/fr/ziedelth/entities/LangType.kt b/src/main/kotlin/fr/ziedelth/entities/LangType.kt index 63ed77b..57f39cc 100644 --- a/src/main/kotlin/fr/ziedelth/entities/LangType.kt +++ b/src/main/kotlin/fr/ziedelth/entities/LangType.kt @@ -1,7 +1,6 @@ package fr.ziedelth.entities import jakarta.persistence.* -import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -9,7 +8,7 @@ fun LangType?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "langtype") -data class LangType( +class LangType( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), @@ -17,19 +16,4 @@ data class LangType( val name: String? = null ) : Serializable { fun isNotValid(): Boolean = name.isNullOrBlank() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as LangType - - return uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , name = $name )" - } } diff --git a/src/main/kotlin/fr/ziedelth/entities/Manga.kt b/src/main/kotlin/fr/ziedelth/entities/Manga.kt index 9079b36..86570b5 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Manga.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Manga.kt @@ -3,7 +3,6 @@ package fr.ziedelth.entities import fr.ziedelth.utils.DATE_FORMAT_REGEX import fr.ziedelth.utils.toISO8601 import jakarta.persistence.* -import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -11,17 +10,11 @@ fun Manga?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "manga") -data class Manga( +class Manga( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), - @ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) - @JoinColumn( - name = "platform_uuid", - nullable = false, - foreignKey = ForeignKey(foreignKeyDefinition = "FOREIGN KEY (platform_uuid) REFERENCES platform(uuid) ON DELETE CASCADE") - ) - var platform: Platform? = null, + platform: Platform? = null, @ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) @JoinColumn( name = "anime_uuid", @@ -47,24 +40,9 @@ data class Manga( val age: Int? = null, @Column(nullable = true) val price: Double? = null -) : Serializable { +) : Platformeable(platform), Serializable { fun isNotValid(): Boolean = platform.isNullOrNotValid() || anime.isNullOrNotValid() || hash.isNullOrBlank() || (releaseDate.isBlank() || !releaseDate.matches( DATE_FORMAT_REGEX )) || url.isNullOrBlank() || cover.isNullOrBlank() || editor.isNullOrBlank() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Manga - - return uuid != null && uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , platform = $platform , anime = $anime , hash = $hash , releaseDate = $releaseDate , url = $url , cover = $cover , editor = $editor , ref = $ref , ean = $ean , age = $age , price = $price )" - } } diff --git a/src/main/kotlin/fr/ziedelth/entities/News.kt b/src/main/kotlin/fr/ziedelth/entities/News.kt index 1694972..e4ded77 100644 --- a/src/main/kotlin/fr/ziedelth/entities/News.kt +++ b/src/main/kotlin/fr/ziedelth/entities/News.kt @@ -3,7 +3,6 @@ package fr.ziedelth.entities import fr.ziedelth.utils.DATE_FORMAT_REGEX import fr.ziedelth.utils.toISO8601 import jakarta.persistence.* -import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -11,17 +10,11 @@ fun News?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "news") -data class News( +class News( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), - @ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) - @JoinColumn( - name = "platform_uuid", - nullable = false, - foreignKey = ForeignKey(foreignKeyDefinition = "FOREIGN KEY (platform_uuid) REFERENCES platform(uuid) ON DELETE CASCADE") - ) - var platform: Platform? = null, + platform: Platform? = null, @ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) @JoinColumn( name = "country_uuid", @@ -39,24 +32,9 @@ data class News( val description: String? = null, @Column(nullable = false) val url: String? = null -) : Serializable { +) : Platformeable(platform), Serializable { fun isNotValid(): Boolean = platform.isNullOrNotValid() || country.isNullOrNotValid() || hash.isNullOrBlank() || ( releaseDate.isBlank() || !releaseDate.matches(DATE_FORMAT_REGEX) ) || title.isNullOrBlank() || description.isNullOrBlank() || url.isNullOrBlank() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as News - - return uuid != null && uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , platform = $platform , country = $country , hash = $hash , releaseDate = $releaseDate , title = $title , description = $description , url = $url )" - } } diff --git a/src/main/kotlin/fr/ziedelth/entities/Platform.kt b/src/main/kotlin/fr/ziedelth/entities/Platform.kt index e823e6e..c0cca79 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Platform.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Platform.kt @@ -1,7 +1,6 @@ package fr.ziedelth.entities import jakarta.persistence.* -import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -9,7 +8,7 @@ fun Platform?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "platform") -data class Platform( +class Platform( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), @@ -21,19 +20,4 @@ data class Platform( val image: String? = null ) : Serializable { fun isNotValid(): Boolean = name.isNullOrBlank() || url.isNullOrBlank() || image.isNullOrBlank() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Platform - - return uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , name = $name , url = $url , image = $image )" - } } diff --git a/src/main/kotlin/fr/ziedelth/entities/Platformeable.kt b/src/main/kotlin/fr/ziedelth/entities/Platformeable.kt new file mode 100644 index 0000000..c3e0730 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/entities/Platformeable.kt @@ -0,0 +1,13 @@ +package fr.ziedelth.entities + +import jakarta.persistence.* + +open class Platformeable( + @ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) + @JoinColumn( + name = "platform_uuid", + nullable = false, + foreignKey = ForeignKey(foreignKeyDefinition = "FOREIGN KEY (platform_uuid) REFERENCES platform(uuid) ON DELETE CASCADE") + ) + var platform: Platform? = null, +) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt b/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt index b1bd6b3..f6f78ca 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt @@ -1,7 +1,6 @@ package fr.ziedelth.entities import jakarta.persistence.* -import org.hibernate.Hibernate import java.io.Serializable import java.util.* @@ -9,7 +8,7 @@ fun Simulcast?.isNullOrNotValid() = this == null || this.isNotValid() @Entity @Table(name = "simulcast", uniqueConstraints = [UniqueConstraint(columnNames = arrayOf("season", "year"))]) -data class Simulcast( +class Simulcast( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), @@ -20,21 +19,6 @@ data class Simulcast( ) : Serializable { fun isNotValid(): Boolean = season.isNullOrBlank() || year == null - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Simulcast - - return uuid != null && uuid == other.uuid - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + "(uuid = $uuid , season = $season , year = $year )" - } - companion object { fun getSimulcast(year: Int, month: Int): Simulcast { val seasons = arrayOf("WINTER", "SPRING", "SUMMER", "AUTUMN") diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index 2514bb9..a6b41a2 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -1,16 +1,14 @@ package fr.ziedelth.plugins -import fr.ziedelth.controllers.AnimeController.getAnimes -import fr.ziedelth.controllers.CountryController.getCountries +import fr.ziedelth.controllers.* import fr.ziedelth.controllers.DiaryController.getDiary -import fr.ziedelth.controllers.EpisodeController.getEpisodes import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.controllers.LangTypeController.getLangTypes -import fr.ziedelth.controllers.MangaController.getMangas -import fr.ziedelth.controllers.NewsController.getNews import fr.ziedelth.controllers.PlatformController.getPlatforms import fr.ziedelth.controllers.SimulcastController.getSimulcasts +import fr.ziedelth.repositories.AnimeRepository +import fr.ziedelth.repositories.CountryRepository import io.ktor.serialization.gson.* import io.ktor.server.application.* import io.ktor.server.plugins.contentnegotiation.* @@ -23,16 +21,19 @@ fun Application.configureRouting() { } routing { - getCountries() + val countryRepository = CountryRepository() + val animeRepository = AnimeRepository() + + CountryController(countryRepository).getRoutes(this) getPlatforms() getSimulcasts() getGenres() - getAnimes() + AnimeController(countryRepository, animeRepository).getRoutes(this) getEpisodeTypes() getLangTypes() - getEpisodes() - getNews() - getMangas() + EpisodeController(animeRepository).getRoutes(this) + NewsController(countryRepository).getRoutes(this) + MangaController(animeRepository).getRoutes(this) getDiary() } } diff --git a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt index c2f29e0..4e0d407 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt @@ -3,5 +3,59 @@ package fr.ziedelth.repositories import fr.ziedelth.entities.Anime import fr.ziedelth.utils.Database import org.hibernate.Session +import java.util.* -class AnimeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file +class AnimeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) { + fun findByHash(tag: String, hash: String): UUID? { + val session = getSession.invoke() + val query = session.createQuery( + "SELECT a.uuid FROM Anime a JOIN a.hashes h WHERE a.country.tag = :tag AND h = :hash", + UUID::class.java + ) + query.maxResults = 1 + query.setParameter("tag", tag) + query.setParameter("hash", hash) + val uuid = query.uniqueResult() + session.close() + return uuid + } + + fun findByName(tag: String, name: String): List { + val session = getSession.invoke() + val query = session.createQuery( + "SELECT DISTINCT anime FROM Episode e WHERE e.anime.country.tag = :tag AND LOWER(e.anime.name) LIKE CONCAT('%', :name, '%') ORDER BY e.anime.name", + Anime::class.java + ) + query.setParameter("tag", tag) + query.setParameter("name", name.lowercase()) + val list = query.list() + session.close() + return list + } + + fun getByPage(tag: String, simulcast: UUID, page: Int, limit: Int): List { + val session = getSession.invoke() + val query = session.createQuery( + "FROM Anime a JOIN a.simulcasts s WHERE a.country.tag = :tag AND s.uuid = :simulcast ORDER BY a.name", + Anime::class.java + ) + query.setParameter("tag", tag) + query.setParameter("simulcast", simulcast) + query.firstResult = (limit * page) - limit + query.maxResults = limit + val list = query.list() + session.close() + return list + } + + fun findAllByPage(uuids: List, page: Int, limit: Int): List { + val session = getSession.invoke() + val query = session.createQuery("FROM Anime WHERE uuid IN :list ORDER BY name", Anime::class.java) + query.setParameter("list", uuids) + query.firstResult = (limit * page) - limit + query.maxResults = limit + val list = query.list() + session.close() + return list + } +} \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt new file mode 100644 index 0000000..fd1942a --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt @@ -0,0 +1,7 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.Country +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class CountryRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt index ed4e2ae..7707756 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt @@ -3,10 +3,11 @@ package fr.ziedelth.repositories import fr.ziedelth.utils.Database import org.hibernate.Session import java.lang.reflect.ParameterizedType -import java.util.UUID +import java.util.* open class IRepository(val getSession: () -> Session = { Database.getSession() }) { - private val entityClass: Class = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class + private val entityClass: Class = + (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class private val entityName: String = entityClass.simpleName fun find(uuid: UUID): T? { @@ -16,6 +17,25 @@ open class IRepository(val getSession: () -> Session = { Database.getSession( return entity } + fun exists(field: String, value: Any?): Boolean { + val session = getSession.invoke() + val query = session.createQuery("SELECT uuid FROM $entityName WHERE $field = :$field", UUID::class.java) + query.maxResults = 1 + query.setParameter(field, value) + val uuid = query.uniqueResult() + session.close() + return uuid != null + } + + fun findAll(uuids: List): List { + val session = getSession.invoke() + val entities = session.createQuery("FROM $entityName WHERE uuid IN :uuids", entityClass) + .setParameter("uuids", uuids) + .resultList + session.close() + return entities + } + fun getAll(): MutableList { val session = getSession.invoke() val list = session.createQuery("FROM $entityName", entityClass).list() @@ -39,6 +59,22 @@ open class IRepository(val getSession: () -> Session = { Database.getSession( } } + fun saveAll(entities: List): List { + val session = getSession.invoke() + val transaction = session.beginTransaction() + + try { + entities.forEach { session.persist(session.merge(it)) } + transaction.commit() + return entities + } catch (e: Exception) { + transaction.rollback() + throw e + } finally { + session.close() + } + } + fun delete(entity: T) { val session = getSession.invoke() val transaction = session.beginTransaction() diff --git a/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt new file mode 100644 index 0000000..cce1c24 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt @@ -0,0 +1,7 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.Simulcast +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class SimulcastRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt index 60577f6..979b150 100644 --- a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt +++ b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt @@ -2,6 +2,7 @@ package fr.ziedelth.repositories import fr.ziedelth.entities.Anime import fr.ziedelth.entities.Country +import fr.ziedelth.entities.Simulcast import fr.ziedelth.utils.DatabaseTest import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach @@ -11,12 +12,19 @@ import java.util.* import kotlin.test.expect internal class AnimeRepositoryTest { + private val countryRepository = CountryRepository { DatabaseTest.getSession() } + private val simulcastRepository = SimulcastRepository { DatabaseTest.getSession() } private val animeRepository = AnimeRepository { DatabaseTest.getSession() } @BeforeEach fun tearUp() { - val anime = Anime(country = Country(tag = "fr", name = "France"), name = "One Piece", image = "hello") - animeRepository.save(anime) + countryRepository.save(Country(tag = "fr", name = "France")) + val country = countryRepository.getAll().first() + + val anime1 = Anime(country = country, name = "One Piece", image = "hello") + val anime2 = Anime(country = country, name = "Naruto", image = "hello") + val anime3 = Anime(country = country, name = "Bleach", image = "hello") + animeRepository.saveAll(listOf(anime1, anime2, anime3)) } @AfterEach @@ -25,34 +33,138 @@ internal class AnimeRepositoryTest { } @Test - fun getAll() { + fun find() { + val anime = animeRepository.find(UUID.randomUUID()) + expect(null) { anime } + val animes = animeRepository.getAll() - expect(1) { animes.size } + expect(animes.first().uuid) { animeRepository.find(animes.first().uuid)?.uuid } } @Test - fun find() { - val anime = animeRepository.find(UUID.randomUUID()) - expect(null) { anime } + fun exists() { + expect(true) { animeRepository.exists("name", "One Piece") } + expect(false) { animeRepository.exists("uuid", UUID.randomUUID()) } + } + + @Test + fun findAll() { + expect(emptyList()) { animeRepository.findAll(listOf(UUID.randomUUID())) } + + val animes = animeRepository.getAll() + val list = animeRepository.findAll(listOf(animes.first().uuid, animes[1].uuid)) + + expect(true) { list.any { it.uuid == animes.first().uuid } && list.any { it.uuid == animes[1].uuid } } + expect(false) { list.any { it.uuid == animes[2].uuid } } + } + + @Test + fun getAll() { + expect(3) { animeRepository.getAll().size } } @Test fun save() { - assertThrows { animeRepository.save(Anime(country = Country(tag = "fr", name = "France"), name = "Naruto", image = "hello")) } + assertThrows { + animeRepository.save( + Anime( + country = Country(tag = "fr", name = "France"), + name = "Naruto", + image = "hello" + ) + ) + } val anime = Anime(country = Country(tag = "us", name = "United States"), name = "Naruto", image = "hello") animeRepository.save(anime) - expect(2) { animeRepository.getAll().size } + expect(4) { animeRepository.getAll().size } checkNotNull { anime.uuid } expect("Naruto") { anime.name } } + @Test + fun saveAll() { + assertThrows { + animeRepository.saveAll( + listOf( + Anime( + country = Country(tag = "fr", name = "France"), + name = "Naruto", + image = "hello" + ) + ) + ) + } + + val anime1 = Anime(country = Country(tag = "us", name = "United States"), name = "Naruto", image = "hello") + val anime2 = Anime(country = Country(tag = "uk", name = "United Kingdom"), name = "Bleach", image = "hello") + animeRepository.saveAll(listOf(anime1, anime2)) + + expect(5) { animeRepository.getAll().size } + checkNotNull { anime1.uuid } + checkNotNull { anime2.uuid } + expect("Naruto") { anime1.name } + expect("Bleach") { anime2.name } + } + @Test fun delete() { - assertThrows { animeRepository.delete(Anime(country = Country(tag = "fr", name = "France"), name = "Naruto", image = "hello")) } + assertThrows { + animeRepository.delete( + Anime( + country = Country(tag = "fr", name = "France"), + name = "Naruto", + image = "hello" + ) + ) + } + + val animes = animeRepository.getAll() + animeRepository.delete(animes.first()) + expect(2) { animes.size - 1 } + } + + @Test + fun findByHash() { + val anime = animeRepository.getAll().first() + anime.hashes.add("hello") + animeRepository.save(anime) + + val anime2 = animeRepository.findByHash("fr", "hello") + expect(anime.uuid) { anime2 } + } + + @Test + fun findByName() { + // TODO: Add episode + val animes = animeRepository.findByName("fr", "Naruto") + expect(0) { animes.size } + } + + @Test + fun getByPage() { + simulcastRepository.save(Simulcast(season = "TEST", year = 2022)) + val simulcast = simulcastRepository.getAll().first() + + val animes = animeRepository.getAll() + animes.forEach { it.simulcasts.add(simulcast) } + animeRepository.saveAll(animes) + + val page1 = animeRepository.getByPage("fr", simulcast.uuid, 1, 2) + expect(2) { page1.size } + val page2 = animeRepository.getByPage("fr", simulcast.uuid, 2, 2) + expect(1) { page2.size } + } + + @Test + fun findByPage() { + val animes = animeRepository.getAll() + val uuids = listOf(animes[0].uuid, animes[1].uuid, animes[2].uuid) - animeRepository.delete(animeRepository.getAll().first()) - expect(0) { animeRepository.getAll().size } + val page1 = animeRepository.findAllByPage(uuids, 1, 2) + expect(2) { page1.size } + val page2 = animeRepository.findAllByPage(uuids, 2, 2) + expect(1) { page2.size } } } diff --git a/src/test/kotlin/fr/ziedelth/repositories/CountryRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/CountryRepositoryTest.kt new file mode 100644 index 0000000..d465546 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/CountryRepositoryTest.kt @@ -0,0 +1,106 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.Country +import fr.ziedelth.utils.DatabaseTest +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.util.* +import kotlin.test.expect + +internal class CountryRepositoryTest { + private val countryRepository = CountryRepository { DatabaseTest.getSession() } + + @BeforeEach + fun tearUp() { + countryRepository.saveAll(listOf(Country(tag = "fr", name = "France"), Country(tag = "jp", name = "Japan"))) + } + + @AfterEach + fun tearDown() { + DatabaseTest.clean() + } + + @Test + fun find() { + val country = countryRepository.find(UUID.randomUUID()) + expect(null) { country } + + val countries = countryRepository.getAll() + expect(countries.first().uuid) { countryRepository.find(countries.first().uuid)?.uuid } + } + + @Test + fun exists() { + expect(true) { countryRepository.exists("tag", "fr") } + expect(false) { countryRepository.exists("uuid", UUID.randomUUID()) } + } + + @Test + fun findAll() { + expect(emptyList()) { countryRepository.findAll(listOf(UUID.randomUUID())) } + + val countries = countryRepository.getAll() + val list = countryRepository.findAll(listOf(countries[0].uuid, countries[1].uuid)) + + expect(true) { list.any { it.uuid == countries.first().uuid } && list.any { it.uuid == countries[1].uuid } } + } + + @Test + fun getAll() { + expect(2) { countryRepository.getAll().size } + } + + @Test + fun save() { + assertThrows { + countryRepository.save(Country(tag = "fr", name = "France")) + } + + val country = Country(tag = "us", name = "United States") + countryRepository.save(country) + + expect(3) { countryRepository.getAll().size } + checkNotNull { country.uuid } + expect("United States") { country.name } + } + + @Test + fun saveAll() { + assertThrows { + countryRepository.saveAll( + listOf( + Country(tag = "fr", name = "France"), + Country(tag = "jp", name = "Japan") + ) + ) + } + + val country1 = Country(tag = "us", name = "United States") + val country2 = Country(tag = "uk", name = "United Kingdom") + countryRepository.saveAll(listOf(country1, country2)) + + expect(4) { countryRepository.getAll().size } + checkNotNull { country1.uuid } + checkNotNull { country2.uuid } + expect("United States") { country1.name } + expect("United Kingdom") { country2.name } + } + + @Test + fun delete() { + assertThrows { + countryRepository.delete( + Country( + tag = "fr", + name = "France" + ) + ) + } + + val countries = countryRepository.getAll() + countryRepository.delete(countries.first()) + expect(1) { countries.size - 1 } + } +} diff --git a/src/test/kotlin/fr/ziedelth/utils/DatabaseTest.kt b/src/test/kotlin/fr/ziedelth/utils/DatabaseTest.kt index 6bd7b19..0ed51c7 100644 --- a/src/test/kotlin/fr/ziedelth/utils/DatabaseTest.kt +++ b/src/test/kotlin/fr/ziedelth/utils/DatabaseTest.kt @@ -14,7 +14,10 @@ object DatabaseTest { init { try { - val file = File(javaClass.classLoader.getResource("hibernate.cfg.xml")?.file ?: throw Exception("hibernate.cfg.xml not found")) + val file = File( + javaClass.classLoader.getResource("hibernate.cfg.xml")?.file + ?: throw Exception("hibernate.cfg.xml not found") + ) Configuration().let { configuration -> getEntities().forEach { configuration.addAnnotatedClass(it) } @@ -33,7 +36,6 @@ object DatabaseTest { private fun getEntities(): MutableSet> = Reflections("fr.ziedelth.entities").getSubTypesOf(Serializable::class.java) - fun getSessionFactory() = sessionFactory fun getSession(): Session = sessionFactory.openSession() fun clean() { diff --git a/src/test/resources/hibernate.cfg.xml b/src/test/resources/hibernate.cfg.xml index f6eb3fc..7522471 100644 --- a/src/test/resources/hibernate.cfg.xml +++ b/src/test/resources/hibernate.cfg.xml @@ -10,7 +10,7 @@ org.hibernate.dialect.H2Dialect - true + false create-drop \ No newline at end of file From 5cce6dbbea8c2d2752b3b64c92aa3f214ce53681 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 9 Nov 2022 16:49:20 +0100 Subject: [PATCH 04/35] Fix --- pom.xml | 11 + .../ziedelth/controllers/AnimeController.kt | 162 ++++++------ src/main/kotlin/fr/ziedelth/entities/Anime.kt | 10 +- .../kotlin/fr/ziedelth/entities/Episode.kt | 16 ++ src/main/kotlin/fr/ziedelth/entities/Manga.kt | 14 + src/main/kotlin/fr/ziedelth/plugins/HTTP.kt | 20 +- .../kotlin/fr/ziedelth/plugins/Routing.kt | 13 +- .../repositories/EpisodeRepository.kt | 7 + .../repositories/EpisodeTypeRepository.kt | 7 + .../fr/ziedelth/repositories/IRepository.kt | 38 ++- .../repositories/LangTypeRepository.kt | 7 + .../ziedelth/repositories/MangaRepository.kt | 7 + .../repositories/PlatformRepository.kt | 7 + .../kotlin/fr/ziedelth/AbstractAPITest.kt | 92 +++++++ .../controllers/AnimeControllerTest.kt | 250 ++++++++++++++++++ .../kotlin/fr/ziedelth/plugins/RoutingTest.kt | 38 +++ .../repositories/AnimeRepositoryTest.kt | 68 +++-- .../repositories/CountryRepositoryTest.kt | 19 +- .../{ => utils/plugins}/PluginManagerTest.kt | 3 +- 19 files changed, 626 insertions(+), 163 deletions(-) create mode 100644 src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt create mode 100644 src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt create mode 100644 src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt create mode 100644 src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt create mode 100644 src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt create mode 100644 src/test/kotlin/fr/ziedelth/AbstractAPITest.kt create mode 100644 src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt rename src/test/kotlin/fr/ziedelth/{ => utils/plugins}/PluginManagerTest.kt (91%) diff --git a/pom.xml b/pom.xml index fc6b522..956ece2 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,11 @@ 2.1.214 test + + io.ktor + ktor-server-test-host-jvm + ${ktor_version} + io.ktor ktor-server-core-jvm @@ -73,6 +78,12 @@ ktor-server-content-negotiation-jvm ${ktor_version} + + io.ktor + ktor-client-content-negotiation-jvm + ${ktor_version} + test + io.ktor ktor-serialization-gson-jvm diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index e0d514b..e7d73bd 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -5,6 +5,8 @@ import fr.ziedelth.entities.Anime import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.repositories.AnimeRepository import fr.ziedelth.repositories.CountryRepository +import fr.ziedelth.repositories.EpisodeRepository +import fr.ziedelth.repositories.MangaRepository import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache import fr.ziedelth.utils.RequestCache @@ -16,12 +18,17 @@ import io.ktor.server.routing.* import io.ktor.util.pipeline.* import java.util.* -class AnimeController(private val countryRepository: CountryRepository, private val animeRepository: AnimeRepository) : +class AnimeController( + private val countryRepository: CountryRepository, + private val animeRepository: AnimeRepository, + private val episodeRepository: EpisodeRepository, + private val mangaRepository: MangaRepository +) : IController("/animes") { fun getRoutes(routing: Routing) { routing.route(prefix) { search() - getWithPage() + getByPage() getWatchlistWithPage() getAttachment() create() @@ -32,26 +39,26 @@ class AnimeController(private val countryRepository: CountryRepository, private private fun Route.search() { route("/country/{country}/search") { get("/hash/{hash}") { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val hash = call.parameters["hash"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val country = call.parameters["country"]!! + val hash = call.parameters["hash"]!! println("GET $prefix/country/$country/search/hash/$hash") call.respond(mapOf("uuid" to animeRepository.findByHash(country, hash))) } get("/name/{name}") { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val name = call.parameters["name"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val country = call.parameters["country"]!! + val name = call.parameters["name"]!! println("GET $prefix/country/$country/search/name/$name") call.respond(animeRepository.findByName(country, name)) } } } - private fun Route.getWithPage() { + private fun Route.getByPage() { get("/country/{country}/simulcast/{simulcast}/page/{page}/limit/{limit}") { try { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val simulcast = call.parameters["simulcast"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val country = call.parameters["country"]!! + val simulcast = call.parameters["simulcast"]!! val (page, limit) = getPageAndLimit() println("GET $prefix/country/$country/simulcast/$simulcast/page/$page/limit/$limit") val request = RequestCache.get(uuidRequest, country, page, limit, simulcast) @@ -61,9 +68,7 @@ class AnimeController(private val countryRepository: CountryRepository, private request?.update(list) ?: RequestCache.put(uuidRequest, country, page, limit, simulcast, list) } - call.respond( - RequestCache.get(uuidRequest, country, page, limit, simulcast)?.value ?: HttpStatusCode.NotFound - ) + call.respond(RequestCache.get(uuidRequest, country, page, limit, simulcast)!!.value!!) } catch (e: Exception) { printError(call, e) } @@ -116,16 +121,13 @@ class AnimeController(private val countryRepository: CountryRepository, private val hash = anime.hash() - if (contains("hashes", hash)) { + if (animeRepository.findByHash(anime.country!!.tag!!, hash) != null) { println("$entityName already exists") call.respond(HttpStatusCode.Conflict, "$entityName already exists") return@post } - if (!(anime.hashes.contains(hash))) { - anime.hashes.add(hash!!) - } - + anime.hashes.add(hash) val savedAnime = animeRepository.save(anime) ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!) call.respond(HttpStatusCode.Created, savedAnime) @@ -137,73 +139,65 @@ class AnimeController(private val countryRepository: CountryRepository, private private fun Route.merge() { put("/merge") { -// // Get list of uuids -// val uuids = call.receive>().map { UUID.fromString(it) } -// println("PUT $prefix/merge") -// // Get anime -// val animes = uuids.mapNotNull { getBy("uuid", it) } -// -// if (animes.isEmpty()) { -// println("Anime not found") -// call.respond(HttpStatusCode.NotFound, "Anime not found") -// return@put -// } -// -// // Get all countries -// val countries = animes.map { it.country }.distinctBy { it?.uuid } -// -// if (countries.size > 1) { -// println("Anime has different countries") -// call.respond(HttpStatusCode.BadRequest, "Anime has different countries") -// return@put -// } -// -// // Get all hashes -// val hashes = animes.map { it.hashes }.flatten().distinct().toMutableSet() -// // Get all genres -// val genres = animes.map { it.genres }.flatten().distinctBy { it.uuid }.toMutableSet() -// // Get all simulcasts -// val simulcasts = animes.map { it.simulcasts }.flatten().distinctBy { it.uuid }.toMutableSet() -// // Get all episodes -// val episodes = -// animes.map { EpisodeController.getAllBy("anime.uuid", it.uuid) }.flatten().distinctBy { it.uuid } -// .toMutableSet() -// // Get all mangas -// val mangas = animes.map { MangaController.getAllBy("anime.uuid", it.uuid) }.flatten().distinctBy { it.uuid } -// .toMutableSet() -// -// val firstAnime = animes.first() -// val mergedAnime = Anime( -// country = countries.first(), -// name = "${animes.first().name} (${animes.size})", -// releaseDate = firstAnime.releaseDate, -// image = firstAnime.image, -// description = firstAnime.description, -// hashes = hashes, -// genres = genres, -// simulcasts = simulcasts -// ) -// -// val savedAnime = justSave(mergedAnime) -// ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!) -// episodes.map { it.copy(anime = savedAnime) }.map { EpisodeController.justSave(it) } -// mangas.map { it.copy(anime = savedAnime) }.map { MangaController.justSave(it) } -// -// // Delete animes -// val session = Database.getSession() -// val transaction = session.beginTransaction() -// -// try { -// session.remove(animes) -// transaction.commit() -// } catch (e: Exception) { -// e.printStackTrace() -// println("Error while deleting $prefix : ${e.message}") -// transaction.rollback() -// throw e -// } finally { -// session.close() -// } + // Get list of uuids + val uuids = call.receive>().map { UUID.fromString(it) } + println("PUT $prefix/merge") + // Get anime + val animes = uuids.mapNotNull { animeRepository.find(it) } + + if (animes.isEmpty()) { + println("Anime not found") + call.respond(HttpStatusCode.NotFound, "Anime not found") + return@put + } + + // Get all countries + val countries = animes.map { it.country }.distinctBy { it?.uuid } + + if (countries.size > 1) { + println("Anime has different countries") + call.respond(HttpStatusCode.BadRequest, "Anime has different countries") + return@put + } + + // Get all hashes + val hashes = animes.map { it.hashes }.flatten().distinct().toMutableSet() + // Get all genres + val genres = animes.map { it.genres }.flatten().distinctBy { it.uuid }.toMutableSet() + // Get all simulcasts + val simulcasts = animes.map { it.simulcasts }.flatten().distinctBy { it.uuid }.toMutableSet() + // Get all episodes + val episodes = + animes.map { episodeRepository.getAllBy("anime.uuid", it.uuid) }.flatten().distinctBy { it.uuid } + .toMutableSet() + // Get all mangas + val mangas = animes.map { mangaRepository.getAllBy("anime.uuid", it.uuid) }.flatten().distinctBy { it.uuid } + .toMutableSet() + + val firstAnime = animes.first() + + val savedAnime = animeRepository.find( + animeRepository.save( + Anime( + country = countries.first(), + name = "${animes.first().name} (${animes.size})", + releaseDate = firstAnime.releaseDate, + image = firstAnime.image, + description = firstAnime.description, + hashes = hashes, + genres = genres, + simulcasts = simulcasts + ) + ).uuid + )!! + + ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!) + episodes.map { it.copy(anime = savedAnime) }.map { episodeRepository.save(it) } + mangas.map { it.copy(anime = savedAnime) }.map { mangaRepository.save(it) } + + // Delete animes + animeRepository.deleteAll(animes) + call.respond(HttpStatusCode.OK, savedAnime) } } } diff --git a/src/main/kotlin/fr/ziedelth/entities/Anime.kt b/src/main/kotlin/fr/ziedelth/entities/Anime.kt index d013768..d61b5a3 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Anime.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Anime.kt @@ -16,7 +16,7 @@ class Anime( @Id @GeneratedValue val uuid: UUID = UUID.randomUUID(), - @ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) + @ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.MERGE, CascadeType.PERSIST]) @JoinColumn( name = "country_uuid", nullable = false, @@ -39,7 +39,7 @@ class Anime( foreignKey = ForeignKey(foreignKeyDefinition = "FOREIGN KEY (anime_uuid) REFERENCES anime (uuid) ON DELETE CASCADE") ) val hashes: MutableSet = mutableSetOf(), - @ManyToMany(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) + @ManyToMany(fetch = FetchType.EAGER, cascade = [CascadeType.MERGE, CascadeType.PERSIST]) @JoinTable( name = "anime_genre", joinColumns = [ @@ -56,7 +56,7 @@ class Anime( ] ) val genres: MutableSet = mutableSetOf(), - @ManyToMany(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) + @ManyToMany(fetch = FetchType.EAGER, cascade = [CascadeType.MERGE, CascadeType.PERSIST]) @JoinTable( name = "anime_simulcast", joinColumns = [ @@ -74,8 +74,8 @@ class Anime( ) val simulcasts: MutableSet = mutableSetOf(), ) : Serializable { - fun hash(): String? = name?.lowercase()?.filter { it.isLetterOrDigit() || it.isWhitespace() || it == '-' }?.trim() - ?.replace("\\s+".toRegex(), "-")?.replace("--", "-") + fun hash(): String = name!!.lowercase().filter { it.isLetterOrDigit() || it.isWhitespace() || it == '-' }.trim() + .replace("\\s+".toRegex(), "-").replace("--", "-") fun isNotValid(): Boolean = country.isNullOrNotValid() || name.isNullOrBlank() || ( releaseDate.isBlank() || !releaseDate.matches( diff --git a/src/main/kotlin/fr/ziedelth/entities/Episode.kt b/src/main/kotlin/fr/ziedelth/entities/Episode.kt index 76f92ff..6a19dcb 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Episode.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Episode.kt @@ -57,4 +57,20 @@ class Episode( platform.isNullOrNotValid() || anime.isNullOrNotValid() || episodeType.isNullOrNotValid() || langType.isNullOrNotValid() || hash.isNullOrBlank() || ( releaseDate.isBlank() || !releaseDate.matches(DATE_FORMAT_REGEX) ) || season == null || number == null || url.isNullOrBlank() || image.isNullOrBlank() + + fun copy(anime: Anime? = this.anime) = Episode( + this.uuid, + platform, + anime, + episodeType, + langType, + hash, + releaseDate, + season, + number, + title, + url, + image, + duration + ) } diff --git a/src/main/kotlin/fr/ziedelth/entities/Manga.kt b/src/main/kotlin/fr/ziedelth/entities/Manga.kt index 86570b5..1ffba18 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Manga.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Manga.kt @@ -45,4 +45,18 @@ class Manga( platform.isNullOrNotValid() || anime.isNullOrNotValid() || hash.isNullOrBlank() || (releaseDate.isBlank() || !releaseDate.matches( DATE_FORMAT_REGEX )) || url.isNullOrBlank() || cover.isNullOrBlank() || editor.isNullOrBlank() + + fun copy(anime: Anime? = this.anime) = Manga( + platform = platform, + anime = anime, + hash = hash, + releaseDate = releaseDate, + url = url, + cover = cover, + editor = editor, + ref = ref, + ean = ean, + age = age, + price = price + ) } diff --git a/src/main/kotlin/fr/ziedelth/plugins/HTTP.kt b/src/main/kotlin/fr/ziedelth/plugins/HTTP.kt index 855a1f0..f38c65c 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/HTTP.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/HTTP.kt @@ -1,11 +1,11 @@ package fr.ziedelth.plugins import io.ktor.http.* +import io.ktor.serialization.gson.* import io.ktor.server.application.* import io.ktor.server.plugins.compression.* +import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.plugins.cors.routing.* -import io.ktor.server.websocket.* -import java.time.Duration fun Application.configureHTTP() { install(Compression) { @@ -17,16 +17,22 @@ fun Application.configureHTTP() { minimumSize(1024) // condition } } + install(CORS) { HttpMethod.DefaultMethods.forEach { allowMethod(it) } allowHeader(HttpHeaders.Authorization) anyHost() } - install(WebSockets) { - pingPeriod = Duration.ofSeconds(15) - timeout = Duration.ofSeconds(15) - maxFrameSize = Long.MAX_VALUE - masking = false + install(ContentNegotiation) { + gson { + } } + +// install(WebSockets) { +// pingPeriod = Duration.ofSeconds(15) +// timeout = Duration.ofSeconds(15) +// maxFrameSize = Long.MAX_VALUE +// masking = false +// } } diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index a6b41a2..45fb147 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -9,26 +9,23 @@ import fr.ziedelth.controllers.PlatformController.getPlatforms import fr.ziedelth.controllers.SimulcastController.getSimulcasts import fr.ziedelth.repositories.AnimeRepository import fr.ziedelth.repositories.CountryRepository -import io.ktor.serialization.gson.* +import fr.ziedelth.repositories.EpisodeRepository +import fr.ziedelth.repositories.MangaRepository import io.ktor.server.application.* -import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.routing.* fun Application.configureRouting() { - install(ContentNegotiation) { - gson { - } - } - routing { val countryRepository = CountryRepository() val animeRepository = AnimeRepository() + val episodeRepository = EpisodeRepository() + val mangaRepository = MangaRepository() CountryController(countryRepository).getRoutes(this) getPlatforms() getSimulcasts() getGenres() - AnimeController(countryRepository, animeRepository).getRoutes(this) + AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) getEpisodeTypes() getLangTypes() EpisodeController(animeRepository).getRoutes(this) diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt new file mode 100644 index 0000000..8ca2370 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt @@ -0,0 +1,7 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.Episode +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class EpisodeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt new file mode 100644 index 0000000..27b8200 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt @@ -0,0 +1,7 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.EpisodeType +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class EpisodeTypeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt index 7707756..bc687db 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt @@ -43,14 +43,24 @@ open class IRepository(val getSession: () -> Session = { Database.getSession( return list } + fun getAllBy(field: String, value: Any?): MutableList { + val session = getSession.invoke() + val query = session.createQuery("FROM $entityName WHERE $field = :value", entityClass) + query.setParameter("value", value) + val list = query.list() + session.close() + return list + } + fun save(entity: T): T { val session = getSession.invoke() val transaction = session.beginTransaction() try { - session.persist(session.merge(entity)) + val mergedEntity = session.merge(entity) + session.persist(mergedEntity) transaction.commit() - return entity + return mergedEntity } catch (e: Exception) { transaction.rollback() throw e @@ -64,9 +74,14 @@ open class IRepository(val getSession: () -> Session = { Database.getSession( val transaction = session.beginTransaction() try { - entities.forEach { session.persist(session.merge(it)) } + val mergedEntities = entities.map { + val mergedEntity = session.merge(it) + session.persist(mergedEntity) + mergedEntity + } + transaction.commit() - return entities + return mergedEntities } catch (e: Exception) { transaction.rollback() throw e @@ -89,4 +104,19 @@ open class IRepository(val getSession: () -> Session = { Database.getSession( session.close() } } + + fun deleteAll(entities: List) { + val session = getSession.invoke() + val transaction = session.beginTransaction() + + try { + entities.forEach { session.remove(session.merge(it)) } + transaction.commit() + } catch (e: Exception) { + transaction.rollback() + throw e + } finally { + session.close() + } + } } diff --git a/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt new file mode 100644 index 0000000..8038ef7 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt @@ -0,0 +1,7 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.LangType +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class LangTypeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt new file mode 100644 index 0000000..ddda5f6 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt @@ -0,0 +1,7 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.Manga +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class MangaRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt new file mode 100644 index 0000000..a0f2966 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt @@ -0,0 +1,7 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.Platform +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class PlatformRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt b/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt new file mode 100644 index 0000000..3a5856a --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt @@ -0,0 +1,92 @@ +package fr.ziedelth + +import fr.ziedelth.entities.* +import fr.ziedelth.plugins.* +import fr.ziedelth.utils.DatabaseTest +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach + +internal abstract class AbstractAPITest { + @BeforeEach + fun tearUp() { + countryRepository.saveAll( + listOf( + Country(tag = "fr", name = "France"), + Country(tag = "jp", name = "Japan") + ) + ) + val countries = countryRepository.getAll() + + val platform1 = Platform(name = "Netflix", image = "hello", url = "hello") + val platform2 = Platform(name = "Crunchyroll", image = "hello", url = "hello") + val platform3 = Platform(name = "Wakanim", image = "hello", url = "hello") + platformRepository.saveAll(listOf(platform1, platform2, platform3)) + val platforms = platformRepository.getAll() + + val simulcast = Simulcast(season = "Winter", year = 2020) + simulcastRepository.save(simulcast) + val simulcasts = simulcastRepository.getAll() + + val anime1 = Anime( + country = countries.first(), + name = "One Piece", + image = "hello", + hashes = mutableSetOf("hello"), + simulcasts = mutableSetOf(simulcasts.random()) + ) + val anime2 = Anime( + country = countries.first(), + name = "Naruto", + image = "hello", + hashes = mutableSetOf("hello2"), + simulcasts = mutableSetOf(simulcasts.random()) + ) + val anime3 = Anime( + country = countries.first(), + name = "Bleach", + image = "hello", + hashes = mutableSetOf("hello3"), + simulcasts = mutableSetOf(simulcasts.random()) + ) + animeRepository.saveAll(listOf(anime1, anime2, anime3)) + val animes = animeRepository.getAll() + + val episodeType1 = EpisodeType(name = "Episode") + val episodeType2 = EpisodeType(name = "OAV") + val episodeType3 = EpisodeType(name = "Film") + episodeTypeRepository.saveAll(listOf(episodeType1, episodeType2, episodeType3)) + val episodeTypes = episodeTypeRepository.getAll() + + val langType1 = LangType(name = "SUBTITLES") + val langType2 = LangType(name = "VOICE") + langTypeRepository.saveAll(listOf(langType1, langType2)) + val langTypes = langTypeRepository.getAll() + + animes.forEach { + val episodes = (1..10).map { episode -> + val platform = platforms.random() + val episodeType = episodeTypes.random() + val langType = langTypes.random() + + Episode( + platform = platform, + anime = it, + episodeType = episodeType, + langType = langType, + hash = "EP-$episode-${platform.name}-${episodeType.name}-${langType.name}-${Math.random()}", + season = 1, + number = episode, + url = "hello", + image = "hello", + duration = 1440 + ) + } + episodeRepository.saveAll(episodes) + } + } + + @AfterEach + fun tearDown() { + DatabaseTest.clean() + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt new file mode 100644 index 0000000..2bbad31 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt @@ -0,0 +1,250 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import com.google.gson.JsonObject +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.Anime +import fr.ziedelth.entities.Country +import fr.ziedelth.plugins.* +import fr.ziedelth.utils.Encoder +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class AnimeControllerTest : AbstractAPITest() { + @Test + fun searchByHash() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.get("/animes/country/fr/search/hash/hello") + val json = Gson().fromJson(response.bodyAsText(), JsonObject::class.java) + val uuid = json.get("uuid").asString + + expect(HttpStatusCode.OK) { response.status } + checkNotNull(uuid) + } + } + + @Test + fun searchByName() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.get("/animes/country/fr/search/name/Naruto") + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { response.status } + expect(1) { json.size } + } + } + + @Test + fun getByPage() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val simulcast = simulcastRepository.getAll().first() + + // NOT CACHED + + val responseNotCached = client.get("/animes/country/fr/simulcast/${simulcast.uuid}/page/1/limit/12") + val jsonNotCached = Gson().fromJson(responseNotCached.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { responseNotCached.status } + expect(3) { jsonNotCached.size } + + // CACHED + + val responseCached = client.get("/animes/country/fr/simulcast/${simulcast.uuid}/page/1/limit/12") + val jsonCached = Gson().fromJson(responseCached.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { responseCached.status } + expect(3) { jsonCached.size } + } + } + + @Test + fun getByPageError() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val simulcast = simulcastRepository.getAll().first() + + // ERROR + + val responseError = client.get("/animes/country/fr/simulcast/${simulcast.uuid}/page/ae/limit/12") + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun getWatchlistByPage() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val anime = animeRepository.getAll().first() + val bodyRequest = Encoder.toGzip("[\"${anime.uuid}\"]") + + val response = client.post("/animes/watchlist/page/1/limit/12") { + setBody(bodyRequest) + } + + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { response.status } + expect(1) { json.size } + + // ERROR + + val responseError = client.post("/animes/watchlist/page/ae/limit/12") { + setBody(bodyRequest) + } + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun getWatchlistByPageError() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val anime = animeRepository.getAll().first() + val bodyRequest = Encoder.toGzip("[\"${anime.uuid}\"]") + + val responseError = client.post("/animes/watchlist/page/ae/limit/12") { + setBody(bodyRequest) + } + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun create() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + + val response = client.post("/animes") { + contentType(ContentType.Application.Json) + setBody(Anime(country = country, name = "Test", description = "Test", image = "Test")) + } + + val json = Gson().fromJson(response.bodyAsText(), Anime::class.java) + + expect(HttpStatusCode.Created) { response.status } + checkNotNull(json.uuid) + } + } + + @Test + fun createError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + + expect(HttpStatusCode.BadRequest) { + client.post("/animes") { + contentType(ContentType.Application.Json) + setBody( + Anime( + country = Country(tag = "us", name = "United States"), + name = "Test", + description = "Test", + image = "Test" + ) + ) + }.status + } + + expect(HttpStatusCode.BadRequest) { + client.post("/animes") { + contentType(ContentType.Application.Json) + setBody(Anime(country = country, description = "Test", image = "Test")) + }.status + } + + expect(HttpStatusCode.Conflict) { + client.post("/animes") { + contentType(ContentType.Application.Json) + setBody(Anime(country = country, name = "One Piece", description = "Test", image = "Test")) + }.status + } + } + } + + @Test + fun merge() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val animes = animeRepository.getAll() + val uuids = animes.map { it.uuid.toString() } + + val response = client.put("/animes/merge") { + contentType(ContentType.Application.Json) + setBody(uuids) + } + + expect(HttpStatusCode.OK) { response.status } + expect(1) { animeRepository.getAll().size } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt new file mode 100644 index 0000000..15c0d41 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -0,0 +1,38 @@ +package fr.ziedelth.plugins + +import fr.ziedelth.controllers.* +import fr.ziedelth.controllers.DiaryController.getDiary +import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes +import fr.ziedelth.controllers.GenreController.getGenres +import fr.ziedelth.controllers.LangTypeController.getLangTypes +import fr.ziedelth.controllers.PlatformController.getPlatforms +import fr.ziedelth.controllers.SimulcastController.getSimulcasts +import fr.ziedelth.repositories.* +import fr.ziedelth.utils.DatabaseTest +import io.ktor.server.application.* +import io.ktor.server.routing.* + +val countryRepository = CountryRepository { DatabaseTest.getSession() } +val platformRepository = PlatformRepository { DatabaseTest.getSession() } +val simulcastRepository = SimulcastRepository { DatabaseTest.getSession() } +val animeRepository = AnimeRepository { DatabaseTest.getSession() } +val episodeTypeRepository = EpisodeTypeRepository { DatabaseTest.getSession() } +val langTypeRepository = LangTypeRepository { DatabaseTest.getSession() } +val episodeRepository = EpisodeRepository { DatabaseTest.getSession() } +val mangaRepository = MangaRepository { DatabaseTest.getSession() } + +fun Application.configureRoutingTest() { + routing { + CountryController(countryRepository).getRoutes(this) + getPlatforms() + getSimulcasts() + getGenres() + AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) + getEpisodeTypes() + getLangTypes() + EpisodeController(animeRepository).getRoutes(this) + NewsController(countryRepository).getRoutes(this) + MangaController(animeRepository).getRoutes(this) + getDiary() + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt index 979b150..320e8f9 100644 --- a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt +++ b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt @@ -1,37 +1,16 @@ package fr.ziedelth.repositories +import fr.ziedelth.AbstractAPITest import fr.ziedelth.entities.Anime import fr.ziedelth.entities.Country -import fr.ziedelth.entities.Simulcast -import fr.ziedelth.utils.DatabaseTest -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeEach +import fr.ziedelth.plugins.animeRepository +import fr.ziedelth.plugins.simulcastRepository import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import java.util.* import kotlin.test.expect -internal class AnimeRepositoryTest { - private val countryRepository = CountryRepository { DatabaseTest.getSession() } - private val simulcastRepository = SimulcastRepository { DatabaseTest.getSession() } - private val animeRepository = AnimeRepository { DatabaseTest.getSession() } - - @BeforeEach - fun tearUp() { - countryRepository.save(Country(tag = "fr", name = "France")) - val country = countryRepository.getAll().first() - - val anime1 = Anime(country = country, name = "One Piece", image = "hello") - val anime2 = Anime(country = country, name = "Naruto", image = "hello") - val anime3 = Anime(country = country, name = "Bleach", image = "hello") - animeRepository.saveAll(listOf(anime1, anime2, anime3)) - } - - @AfterEach - fun tearDown() { - DatabaseTest.clean() - } - +internal class AnimeRepositoryTest : AbstractAPITest() { @Test fun find() { val anime = animeRepository.find(UUID.randomUUID()) @@ -63,6 +42,12 @@ internal class AnimeRepositoryTest { expect(3) { animeRepository.getAll().size } } + @Test + fun getAllByCountry() { + expect(3) { animeRepository.getAllBy("country.tag", "fr").size } + expect(0) { animeRepository.getAllBy("country.tag", "us").size } + } + @Test fun save() { assertThrows { @@ -126,31 +111,40 @@ internal class AnimeRepositoryTest { } @Test - fun findByHash() { - val anime = animeRepository.getAll().first() - anime.hashes.add("hello") - animeRepository.save(anime) + fun deleteAll() { + assertThrows { + animeRepository.deleteAll( + listOf( + Anime( + country = Country(tag = "fr", name = "France"), + name = "Naruto", + image = "hello" + ) + ) + ) + } + val animes = animeRepository.getAll() + animeRepository.deleteAll(listOf(animes.first(), animes[1])) + expect(1) { animes.size - 2 } + } + + @Test + fun findByHash() { val anime2 = animeRepository.findByHash("fr", "hello") - expect(anime.uuid) { anime2 } + checkNotNull { anime2 } } @Test fun findByName() { - // TODO: Add episode val animes = animeRepository.findByName("fr", "Naruto") - expect(0) { animes.size } + expect(1) { animes.size } } @Test fun getByPage() { - simulcastRepository.save(Simulcast(season = "TEST", year = 2022)) val simulcast = simulcastRepository.getAll().first() - val animes = animeRepository.getAll() - animes.forEach { it.simulcasts.add(simulcast) } - animeRepository.saveAll(animes) - val page1 = animeRepository.getByPage("fr", simulcast.uuid, 1, 2) expect(2) { page1.size } val page2 = animeRepository.getByPage("fr", simulcast.uuid, 2, 2) diff --git a/src/test/kotlin/fr/ziedelth/repositories/CountryRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/CountryRepositoryTest.kt index d465546..c9f28a8 100644 --- a/src/test/kotlin/fr/ziedelth/repositories/CountryRepositoryTest.kt +++ b/src/test/kotlin/fr/ziedelth/repositories/CountryRepositoryTest.kt @@ -1,27 +1,14 @@ package fr.ziedelth.repositories +import fr.ziedelth.AbstractAPITest import fr.ziedelth.entities.Country -import fr.ziedelth.utils.DatabaseTest -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeEach +import fr.ziedelth.plugins.countryRepository import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import java.util.* import kotlin.test.expect -internal class CountryRepositoryTest { - private val countryRepository = CountryRepository { DatabaseTest.getSession() } - - @BeforeEach - fun tearUp() { - countryRepository.saveAll(listOf(Country(tag = "fr", name = "France"), Country(tag = "jp", name = "Japan"))) - } - - @AfterEach - fun tearDown() { - DatabaseTest.clean() - } - +internal class CountryRepositoryTest : AbstractAPITest() { @Test fun find() { val country = countryRepository.find(UUID.randomUUID()) diff --git a/src/test/kotlin/fr/ziedelth/PluginManagerTest.kt b/src/test/kotlin/fr/ziedelth/utils/plugins/PluginManagerTest.kt similarity index 91% rename from src/test/kotlin/fr/ziedelth/PluginManagerTest.kt rename to src/test/kotlin/fr/ziedelth/utils/plugins/PluginManagerTest.kt index 50deb94..a1ed971 100644 --- a/src/test/kotlin/fr/ziedelth/PluginManagerTest.kt +++ b/src/test/kotlin/fr/ziedelth/utils/plugins/PluginManagerTest.kt @@ -1,7 +1,6 @@ -package fr.ziedelth +package fr.ziedelth.utils.plugins import fr.ziedelth.events.ExampleEvent -import fr.ziedelth.utils.plugins.PluginManager import fr.ziedelth.utils.plugins.events.EventHandler import fr.ziedelth.utils.plugins.events.Listener import org.junit.jupiter.api.Assertions.assertEquals From b9a92f9e0b46df8feefa0d78b38245b802a18fd5 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 10:20:07 +0100 Subject: [PATCH 05/35] Add CI/CD --- .github/workflows/develop.yml | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/develop.yml diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml new file mode 100644 index 0000000..79d3165 --- /dev/null +++ b/.github/workflows/develop.yml @@ -0,0 +1,37 @@ +name: Build +on: + push: + branches: + - master + pull_request: + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Cache SonarQube packages + uses: actions/cache@v1 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + - name: Cache Maven packages + uses: actions/cache@v1 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + - name: Build and analyze + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=API \ No newline at end of file From 68ea42c8ecc598b78b7a76fecd86b00710fa7d0f Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 10:22:29 +0100 Subject: [PATCH 06/35] Change Sonar CI/CD --- .github/workflows/develop.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 79d3165..a11b7aa 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -1,8 +1,8 @@ name: Build on: push: - branches: - - master + branches-ignore: + - stable pull_request: jobs: From b3c23402a23dd2d78c75b2e190f85bfe3525c986 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 10:45:33 +0100 Subject: [PATCH 07/35] More tests --- .../ziedelth/controllers/AnimeController.kt | 6 ++++- .../ziedelth/repositories/AnimeRepository.kt | 14 ++++++++++ .../controllers/AnimeControllerTest.kt | 26 +++++++++++++++++-- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index e7d73bd..4882396 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -113,7 +113,11 @@ class AnimeController( return@post } - if (animeRepository.exists("name", anime.name)) { + if (animeRepository.findOneByName( + anime.country!!.tag!!, + anime.name!! + )?.country?.uuid == anime.country!!.uuid + ) { println("$entityName already exists") call.respond(HttpStatusCode.Conflict, "$entityName already exists") return@post diff --git a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt index 4e0d407..db8f195 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt @@ -20,6 +20,20 @@ class AnimeRepository(session: () -> Session = { Database.getSession() }) : IRep return uuid } + fun findOneByName(tag: String, name: String): Anime? { + val session = getSession.invoke() + val query = session.createQuery( + "FROM Anime WHERE country.tag = :tag AND LOWER(name) = :name", + Anime::class.java + ) + query.maxResults = 1 + query.setParameter("tag", tag) + query.setParameter("name", name.lowercase()) + val uuid = query.uniqueResult() + session.close() + return uuid + } + fun findByName(tag: String, name: String): List { val session = getSession.invoke() val query = session.createQuery( diff --git a/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt index 2bbad31..9638526 100644 --- a/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt +++ b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt @@ -168,9 +168,8 @@ internal class AnimeControllerTest : AbstractAPITest() { setBody(Anime(country = country, name = "Test", description = "Test", image = "Test")) } - val json = Gson().fromJson(response.bodyAsText(), Anime::class.java) - expect(HttpStatusCode.Created) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Anime::class.java) checkNotNull(json.uuid) } } @@ -247,4 +246,27 @@ internal class AnimeControllerTest : AbstractAPITest() { expect(1) { animeRepository.getAll().size } } } + + @Test + fun mergeError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + expect(HttpStatusCode.NotFound) { + client.put("/animes/merge") { + contentType(ContentType.Application.Json) + setBody(emptyList()) + }.status + } + } + } } \ No newline at end of file From 3c72f22b46c6a35837e1955247f89df6805eebe2 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 10:57:21 +0100 Subject: [PATCH 08/35] Add tests for CountryController --- .../ziedelth/controllers/AnimeController.kt | 2 +- .../controllers/CountryControllerTest.kt | 96 +++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/test/kotlin/fr/ziedelth/controllers/CountryControllerTest.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index 4882396..b109cb3 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -156,7 +156,7 @@ class AnimeController( } // Get all countries - val countries = animes.map { it.country }.distinctBy { it?.uuid } + val countries = animes.map { it.country }.distinctBy { it!!.uuid } if (countries.size > 1) { println("Anime has different countries") diff --git a/src/test/kotlin/fr/ziedelth/controllers/CountryControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/CountryControllerTest.kt new file mode 100644 index 0000000..608846c --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/CountryControllerTest.kt @@ -0,0 +1,96 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.Anime +import fr.ziedelth.entities.Country +import fr.ziedelth.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class CountryControllerTest : AbstractAPITest() { + @Test + fun getAll() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.get("/countries") + expect(HttpStatusCode.OK) { response.status } + val jsonNotCached = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(2) { jsonNotCached.size } + } + } + + @Test + fun create() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.post("/countries") { + contentType(ContentType.Application.Json) + setBody(Country(tag = "us", name = "United States")) + } + + expect(HttpStatusCode.Created) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Anime::class.java) + checkNotNull(json.uuid) + } + } + + @Test + fun createError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + expect(HttpStatusCode.BadRequest) { + client.post("/countries") { + contentType(ContentType.Application.Json) + setBody(Country(name = "France")) + }.status + } + + expect(HttpStatusCode.Conflict) { + client.post("/countries") { + contentType(ContentType.Application.Json) + setBody(Country(tag = "fr", name = "Test")) + }.status + } + + expect(HttpStatusCode.Conflict) { + client.post("/countries") { + contentType(ContentType.Application.Json) + setBody(Country(tag = "test", name = "France")) + }.status + } + } + } +} \ No newline at end of file From 4246ed255b3ea52a9baa0418c16ced4b65832999 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 11:26:31 +0100 Subject: [PATCH 09/35] Change diary routes --- .../ziedelth/controllers/AnimeController.kt | 10 ++++++ .../ziedelth/controllers/DiaryController.kt | 36 ------------------- .../kotlin/fr/ziedelth/plugins/Routing.kt | 2 -- .../ziedelth/repositories/AnimeRepository.kt | 13 +++++++ .../kotlin/fr/ziedelth/plugins/RoutingTest.kt | 2 -- .../repositories/AnimeRepositoryTest.kt | 7 ++++ 6 files changed, 30 insertions(+), 40 deletions(-) delete mode 100644 src/main/kotlin/fr/ziedelth/controllers/DiaryController.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index b109cb3..2bf0ff5 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -33,6 +33,7 @@ class AnimeController( getAttachment() create() merge() + diary() } } @@ -204,4 +205,13 @@ class AnimeController( call.respond(HttpStatusCode.OK, savedAnime) } } + + private fun Route.diary() { + get("/diary/country/{country}/day/{day}") { + val country = call.parameters["country"]!! + val day = call.parameters["day"]?.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest) + println("GET $prefix/diary/country/$country/day/$day") + call.respond(animeRepository.getDiary(country, day)) + } + } } diff --git a/src/main/kotlin/fr/ziedelth/controllers/DiaryController.kt b/src/main/kotlin/fr/ziedelth/controllers/DiaryController.kt deleted file mode 100644 index f4223e2..0000000 --- a/src/main/kotlin/fr/ziedelth/controllers/DiaryController.kt +++ /dev/null @@ -1,36 +0,0 @@ -package fr.ziedelth.controllers - -import fr.ziedelth.entities.Anime -import fr.ziedelth.utils.Database -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -object DiaryController : IController("/diary") { - fun Routing.getDiary() { - route(prefix) { - get("/country/{country}/day/{day}") { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val day = call.parameters["day"]?.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest) - println("GET $prefix/country/$country/day/$day") - val session = Database.getSession() - - try { - val query = session.createQuery( - "SELECT anime FROM Episode episode WHERE episode.anime.country.tag = :tag AND current_date - to_date(episode.releaseDate, 'YYYY-MM-DDTHH:MI:SS') <= 7 AND FUNCTION('date_part', 'dow', to_date(episode.releaseDate, 'YYYY-MM-DDTHH:MI:SS')) = :day ORDER BY episode.anime.name ASC", - entityClass - ) - query.setParameter("tag", country) - query.setParameter("day", day) - val list = query.list()?.distinctBy { it.uuid } - call.respond(list ?: HttpStatusCode.NotFound) - } catch (e: Exception) { - printError(call, e) - } finally { - session.close() - } - } - } - } -} diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index 45fb147..4ea0c94 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -1,7 +1,6 @@ package fr.ziedelth.plugins import fr.ziedelth.controllers.* -import fr.ziedelth.controllers.DiaryController.getDiary import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.controllers.LangTypeController.getLangTypes @@ -31,6 +30,5 @@ fun Application.configureRouting() { EpisodeController(animeRepository).getRoutes(this) NewsController(countryRepository).getRoutes(this) MangaController(animeRepository).getRoutes(this) - getDiary() } } diff --git a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt index db8f195..ec0173e 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt @@ -72,4 +72,17 @@ class AnimeRepository(session: () -> Session = { Database.getSession() }) : IRep session.close() return list } + + fun getDiary(tag: String, day: Int): List { + val session = getSession.invoke() + val query = session.createQuery( + "SELECT DISTINCT anime FROM Episode episode WHERE episode.anime.country.tag = :tag AND current_date - to_date(episode.releaseDate, 'YYYY-MM-DDTHH:MI:SS') <= 7 AND FUNCTION('date_part', 'dow', to_date(episode.releaseDate, 'YYYY-MM-DDTHH:MI:SS')) = :day ORDER BY episode.anime.name ASC", + Anime::class.java + ) + query.setParameter("tag", tag) + query.setParameter("day", day) + val list = query.list() + session.close() + return list ?: emptyList() + } } \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt index 15c0d41..b22d69d 100644 --- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -1,7 +1,6 @@ package fr.ziedelth.plugins import fr.ziedelth.controllers.* -import fr.ziedelth.controllers.DiaryController.getDiary import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.controllers.LangTypeController.getLangTypes @@ -33,6 +32,5 @@ fun Application.configureRoutingTest() { EpisodeController(animeRepository).getRoutes(this) NewsController(countryRepository).getRoutes(this) MangaController(animeRepository).getRoutes(this) - getDiary() } } \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt index 320e8f9..6236e28 100644 --- a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt +++ b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt @@ -161,4 +161,11 @@ internal class AnimeRepositoryTest : AbstractAPITest() { val page2 = animeRepository.findAllByPage(uuids, 2, 2) expect(1) { page2.size } } + +// @Test +// fun getDiary() { +// val country = countryRepository.getAll().first() +// val diary = animeRepository.getDiary(country.tag!!, Calendar.getInstance().get(Calendar.DAY_OF_WEEK)) +// expect(3) { diary.size } +// } } From d72aae2cbf013aa1616a17d69108971db3bb19fe Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 11:41:01 +0100 Subject: [PATCH 10/35] Add platform tests --- .../controllers/PlatformController.kt | 20 +++- .../kotlin/fr/ziedelth/plugins/Routing.kt | 8 +- .../controllers/CountryControllerTest.kt | 7 +- .../controllers/PlatformControllerTest.kt | 102 +++++++++++++++++ .../kotlin/fr/ziedelth/plugins/RoutingTest.kt | 3 +- .../repositories/PlatformRepositoryTest.kt | 108 ++++++++++++++++++ 6 files changed, 230 insertions(+), 18 deletions(-) create mode 100644 src/test/kotlin/fr/ziedelth/controllers/PlatformControllerTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/repositories/PlatformRepositoryTest.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt b/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt index dd1760b..2de832a 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt @@ -1,21 +1,29 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.Platform +import fr.ziedelth.repositories.PlatformRepository import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -object PlatformController : IController("/platforms") { - fun Routing.getPlatforms() { - route(prefix) { +class PlatformController(private val platformRepository: PlatformRepository) : IController("/platforms") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { getAll() getAttachment() create() } } + override fun Route.getAll() { + get { + println("GET $prefix") + call.respond(platformRepository.getAll()) + } + } + private fun Route.create() { post { println("POST $prefix") @@ -23,17 +31,17 @@ object PlatformController : IController("/platforms") { try { val platform = call.receive() - if (platform.name.isNullOrBlank() || platform.url.isNullOrBlank() || platform.image.isNullOrBlank()) { + if (platform.isNotValid()) { call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } - if (isExists("name", platform.name)) { + if (platformRepository.exists("name", platform.name)) { call.respond(HttpStatusCode.Conflict, "$entityName already exists") return@post } - call.respond(HttpStatusCode.Created, justSave(platform)) + call.respond(HttpStatusCode.Created, platformRepository.save(platform)) } catch (e: Exception) { printError(call, e) } diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index 4ea0c94..8cff736 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -4,12 +4,8 @@ import fr.ziedelth.controllers.* import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.controllers.LangTypeController.getLangTypes -import fr.ziedelth.controllers.PlatformController.getPlatforms import fr.ziedelth.controllers.SimulcastController.getSimulcasts -import fr.ziedelth.repositories.AnimeRepository -import fr.ziedelth.repositories.CountryRepository -import fr.ziedelth.repositories.EpisodeRepository -import fr.ziedelth.repositories.MangaRepository +import fr.ziedelth.repositories.* import io.ktor.server.application.* import io.ktor.server.routing.* @@ -21,7 +17,7 @@ fun Application.configureRouting() { val mangaRepository = MangaRepository() CountryController(countryRepository).getRoutes(this) - getPlatforms() + PlatformController(PlatformRepository()).getRoutes(this) getSimulcasts() getGenres() AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) diff --git a/src/test/kotlin/fr/ziedelth/controllers/CountryControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/CountryControllerTest.kt index 608846c..32b41a0 100644 --- a/src/test/kotlin/fr/ziedelth/controllers/CountryControllerTest.kt +++ b/src/test/kotlin/fr/ziedelth/controllers/CountryControllerTest.kt @@ -2,7 +2,6 @@ package fr.ziedelth.controllers import com.google.gson.Gson import fr.ziedelth.AbstractAPITest -import fr.ziedelth.entities.Anime import fr.ziedelth.entities.Country import fr.ziedelth.plugins.* import io.ktor.client.plugins.contentnegotiation.* @@ -27,8 +26,8 @@ internal class CountryControllerTest : AbstractAPITest() { val response = client.get("/countries") expect(HttpStatusCode.OK) { response.status } - val jsonNotCached = Gson().fromJson(response.bodyAsText(), Array::class.java) - expect(2) { jsonNotCached.size } + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(2) { json.size } } } @@ -52,7 +51,7 @@ internal class CountryControllerTest : AbstractAPITest() { } expect(HttpStatusCode.Created) { response.status } - val json = Gson().fromJson(response.bodyAsText(), Anime::class.java) + val json = Gson().fromJson(response.bodyAsText(), Country::class.java) checkNotNull(json.uuid) } } diff --git a/src/test/kotlin/fr/ziedelth/controllers/PlatformControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/PlatformControllerTest.kt new file mode 100644 index 0000000..d2c6975 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/PlatformControllerTest.kt @@ -0,0 +1,102 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.Platform +import fr.ziedelth.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class PlatformControllerTest : AbstractAPITest() { + @Test + fun getAll() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.get("/platforms") + expect(HttpStatusCode.OK) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(3) { json.size } + } + } + + @Test + fun create() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.post("/platforms") { + contentType(ContentType.Application.Json) + setBody(Platform(name = "MangaNews", url = "hello", image = "hello")) + } + + expect(HttpStatusCode.Created) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Platform::class.java) + checkNotNull(json.uuid) + } + } + + @Test + fun createError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + expect(HttpStatusCode.BadRequest) { + client.post("/platforms") { + contentType(ContentType.Application.Json) + setBody(Platform(name = "MangaNews")) + }.status + } + + expect(HttpStatusCode.BadRequest) { + client.post("/platforms") { + contentType(ContentType.Application.Json) + setBody(Platform(url = "hello")) + }.status + } + + expect(HttpStatusCode.BadRequest) { + client.post("/platforms") { + contentType(ContentType.Application.Json) + setBody(Platform(image = "hello")) + }.status + } + + expect(HttpStatusCode.Conflict) { + client.post("/platforms") { + contentType(ContentType.Application.Json) + setBody(Platform(name = "Netflix", url = "hello", image = "hello")) + }.status + } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt index b22d69d..1bfdc85 100644 --- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -4,7 +4,6 @@ import fr.ziedelth.controllers.* import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.controllers.LangTypeController.getLangTypes -import fr.ziedelth.controllers.PlatformController.getPlatforms import fr.ziedelth.controllers.SimulcastController.getSimulcasts import fr.ziedelth.repositories.* import fr.ziedelth.utils.DatabaseTest @@ -23,7 +22,7 @@ val mangaRepository = MangaRepository { DatabaseTest.getSession() } fun Application.configureRoutingTest() { routing { CountryController(countryRepository).getRoutes(this) - getPlatforms() + PlatformController(platformRepository).getRoutes(this) getSimulcasts() getGenres() AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) diff --git a/src/test/kotlin/fr/ziedelth/repositories/PlatformRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/PlatformRepositoryTest.kt new file mode 100644 index 0000000..b987714 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/PlatformRepositoryTest.kt @@ -0,0 +1,108 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.Platform +import fr.ziedelth.plugins.platformRepository +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.util.* +import kotlin.test.expect + +internal class PlatformRepositoryTest : AbstractAPITest() { + @Test + fun find() { + val platform = platformRepository.find(UUID.randomUUID()) + expect(null) { platform } + + val platforms = platformRepository.getAll() + expect(platforms.first().uuid) { platformRepository.find(platforms.first().uuid)?.uuid } + } + + @Test + fun exists() { + expect(true) { platformRepository.exists("name", "Netflix") } + expect(false) { platformRepository.exists("uuid", UUID.randomUUID()) } + } + + @Test + fun findAll() { + expect(emptyList()) { platformRepository.findAll(listOf(UUID.randomUUID())) } + + val platforms = platformRepository.getAll() + val list = platformRepository.findAll(listOf(platforms[0].uuid, platforms[1].uuid)) + + expect(true) { list.any { it.uuid == platforms.first().uuid } && list.any { it.uuid == platforms[1].uuid } } + } + + @Test + fun getAll() { + expect(3) { platformRepository.getAll().size } + } + + @Test + fun save() { + assertThrows { + platformRepository.save( + Platform( + name = "Netflix", + image = "hello", + url = "hello" + ) + ) + } + + val platform = Platform(name = "Animation Digital Network", image = "hello", url = "hello") + platformRepository.save(platform) + + expect(4) { platformRepository.getAll().size } + checkNotNull { platform.uuid } + expect("Animation Digital Network") { platform.name } + } + + @Test + fun saveAll() { + assertThrows { + platformRepository.saveAll( + listOf( + Platform( + name = "Netflix", + image = "hello", + url = "hello" + ), + Platform( + name = "Crunchyroll", + image = "hello", + url = "hello" + ) + ) + ) + } + + val platform1 = Platform(name = "Animation Digital Network", image = "hello", url = "hello") + val platform2 = Platform(name = "MangaNews", image = "hello", url = "hello") + platformRepository.saveAll(listOf(platform1, platform2)) + + expect(5) { platformRepository.getAll().size } + checkNotNull { platform1.uuid } + checkNotNull { platform2.uuid } + expect("Animation Digital Network") { platform1.name } + expect("MangaNews") { platform2.name } + } + + @Test + fun delete() { + assertThrows { + platformRepository.delete( + Platform( + name = "Netflix", + image = "hello", + url = "hello" + ) + ) + } + + val platforms = platformRepository.getAll() + platformRepository.delete(platforms.first()) + expect(2) { platforms.size - 1 } + } +} From c509a242b45f5c2b87f148e06b006e7fdac6b9f9 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 11:44:51 +0100 Subject: [PATCH 11/35] Fix errors --- .../kotlin/fr/ziedelth/controllers/EpisodeController.kt | 9 ++++++--- .../kotlin/fr/ziedelth/controllers/MangaController.kt | 8 ++++++-- .../kotlin/fr/ziedelth/controllers/NewsController.kt | 8 ++++++-- src/main/kotlin/fr/ziedelth/plugins/Routing.kt | 9 +++++---- src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt | 6 +++--- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt index 1fc7503..7445bae 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt @@ -6,6 +6,7 @@ import fr.ziedelth.entities.Simulcast import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.EpisodesReleaseEvent import fr.ziedelth.repositories.AnimeRepository +import fr.ziedelth.repositories.PlatformRepository import fr.ziedelth.utils.Database import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache @@ -18,7 +19,10 @@ import io.ktor.server.response.* import io.ktor.server.routing.* import java.util.* -class EpisodeController(private val animeRepository: AnimeRepository) : IController("/episodes") { +class EpisodeController( + private val platformRepository: PlatformRepository, + private val animeRepository: AnimeRepository +) : IController("/episodes") { fun getRoutes(routing: Routing) { routing.route(prefix) { getWithPage() @@ -126,8 +130,7 @@ class EpisodeController(private val animeRepository: AnimeRepository) : IControl } private fun merge(episode: Episode) { - episode.platform = - PlatformController.getBy("uuid", episode.platform!!.uuid) ?: throw Exception("Platform not found") + episode.platform = platformRepository.find(episode.platform!!.uuid) ?: throw Exception("Platform not found") episode.anime = animeRepository.find(episode.anime!!.uuid) ?: throw Exception("Anime not found") episode.episodeType = EpisodeTypeController.getBy("uuid", episode.episodeType!!.uuid) ?: throw Exception("EpisodeType not found") diff --git a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt index 789cbca..4ba9ddc 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt @@ -5,6 +5,7 @@ import fr.ziedelth.entities.Manga import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.MangasReleaseEvent import fr.ziedelth.repositories.AnimeRepository +import fr.ziedelth.repositories.PlatformRepository import fr.ziedelth.utils.Database import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache @@ -17,7 +18,10 @@ import io.ktor.server.response.* import io.ktor.server.routing.* import java.util.* -class MangaController(private val animeRepository: AnimeRepository) : IController("/mangas") { +class MangaController( + private val platformRepository: PlatformRepository, + private val animeRepository: AnimeRepository +) : IController("/mangas") { fun getRoutes(routing: Routing) { routing.route(prefix) { search() @@ -154,7 +158,7 @@ class MangaController(private val animeRepository: AnimeRepository) : IControlle private fun merge(manga: Manga) { manga.platform = - PlatformController.getBy("uuid", manga.platform!!.uuid) ?: throw Exception("Platform not found") + platformRepository.find(manga.platform!!.uuid) ?: throw Exception("Platform not found") manga.anime = animeRepository.find(manga.anime!!.uuid) ?: throw Exception("Anime not found") if (manga.isNullOrNotValid()) { diff --git a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt index f69d877..11d9711 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt @@ -4,6 +4,7 @@ import fr.ziedelth.entities.News import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.NewsReleaseEvent import fr.ziedelth.repositories.CountryRepository +import fr.ziedelth.repositories.PlatformRepository import fr.ziedelth.utils.Database import fr.ziedelth.utils.RequestCache import fr.ziedelth.utils.plugins.PluginManager @@ -13,7 +14,10 @@ import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -class NewsController(private val countryRepository: CountryRepository) : IController("/news") { +class NewsController( + private val countryRepository: CountryRepository, + private val platformRepository: PlatformRepository +) : IController("/news") { fun getRoutes(routing: Routing) { routing.route(prefix) { getWithPage() @@ -61,7 +65,7 @@ class NewsController(private val countryRepository: CountryRepository) : IContro } private fun merge(news: News) { - news.platform = PlatformController.getBy("uuid", news.platform!!.uuid) ?: throw Exception("Platform not found") + news.platform = platformRepository.find(news.platform!!.uuid) ?: throw Exception("Platform not found") news.country = countryRepository.find(news.country!!.uuid) ?: throw Exception("Country not found") if (news.isNullOrNotValid()) { diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index 8cff736..f663bd7 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -12,19 +12,20 @@ import io.ktor.server.routing.* fun Application.configureRouting() { routing { val countryRepository = CountryRepository() + val platformRepository = PlatformRepository() val animeRepository = AnimeRepository() val episodeRepository = EpisodeRepository() val mangaRepository = MangaRepository() CountryController(countryRepository).getRoutes(this) - PlatformController(PlatformRepository()).getRoutes(this) + PlatformController(platformRepository).getRoutes(this) getSimulcasts() getGenres() AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) getEpisodeTypes() getLangTypes() - EpisodeController(animeRepository).getRoutes(this) - NewsController(countryRepository).getRoutes(this) - MangaController(animeRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository).getRoutes(this) + NewsController(countryRepository, platformRepository).getRoutes(this) + MangaController(platformRepository, animeRepository).getRoutes(this) } } diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt index 1bfdc85..a170c96 100644 --- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -28,8 +28,8 @@ fun Application.configureRoutingTest() { AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) getEpisodeTypes() getLangTypes() - EpisodeController(animeRepository).getRoutes(this) - NewsController(countryRepository).getRoutes(this) - MangaController(animeRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository).getRoutes(this) + NewsController(countryRepository, platformRepository).getRoutes(this) + MangaController(platformRepository, animeRepository).getRoutes(this) } } \ No newline at end of file From 2be26ba6ef17def978e5047d6a3f6729b60d8af8 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 11:56:06 +0100 Subject: [PATCH 12/35] Add more tests --- .../kotlin/fr/ziedelth/entities/AnimeTest.kt | 17 +++++++++++++++++ .../fr/ziedelth/entities/SimulcastTest.kt | 13 +++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/test/kotlin/fr/ziedelth/entities/AnimeTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/entities/SimulcastTest.kt diff --git a/src/test/kotlin/fr/ziedelth/entities/AnimeTest.kt b/src/test/kotlin/fr/ziedelth/entities/AnimeTest.kt new file mode 100644 index 0000000..36a93fe --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/entities/AnimeTest.kt @@ -0,0 +1,17 @@ +package fr.ziedelth.entities + +import org.junit.jupiter.api.Test +import kotlin.test.expect + +class AnimeTest { + @Test + fun hash() { + val anime = Anime( + name = "Do It Yourself!!", + image = "hello", + country = Country(tag = "fr", name = "France") + ) + + expect("do-it-yourself") { anime.hash() } + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/entities/SimulcastTest.kt b/src/test/kotlin/fr/ziedelth/entities/SimulcastTest.kt new file mode 100644 index 0000000..beb9f1c --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/entities/SimulcastTest.kt @@ -0,0 +1,13 @@ +package fr.ziedelth.entities + +import org.junit.jupiter.api.Test +import kotlin.test.expect + +class SimulcastTest { + @Test + fun hash() { + val simulcast = Simulcast.getSimulcast(2022, 11) + expect(2022) { simulcast.year } + expect("AUTUMN") { simulcast.season } + } +} \ No newline at end of file From bdbacfa9587bbc7d1e661dc483a16e9d0cd3972a Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 12:30:10 +0100 Subject: [PATCH 13/35] Add simulcast tests --- .../controllers/EpisodeTypeController.kt | 3 +- .../controllers/PlatformController.kt | 3 +- .../repositories/SimulcastRepository.kt | 12 ++- .../kotlin/fr/ziedelth/AbstractAPITest.kt | 11 ++- .../repositories/SimulcastRepositoryTest.kt | 94 +++++++++++++++++++ 5 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt index 25c98a7..81c0928 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt @@ -1,6 +1,7 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.EpisodeType +import fr.ziedelth.entities.isNullOrNotValid import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* @@ -22,7 +23,7 @@ object EpisodeTypeController : IController("/episodetypes") { try { val episodeType = call.receive() - if (episodeType.name.isNullOrBlank()) { + if (episodeType.isNullOrNotValid()) { call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } diff --git a/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt b/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt index 2de832a..dd57ba1 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt @@ -1,6 +1,7 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.Platform +import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.repositories.PlatformRepository import io.ktor.http.* import io.ktor.server.application.* @@ -31,7 +32,7 @@ class PlatformController(private val platformRepository: PlatformRepository) : I try { val platform = call.receive() - if (platform.isNotValid()) { + if (platform.isNullOrNotValid()) { call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } diff --git a/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt index cce1c24..e952366 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt @@ -4,4 +4,14 @@ import fr.ziedelth.entities.Simulcast import fr.ziedelth.utils.Database import org.hibernate.Session -class SimulcastRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file +class SimulcastRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) { + fun findBySeasonAndYear(season: String, year: Int): Simulcast? { + val session = getSession.invoke() + val query = session.createQuery("FROM Simulcast WHERE season = :season AND year = :year", Simulcast::class.java) + query.setParameter("season", season) + query.setParameter("year", year) + val simulcast = query.uniqueResult() + session.close() + return simulcast + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt b/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt index 3a5856a..3c4573a 100644 --- a/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt +++ b/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt @@ -23,8 +23,9 @@ internal abstract class AbstractAPITest { platformRepository.saveAll(listOf(platform1, platform2, platform3)) val platforms = platformRepository.getAll() - val simulcast = Simulcast(season = "Winter", year = 2020) - simulcastRepository.save(simulcast) + val simulcast1 = Simulcast(season = "WINTER", year = 2020) + val simulcast2 = Simulcast(season = "SPRING", year = 2020) + simulcastRepository.saveAll(listOf(simulcast1, simulcast2)) val simulcasts = simulcastRepository.getAll() val anime1 = Anime( @@ -32,21 +33,21 @@ internal abstract class AbstractAPITest { name = "One Piece", image = "hello", hashes = mutableSetOf("hello"), - simulcasts = mutableSetOf(simulcasts.random()) + simulcasts = mutableSetOf(simulcasts.first()) ) val anime2 = Anime( country = countries.first(), name = "Naruto", image = "hello", hashes = mutableSetOf("hello2"), - simulcasts = mutableSetOf(simulcasts.random()) + simulcasts = mutableSetOf(simulcasts.first()) ) val anime3 = Anime( country = countries.first(), name = "Bleach", image = "hello", hashes = mutableSetOf("hello3"), - simulcasts = mutableSetOf(simulcasts.random()) + simulcasts = mutableSetOf(simulcasts.first()) ) animeRepository.saveAll(listOf(anime1, anime2, anime3)) val animes = animeRepository.getAll() diff --git a/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt new file mode 100644 index 0000000..6d23925 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt @@ -0,0 +1,94 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.Simulcast +import fr.ziedelth.plugins.simulcastRepository +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.util.* +import kotlin.test.expect + +internal class SimulcastRepositoryTest : AbstractAPITest() { + @Test + fun find() { + val simulcast = simulcastRepository.find(UUID.randomUUID()) + expect(null) { simulcast } + + val simulcasts = simulcastRepository.getAll() + expect(simulcasts.first().uuid) { simulcastRepository.find(simulcasts.first().uuid)?.uuid } + } + + @Test + fun exists() { + expect(true) { simulcastRepository.exists("year", 2020) } + expect(false) { simulcastRepository.exists("uuid", UUID.randomUUID()) } + } + + @Test + fun findAll() { + expect(emptyList()) { simulcastRepository.findAll(listOf(UUID.randomUUID())) } + + val simulcasts = simulcastRepository.getAll() + val list = simulcastRepository.findAll(listOf(simulcasts[0].uuid, simulcasts[1].uuid)) + + expect(true) { list.any { it.uuid == simulcasts.first().uuid } && list.any { it.uuid == simulcasts[1].uuid } } + } + + @Test + fun getAll() { + expect(2) { simulcastRepository.getAll().size } + } + + @Test + fun save() { + assertThrows { + simulcastRepository.save(Simulcast(year = 2020, season = "WINTER")) + } + + val simulcast = Simulcast.getSimulcast(2021, 1) + simulcastRepository.save(simulcast) + + expect(3) { simulcastRepository.getAll().size } + checkNotNull { simulcast.uuid } + expect("WINTER") { simulcast.season } + } + + @Test + fun saveAll() { + assertThrows { + simulcastRepository.saveAll( + listOf( + Simulcast(year = 2020, season = "WINTER"), + Simulcast(year = 2020, season = "SPRING") + ) + ) + } + + val simulcast1 = Simulcast.getSimulcast(2019, 1) + val simulcast2 = Simulcast.getSimulcast(2019, 11) + simulcastRepository.saveAll(listOf(simulcast1, simulcast2)) + + expect(4) { simulcastRepository.getAll().size } + checkNotNull { simulcast1.uuid } + checkNotNull { simulcast2.uuid } + expect("WINTER") { simulcast1.season } + expect("AUTUMN") { simulcast2.season } + } + + @Test + fun delete() { + assertThrows { + simulcastRepository.delete( + Simulcast( + UUID.randomUUID(), + season = "WINTER", + year = 2020 + ) + ) + } + + val simulcasts = simulcastRepository.getAll() + simulcastRepository.delete(simulcasts.first()) + expect(1) { simulcasts.size - 1 } + } +} From 4eff800b986e5bbdccca9b96c9acd4dd7272b597 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 12:31:21 +0100 Subject: [PATCH 14/35] Add simulcast tests --- .../fr/ziedelth/repositories/SimulcastRepositoryTest.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt index 6d23925..d9f4af2 100644 --- a/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt +++ b/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt @@ -91,4 +91,10 @@ internal class SimulcastRepositoryTest : AbstractAPITest() { simulcastRepository.delete(simulcasts.first()) expect(1) { simulcasts.size - 1 } } + + @Test + fun findBySeasonAndYear() { + val simulcast = simulcastRepository.findBySeasonAndYear("WINTER", 2020) + checkNotNull(simulcast?.uuid) + } } From 0d5eb799c33b5565bc016d35727eb1bc117b68fc Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 13:38:43 +0100 Subject: [PATCH 15/35] Update tests --- .../ziedelth/controllers/EpisodeController.kt | 7 +++- .../controllers/SimulcastController.kt | 42 +++---------------- .../kotlin/fr/ziedelth/plugins/Routing.kt | 6 +-- .../repositories/SimulcastRepository.kt | 12 ++++++ .../controllers/AnimeControllerTest.kt | 11 +++-- .../controllers/SimulcastControllerTest.kt | 35 ++++++++++++++++ .../kotlin/fr/ziedelth/plugins/RoutingTest.kt | 7 ++-- .../repositories/AnimeRepositoryTest.kt | 4 +- .../repositories/SimulcastRepositoryTest.kt | 9 ++++ 9 files changed, 84 insertions(+), 49 deletions(-) create mode 100644 src/test/kotlin/fr/ziedelth/controllers/SimulcastControllerTest.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt index 7445bae..102b04c 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt @@ -7,6 +7,7 @@ import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.EpisodesReleaseEvent import fr.ziedelth.repositories.AnimeRepository import fr.ziedelth.repositories.PlatformRepository +import fr.ziedelth.repositories.SimulcastRepository import fr.ziedelth.utils.Database import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache @@ -21,7 +22,8 @@ import java.util.* class EpisodeController( private val platformRepository: PlatformRepository, - private val animeRepository: AnimeRepository + private val animeRepository: AnimeRepository, + private val simulcastRepository: SimulcastRepository, ) : IController("/episodes") { fun getRoutes(routing: Routing) { routing.route(prefix) { @@ -143,7 +145,8 @@ class EpisodeController( val tmpSimulcast = Simulcast.getSimulcast(episode.releaseDate.split("-")[0].toInt(), episode.releaseDate.split("-")[1].toInt()) - val simulcast = SimulcastController.getBy(tmpSimulcast) + val simulcast = + simulcastRepository.findBySeasonAndYear(tmpSimulcast.season!!, tmpSimulcast.year!!) ?: tmpSimulcast if (episode.anime!!.simulcasts.isEmpty() || episode.anime!!.simulcasts.none { it.uuid == simulcast.uuid }) { episode.anime!!.simulcasts.add(simulcast) diff --git a/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt b/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt index 06ad4d6..7fae634 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt @@ -1,51 +1,21 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.Simulcast -import fr.ziedelth.utils.Database +import fr.ziedelth.repositories.SimulcastRepository import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* -object SimulcastController : IController("/simulcasts") { - fun Routing.getSimulcasts() { - route(prefix) { +class SimulcastController(private val simulcastRepository: SimulcastRepository) : + IController("/simulcasts") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { get("/country/{country}") { val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) println("GET $prefix/country/$country") - val session = Database.getSession() - - try { - val query = session.createQuery( - "SELECT DISTINCT simulcasts FROM Anime WHERE country.tag = :tag", - Simulcast::class.java - ) - query.setParameter("tag", country) - call.respond(query.list()) - } catch (e: Exception) { - printError(call, e) - } finally { - session.close() - } + call.respond(simulcastRepository.getAll(country)) } } } - - fun getBy(simulcast: Simulcast): Simulcast { - val session = Database.getSession() - - try { - val query = - session.createQuery("FROM Simulcast WHERE season = :season AND year = :year", Simulcast::class.java) - query.setParameter("season", simulcast.season) - query.setParameter("year", simulcast.year) - return query.list().firstOrNull() ?: simulcast - } catch (e: Exception) { - e.printStackTrace() - println("Error while getting $prefix : ${e.message}") - throw e - } finally { - session.close() - } - } } diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index f663bd7..e924336 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -4,7 +4,6 @@ import fr.ziedelth.controllers.* import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.controllers.LangTypeController.getLangTypes -import fr.ziedelth.controllers.SimulcastController.getSimulcasts import fr.ziedelth.repositories.* import io.ktor.server.application.* import io.ktor.server.routing.* @@ -14,17 +13,18 @@ fun Application.configureRouting() { val countryRepository = CountryRepository() val platformRepository = PlatformRepository() val animeRepository = AnimeRepository() + val simulcastRepository = SimulcastRepository() val episodeRepository = EpisodeRepository() val mangaRepository = MangaRepository() CountryController(countryRepository).getRoutes(this) PlatformController(platformRepository).getRoutes(this) - getSimulcasts() + SimulcastController(simulcastRepository).getRoutes(this) getGenres() AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) getEpisodeTypes() getLangTypes() - EpisodeController(platformRepository, animeRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository, simulcastRepository).getRoutes(this) NewsController(countryRepository, platformRepository).getRoutes(this) MangaController(platformRepository, animeRepository).getRoutes(this) } diff --git a/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt index e952366..c0ab941 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt @@ -5,6 +5,18 @@ import fr.ziedelth.utils.Database import org.hibernate.Session class SimulcastRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) { + fun getAll(tag: String?): List { + val session = getSession.invoke() + val query = session.createQuery( + "SELECT DISTINCT simulcasts FROM Anime WHERE country.tag = :tag", + Simulcast::class.java + ) + query.setParameter("tag", tag) + val list = query.list() + session.close() + return list + } + fun findBySeasonAndYear(season: String, year: Int): Simulcast? { val session = getSession.invoke() val query = session.createQuery("FROM Simulcast WHERE season = :season AND year = :year", Simulcast::class.java) diff --git a/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt index 9638526..c3691be 100644 --- a/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt +++ b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt @@ -60,11 +60,13 @@ internal class AnimeControllerTest : AbstractAPITest() { configureRoutingTest() } + val country = countryRepository.getAll().first() val simulcast = simulcastRepository.getAll().first() // NOT CACHED - val responseNotCached = client.get("/animes/country/fr/simulcast/${simulcast.uuid}/page/1/limit/12") + val responseNotCached = + client.get("/animes/country/${country.tag}/simulcast/${simulcast.uuid}/page/1/limit/12") val jsonNotCached = Gson().fromJson(responseNotCached.bodyAsText(), Array::class.java) expect(HttpStatusCode.OK) { responseNotCached.status } @@ -72,7 +74,8 @@ internal class AnimeControllerTest : AbstractAPITest() { // CACHED - val responseCached = client.get("/animes/country/fr/simulcast/${simulcast.uuid}/page/1/limit/12") + val responseCached = + client.get("/animes/country/${country.tag}/simulcast/${simulcast.uuid}/page/1/limit/12") val jsonCached = Gson().fromJson(responseCached.bodyAsText(), Array::class.java) expect(HttpStatusCode.OK) { responseCached.status } @@ -88,11 +91,13 @@ internal class AnimeControllerTest : AbstractAPITest() { configureRoutingTest() } + val country = countryRepository.getAll().first() val simulcast = simulcastRepository.getAll().first() // ERROR - val responseError = client.get("/animes/country/fr/simulcast/${simulcast.uuid}/page/ae/limit/12") + val responseError = + client.get("/animes/country/${country.tag}/simulcast/${simulcast.uuid}/page/ae/limit/12") expect(HttpStatusCode.InternalServerError) { responseError.status } } diff --git a/src/test/kotlin/fr/ziedelth/controllers/SimulcastControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/SimulcastControllerTest.kt new file mode 100644 index 0000000..96e27bd --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/SimulcastControllerTest.kt @@ -0,0 +1,35 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.Simulcast +import fr.ziedelth.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class SimulcastControllerTest : AbstractAPITest() { + @Test + fun getAll() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + + val response = client.get("/simulcasts/country/${country.tag}") + expect(HttpStatusCode.OK) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(1) { json.size } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt index a170c96..12b0908 100644 --- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -4,7 +4,6 @@ import fr.ziedelth.controllers.* import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.controllers.LangTypeController.getLangTypes -import fr.ziedelth.controllers.SimulcastController.getSimulcasts import fr.ziedelth.repositories.* import fr.ziedelth.utils.DatabaseTest import io.ktor.server.application.* @@ -12,8 +11,8 @@ import io.ktor.server.routing.* val countryRepository = CountryRepository { DatabaseTest.getSession() } val platformRepository = PlatformRepository { DatabaseTest.getSession() } -val simulcastRepository = SimulcastRepository { DatabaseTest.getSession() } val animeRepository = AnimeRepository { DatabaseTest.getSession() } +val simulcastRepository = SimulcastRepository { DatabaseTest.getSession() } val episodeTypeRepository = EpisodeTypeRepository { DatabaseTest.getSession() } val langTypeRepository = LangTypeRepository { DatabaseTest.getSession() } val episodeRepository = EpisodeRepository { DatabaseTest.getSession() } @@ -23,12 +22,12 @@ fun Application.configureRoutingTest() { routing { CountryController(countryRepository).getRoutes(this) PlatformController(platformRepository).getRoutes(this) - getSimulcasts() + SimulcastController(simulcastRepository).getRoutes(this) getGenres() AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) getEpisodeTypes() getLangTypes() - EpisodeController(platformRepository, animeRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository, simulcastRepository).getRoutes(this) NewsController(countryRepository, platformRepository).getRoutes(this) MangaController(platformRepository, animeRepository).getRoutes(this) } diff --git a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt index 6236e28..5239f81 100644 --- a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt +++ b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt @@ -4,6 +4,7 @@ import fr.ziedelth.AbstractAPITest import fr.ziedelth.entities.Anime import fr.ziedelth.entities.Country import fr.ziedelth.plugins.animeRepository +import fr.ziedelth.plugins.countryRepository import fr.ziedelth.plugins.simulcastRepository import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows @@ -44,7 +45,8 @@ internal class AnimeRepositoryTest : AbstractAPITest() { @Test fun getAllByCountry() { - expect(3) { animeRepository.getAllBy("country.tag", "fr").size } + val country = countryRepository.getAll().first() + expect(3) { animeRepository.getAllBy("country.tag", country.tag).size } expect(0) { animeRepository.getAllBy("country.tag", "us").size } } diff --git a/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt index d9f4af2..8d6d7f0 100644 --- a/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt +++ b/src/test/kotlin/fr/ziedelth/repositories/SimulcastRepositoryTest.kt @@ -2,6 +2,7 @@ package fr.ziedelth.repositories import fr.ziedelth.AbstractAPITest import fr.ziedelth.entities.Simulcast +import fr.ziedelth.plugins.countryRepository import fr.ziedelth.plugins.simulcastRepository import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows @@ -92,6 +93,14 @@ internal class SimulcastRepositoryTest : AbstractAPITest() { expect(1) { simulcasts.size - 1 } } + @Test + fun getAllByTag() { + val country = countryRepository.getAll().first() + val simulcasts = simulcastRepository.getAll(country.tag) + expect(1) { simulcasts.size } + expect("WINTER") { simulcasts.first().season } + } + @Test fun findBySeasonAndYear() { val simulcast = simulcastRepository.findBySeasonAndYear("WINTER", 2020) From 5a8f159378e621042f2f534997673f3440e8692a Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 13:58:46 +0100 Subject: [PATCH 16/35] Add episode type tests --- .../ziedelth/controllers/EpisodeController.kt | 5 +- .../controllers/EpisodeTypeController.kt | 18 +++- .../controllers/SimulcastController.kt | 3 +- .../kotlin/fr/ziedelth/plugins/Routing.kt | 6 +- .../controllers/EpisodeTypeControllerTest.kt | 88 ++++++++++++++++++ .../kotlin/fr/ziedelth/plugins/RoutingTest.kt | 5 +- .../repositories/EpisodeTypeRepositoryTest.kt | 92 +++++++++++++++++++ 7 files changed, 202 insertions(+), 15 deletions(-) create mode 100644 src/test/kotlin/fr/ziedelth/controllers/EpisodeTypeControllerTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/repositories/EpisodeTypeRepositoryTest.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt index 102b04c..bf6d60b 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt @@ -6,6 +6,7 @@ import fr.ziedelth.entities.Simulcast import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.EpisodesReleaseEvent import fr.ziedelth.repositories.AnimeRepository +import fr.ziedelth.repositories.EpisodeTypeRepository import fr.ziedelth.repositories.PlatformRepository import fr.ziedelth.repositories.SimulcastRepository import fr.ziedelth.utils.Database @@ -24,6 +25,7 @@ class EpisodeController( private val platformRepository: PlatformRepository, private val animeRepository: AnimeRepository, private val simulcastRepository: SimulcastRepository, + private val episodeTypeRepository: EpisodeTypeRepository ) : IController("/episodes") { fun getRoutes(routing: Routing) { routing.route(prefix) { @@ -134,8 +136,7 @@ class EpisodeController( private fun merge(episode: Episode) { episode.platform = platformRepository.find(episode.platform!!.uuid) ?: throw Exception("Platform not found") episode.anime = animeRepository.find(episode.anime!!.uuid) ?: throw Exception("Anime not found") - episode.episodeType = - EpisodeTypeController.getBy("uuid", episode.episodeType!!.uuid) ?: throw Exception("EpisodeType not found") + episode.episodeType = episodeTypeRepository.find(episode.episodeType!!.uuid) ?: throw Exception("EpisodeType not found") episode.langType = LangTypeController.getBy("uuid", episode.langType!!.uuid) ?: throw Exception("LangType not found") diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt index 81c0928..ed05c24 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt @@ -2,20 +2,28 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.EpisodeType import fr.ziedelth.entities.isNullOrNotValid +import fr.ziedelth.repositories.EpisodeTypeRepository import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -object EpisodeTypeController : IController("/episodetypes") { - fun Routing.getEpisodeTypes() { - route(prefix) { +class EpisodeTypeController(private val episodeTypeRepository: EpisodeTypeRepository) : IController("/episodetypes") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { getAll() create() } } + override fun Route.getAll() { + get { + println("GET $prefix") + call.respond(episodeTypeRepository.getAll()) + } + } + private fun Route.create() { post { println("POST $prefix") @@ -28,12 +36,12 @@ object EpisodeTypeController : IController("/episodetypes") { return@post } - if (isExists("name", episodeType.name)) { + if (episodeTypeRepository.exists("name", episodeType.name)) { call.respond(HttpStatusCode.Conflict, "$entityName already exists") return@post } - call.respond(HttpStatusCode.Created, justSave(episodeType)) + call.respond(HttpStatusCode.Created, episodeTypeRepository.save(episodeType)) } catch (e: Exception) { printError(call, e) } diff --git a/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt b/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt index 7fae634..3a71116 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/SimulcastController.kt @@ -2,7 +2,6 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.Simulcast import fr.ziedelth.repositories.SimulcastRepository -import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* @@ -12,7 +11,7 @@ class SimulcastController(private val simulcastRepository: SimulcastRepository) fun getRoutes(routing: Routing) { routing.route(prefix) { get("/country/{country}") { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val country = call.parameters["country"]!! println("GET $prefix/country/$country") call.respond(simulcastRepository.getAll(country)) } diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index e924336..ed4a046 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -1,7 +1,6 @@ package fr.ziedelth.plugins import fr.ziedelth.controllers.* -import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.controllers.LangTypeController.getLangTypes import fr.ziedelth.repositories.* @@ -14,6 +13,7 @@ fun Application.configureRouting() { val platformRepository = PlatformRepository() val animeRepository = AnimeRepository() val simulcastRepository = SimulcastRepository() + val episodeTypeRepository = EpisodeTypeRepository() val episodeRepository = EpisodeRepository() val mangaRepository = MangaRepository() @@ -22,9 +22,9 @@ fun Application.configureRouting() { SimulcastController(simulcastRepository).getRoutes(this) getGenres() AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) - getEpisodeTypes() + EpisodeTypeController(episodeTypeRepository).getRoutes(this) getLangTypes() - EpisodeController(platformRepository, animeRepository, simulcastRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository).getRoutes(this) NewsController(countryRepository, platformRepository).getRoutes(this) MangaController(platformRepository, animeRepository).getRoutes(this) } diff --git a/src/test/kotlin/fr/ziedelth/controllers/EpisodeTypeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/EpisodeTypeControllerTest.kt new file mode 100644 index 0000000..3c112d9 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/EpisodeTypeControllerTest.kt @@ -0,0 +1,88 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.EpisodeType +import fr.ziedelth.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class EpisodeTypeControllerTest : AbstractAPITest() { + @Test + fun getAll() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.get("/episodetypes") + expect(HttpStatusCode.OK) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(3) { json.size } + } + } + + @Test + fun create() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.post("/episodetypes") { + contentType(ContentType.Application.Json) + setBody(EpisodeType(name = "test")) + } + + expect(HttpStatusCode.Created) { response.status } + val json = Gson().fromJson(response.bodyAsText(), EpisodeType::class.java) + checkNotNull(json.uuid) + } + } + + @Test + fun createError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + expect(HttpStatusCode.BadRequest) { + client.post("/episodetypes") { + contentType(ContentType.Application.Json) + setBody(EpisodeType()) + }.status + } + + expect(HttpStatusCode.Conflict) { + client.post("/episodetypes") { + contentType(ContentType.Application.Json) + setBody(EpisodeType(name = "Episode")) + }.status + } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt index 12b0908..e0c9ce6 100644 --- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -1,7 +1,6 @@ package fr.ziedelth.plugins import fr.ziedelth.controllers.* -import fr.ziedelth.controllers.EpisodeTypeController.getEpisodeTypes import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.controllers.LangTypeController.getLangTypes import fr.ziedelth.repositories.* @@ -25,9 +24,9 @@ fun Application.configureRoutingTest() { SimulcastController(simulcastRepository).getRoutes(this) getGenres() AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) - getEpisodeTypes() + EpisodeTypeController(episodeTypeRepository).getRoutes(this) getLangTypes() - EpisodeController(platformRepository, animeRepository, simulcastRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository).getRoutes(this) NewsController(countryRepository, platformRepository).getRoutes(this) MangaController(platformRepository, animeRepository).getRoutes(this) } diff --git a/src/test/kotlin/fr/ziedelth/repositories/EpisodeTypeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/EpisodeTypeRepositoryTest.kt new file mode 100644 index 0000000..2239926 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/EpisodeTypeRepositoryTest.kt @@ -0,0 +1,92 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.EpisodeType +import fr.ziedelth.plugins.episodeTypeRepository +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.util.* +import kotlin.test.expect + +internal class EpisodeTypeRepositoryTest : AbstractAPITest() { + @Test + fun find() { + val episodeType = episodeTypeRepository.find(UUID.randomUUID()) + expect(null) { episodeType } + + val episodeTypes = episodeTypeRepository.getAll() + expect(episodeTypes.first().uuid) { episodeTypeRepository.find(episodeTypes.first().uuid)?.uuid } + } + + @Test + fun exists() { + expect(true) { episodeTypeRepository.exists("name", "Episode") } + expect(false) { episodeTypeRepository.exists("uuid", UUID.randomUUID()) } + } + + @Test + fun findAll() { + expect(emptyList()) { episodeTypeRepository.findAll(listOf(UUID.randomUUID())) } + + val episodeTypes = episodeTypeRepository.getAll() + val list = episodeTypeRepository.findAll(listOf(episodeTypes[0].uuid, episodeTypes[1].uuid)) + + expect(true) { list.any { it.uuid == episodeTypes.first().uuid } && list.any { it.uuid == episodeTypes[1].uuid } } + } + + @Test + fun getAll() { + expect(3) { episodeTypeRepository.getAll().size } + } + + @Test + fun save() { + assertThrows { + episodeTypeRepository.save(EpisodeType(name = "Episode")) + } + + val episodeType = EpisodeType(name = "Special") + episodeTypeRepository.save(episodeType) + + expect(4) { episodeTypeRepository.getAll().size } + checkNotNull { episodeType.uuid } + expect("Special") { episodeType.name } + } + + @Test + fun saveAll() { + assertThrows { + episodeTypeRepository.saveAll( + listOf( + EpisodeType(name = "Episode"), + EpisodeType(name = "OAV") + ) + ) + } + + val episodeType1 = EpisodeType(name = "Special") + val episodeType2 = EpisodeType(name = "Special 2") + episodeTypeRepository.saveAll(listOf(episodeType1, episodeType2)) + + expect(5) { episodeTypeRepository.getAll().size } + checkNotNull { episodeType1.uuid } + checkNotNull { episodeType2.uuid } + expect("Special") { episodeType1.name } + expect("Special 2") { episodeType2.name } + } + + @Test + fun delete() { + assertThrows { + episodeTypeRepository.delete( + EpisodeType( + name = "Episode" + ) + ) + } + + val episodeTypes = episodeTypeRepository.getAll() + episodeTypeRepository.delete(episodeTypes.first()) + expect(2) { episodeTypes.size - 1 } + } +} From 05b7edd73ffdae9a2b5777f13355b040ca716802 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 14:19:18 +0100 Subject: [PATCH 17/35] Add lang type tests --- .../ziedelth/controllers/EpisodeController.kt | 11 +-- .../controllers/LangTypeController.kt | 21 +++-- .../kotlin/fr/ziedelth/plugins/Routing.kt | 6 +- .../ziedelth/repositories/GenreRepository.kt | 7 ++ .../controllers/LangTypeControllerTest.kt | 88 ++++++++++++++++++ .../kotlin/fr/ziedelth/plugins/RoutingTest.kt | 5 +- .../repositories/LangTypeRepositoryTest.kt | 92 +++++++++++++++++++ 7 files changed, 211 insertions(+), 19 deletions(-) create mode 100644 src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt create mode 100644 src/test/kotlin/fr/ziedelth/controllers/LangTypeControllerTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/repositories/LangTypeRepositoryTest.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt index bf6d60b..8315a0e 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt @@ -5,10 +5,7 @@ import fr.ziedelth.entities.Episode import fr.ziedelth.entities.Simulcast import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.EpisodesReleaseEvent -import fr.ziedelth.repositories.AnimeRepository -import fr.ziedelth.repositories.EpisodeTypeRepository -import fr.ziedelth.repositories.PlatformRepository -import fr.ziedelth.repositories.SimulcastRepository +import fr.ziedelth.repositories.* import fr.ziedelth.utils.Database import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache @@ -25,7 +22,8 @@ class EpisodeController( private val platformRepository: PlatformRepository, private val animeRepository: AnimeRepository, private val simulcastRepository: SimulcastRepository, - private val episodeTypeRepository: EpisodeTypeRepository + private val episodeTypeRepository: EpisodeTypeRepository, + private val langTypeRepository: LangTypeRepository, ) : IController("/episodes") { fun getRoutes(routing: Routing) { routing.route(prefix) { @@ -137,8 +135,7 @@ class EpisodeController( episode.platform = platformRepository.find(episode.platform!!.uuid) ?: throw Exception("Platform not found") episode.anime = animeRepository.find(episode.anime!!.uuid) ?: throw Exception("Anime not found") episode.episodeType = episodeTypeRepository.find(episode.episodeType!!.uuid) ?: throw Exception("EpisodeType not found") - episode.langType = - LangTypeController.getBy("uuid", episode.langType!!.uuid) ?: throw Exception("LangType not found") + episode.langType = langTypeRepository.find(episode.langType!!.uuid) ?: throw Exception("LangType not found") if (episode.isNullOrNotValid()) { throw Exception("Episode is not valid") diff --git a/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt b/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt index 141f6ce..0170bb1 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt @@ -1,20 +1,29 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.LangType +import fr.ziedelth.entities.isNullOrNotValid +import fr.ziedelth.repositories.LangTypeRepository import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -object LangTypeController : IController("/langtypes") { - fun Routing.getLangTypes() { - route(prefix) { +class LangTypeController(private val langTypeRepository: LangTypeRepository) : IController("/langtypes") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { getAll() create() } } + override fun Route.getAll() { + get { + println("GET $prefix") + call.respond(langTypeRepository.getAll()) + } + } + private fun Route.create() { post { println("POST $prefix") @@ -22,17 +31,17 @@ object LangTypeController : IController("/langtypes") { try { val langType = call.receive() - if (langType.name.isNullOrBlank()) { + if (langType.isNullOrNotValid()) { call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } - if (isExists("name", langType.name)) { + if (langTypeRepository.exists("name", langType.name)) { call.respond(HttpStatusCode.Conflict, "$entityName already exists") return@post } - call.respond(HttpStatusCode.Created, justSave(langType)) + call.respond(HttpStatusCode.Created, langTypeRepository.save(langType)) } catch (e: Exception) { printError(call, e) } diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index ed4a046..942dd66 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -2,7 +2,6 @@ package fr.ziedelth.plugins import fr.ziedelth.controllers.* import fr.ziedelth.controllers.GenreController.getGenres -import fr.ziedelth.controllers.LangTypeController.getLangTypes import fr.ziedelth.repositories.* import io.ktor.server.application.* import io.ktor.server.routing.* @@ -14,6 +13,7 @@ fun Application.configureRouting() { val animeRepository = AnimeRepository() val simulcastRepository = SimulcastRepository() val episodeTypeRepository = EpisodeTypeRepository() + val langTypeRepository = LangTypeRepository() val episodeRepository = EpisodeRepository() val mangaRepository = MangaRepository() @@ -23,8 +23,8 @@ fun Application.configureRouting() { getGenres() AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) EpisodeTypeController(episodeTypeRepository).getRoutes(this) - getLangTypes() - EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository).getRoutes(this) + LangTypeController(langTypeRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository, langTypeRepository).getRoutes(this) NewsController(countryRepository, platformRepository).getRoutes(this) MangaController(platformRepository, animeRepository).getRoutes(this) } diff --git a/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt new file mode 100644 index 0000000..68cf218 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt @@ -0,0 +1,7 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.Genre +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class GenreRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/controllers/LangTypeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/LangTypeControllerTest.kt new file mode 100644 index 0000000..83c3dc6 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/LangTypeControllerTest.kt @@ -0,0 +1,88 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.LangType +import fr.ziedelth.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class LangTypeControllerTest : AbstractAPITest() { + @Test + fun getAll() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.get("/langtypes") + expect(HttpStatusCode.OK) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(2) { json.size } + } + } + + @Test + fun create() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.post("/langtypes") { + contentType(ContentType.Application.Json) + setBody(LangType(name = "test")) + } + + expect(HttpStatusCode.Created) { response.status } + val json = Gson().fromJson(response.bodyAsText(), LangType::class.java) + checkNotNull(json.uuid) + } + } + + @Test + fun createError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + expect(HttpStatusCode.BadRequest) { + client.post("/langtypes") { + contentType(ContentType.Application.Json) + setBody(LangType()) + }.status + } + + expect(HttpStatusCode.Conflict) { + client.post("/langtypes") { + contentType(ContentType.Application.Json) + setBody(LangType(name = "SUBTITLES")) + }.status + } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt index e0c9ce6..b8e3666 100644 --- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -2,7 +2,6 @@ package fr.ziedelth.plugins import fr.ziedelth.controllers.* import fr.ziedelth.controllers.GenreController.getGenres -import fr.ziedelth.controllers.LangTypeController.getLangTypes import fr.ziedelth.repositories.* import fr.ziedelth.utils.DatabaseTest import io.ktor.server.application.* @@ -25,8 +24,8 @@ fun Application.configureRoutingTest() { getGenres() AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) EpisodeTypeController(episodeTypeRepository).getRoutes(this) - getLangTypes() - EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository).getRoutes(this) + LangTypeController(langTypeRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository, langTypeRepository).getRoutes(this) NewsController(countryRepository, platformRepository).getRoutes(this) MangaController(platformRepository, animeRepository).getRoutes(this) } diff --git a/src/test/kotlin/fr/ziedelth/repositories/LangTypeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/LangTypeRepositoryTest.kt new file mode 100644 index 0000000..c972734 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/LangTypeRepositoryTest.kt @@ -0,0 +1,92 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.LangType +import fr.ziedelth.plugins.langTypeRepository +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.util.* +import kotlin.test.expect + +internal class LangTypeRepositoryTest : AbstractAPITest() { + @Test + fun find() { + val langType = langTypeRepository.find(UUID.randomUUID()) + expect(null) { langType } + + val langTypes = langTypeRepository.getAll() + expect(langTypes.first().uuid) { langTypeRepository.find(langTypes.first().uuid)?.uuid } + } + + @Test + fun exists() { + expect(true) { langTypeRepository.exists("name", "SUBTITLES") } + expect(false) { langTypeRepository.exists("uuid", UUID.randomUUID()) } + } + + @Test + fun findAll() { + expect(emptyList()) { langTypeRepository.findAll(listOf(UUID.randomUUID())) } + + val langTypes = langTypeRepository.getAll() + val list = langTypeRepository.findAll(listOf(langTypes[0].uuid, langTypes[1].uuid)) + + expect(true) { list.any { it.uuid == langTypes.first().uuid } && list.any { it.uuid == langTypes[1].uuid } } + } + + @Test + fun getAll() { + expect(2) { langTypeRepository.getAll().size } + } + + @Test + fun save() { + assertThrows { + langTypeRepository.save(LangType(name = "SUBTITLES")) + } + + val langType = LangType(name = "DUB") + langTypeRepository.save(langType) + + expect(3) { langTypeRepository.getAll().size } + checkNotNull { langType.uuid } + expect("DUB") { langType.name } + } + + @Test + fun saveAll() { + assertThrows { + langTypeRepository.saveAll( + listOf( + LangType(name = "SUBTITLES"), + LangType(name = "VOICE") + ) + ) + } + + val langType1 = LangType(name = "DUB") + val langType2 = LangType(name = "DUB2") + langTypeRepository.saveAll(listOf(langType1, langType2)) + + expect(4) { langTypeRepository.getAll().size } + checkNotNull { langType1.uuid } + checkNotNull { langType2.uuid } + expect("DUB") { langType1.name } + expect("DUB2") { langType2.name } + } + + @Test + fun delete() { + assertThrows { + langTypeRepository.delete( + LangType( + name = "SUBTITLES" + ) + ) + } + + val langTypes = langTypeRepository.getAll() + langTypeRepository.delete(langTypes.first()) + expect(1) { langTypes.size - 1 } + } +} From eb823ddf237d86dc857dfd555f9f0e477f6cbd7f Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 14:36:10 +0100 Subject: [PATCH 18/35] Add genre tests --- .../ziedelth/controllers/AnimeController.kt | 2 +- .../ziedelth/controllers/GenreController.kt | 21 +++-- .../kotlin/fr/ziedelth/plugins/Routing.kt | 6 +- .../kotlin/fr/ziedelth/AbstractAPITest.kt | 15 ++- .../controllers/GenreControllerTest.kt | 88 ++++++++++++++++++ .../kotlin/fr/ziedelth/plugins/RoutingTest.kt | 6 +- .../repositories/GenreRepositoryTest.kt | 92 +++++++++++++++++++ 7 files changed, 214 insertions(+), 16 deletions(-) create mode 100644 src/test/kotlin/fr/ziedelth/controllers/GenreControllerTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/repositories/GenreRepositoryTest.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index 2bf0ff5..9d36d77 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -209,7 +209,7 @@ class AnimeController( private fun Route.diary() { get("/diary/country/{country}/day/{day}") { val country = call.parameters["country"]!! - val day = call.parameters["day"]?.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest) + val day = call.parameters["day"]!!.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest) println("GET $prefix/diary/country/$country/day/$day") call.respond(animeRepository.getDiary(country, day)) } diff --git a/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt b/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt index 5f2570f..8273294 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt @@ -1,20 +1,29 @@ package fr.ziedelth.controllers import fr.ziedelth.entities.Genre +import fr.ziedelth.entities.isNullOrNotValid +import fr.ziedelth.repositories.GenreRepository import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -object GenreController : IController("/genres") { - fun Routing.getGenres() { - route(prefix) { +class GenreController(private val genreRepository: GenreRepository) : IController("/genres") { + fun getRoutes(routing: Routing) { + routing.route(prefix) { getAll() create() } } + override fun Route.getAll() { + get { + println("GET $prefix") + call.respond(genreRepository.getAll()) + } + } + private fun Route.create() { post { println("POST $prefix") @@ -22,17 +31,17 @@ object GenreController : IController("/genres") { try { val genre = call.receive() - if (genre.name.isNullOrBlank()) { + if (genre.isNullOrNotValid()) { call.respond(HttpStatusCode.BadRequest, MISSING_PARAMETERS_MESSAGE_ERROR) return@post } - if (isExists("name", genre.name)) { + if (genreRepository.exists("name", genre.name)) { call.respond(HttpStatusCode.Conflict, "$entityName already exists") return@post } - call.respond(HttpStatusCode.Created, justSave(genre)) + call.respond(HttpStatusCode.Created, genreRepository.save(genre)) } catch (e: Exception) { printError(call, e) } diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index 942dd66..700832c 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -1,7 +1,6 @@ package fr.ziedelth.plugins import fr.ziedelth.controllers.* -import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.repositories.* import io.ktor.server.application.* import io.ktor.server.routing.* @@ -10,8 +9,9 @@ fun Application.configureRouting() { routing { val countryRepository = CountryRepository() val platformRepository = PlatformRepository() - val animeRepository = AnimeRepository() val simulcastRepository = SimulcastRepository() + val genreRepository = GenreRepository() + val animeRepository = AnimeRepository() val episodeTypeRepository = EpisodeTypeRepository() val langTypeRepository = LangTypeRepository() val episodeRepository = EpisodeRepository() @@ -20,7 +20,7 @@ fun Application.configureRouting() { CountryController(countryRepository).getRoutes(this) PlatformController(platformRepository).getRoutes(this) SimulcastController(simulcastRepository).getRoutes(this) - getGenres() + GenreController(genreRepository).getRoutes(this) AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) EpisodeTypeController(episodeTypeRepository).getRoutes(this) LangTypeController(langTypeRepository).getRoutes(this) diff --git a/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt b/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt index 3c4573a..7db1b3e 100644 --- a/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt +++ b/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt @@ -28,26 +28,35 @@ internal abstract class AbstractAPITest { simulcastRepository.saveAll(listOf(simulcast1, simulcast2)) val simulcasts = simulcastRepository.getAll() + val genre1 = Genre(name = "Action") + val genre2 = Genre(name = "Comedy") + val genre3 = Genre(name = "Drama") + genreRepository.saveAll(listOf(genre1, genre2, genre3)) + val genres = genreRepository.getAll() + val anime1 = Anime( country = countries.first(), name = "One Piece", image = "hello", hashes = mutableSetOf("hello"), - simulcasts = mutableSetOf(simulcasts.first()) + simulcasts = mutableSetOf(simulcasts.first()), + genres = mutableSetOf(genres.first(), genres.last()), ) val anime2 = Anime( country = countries.first(), name = "Naruto", image = "hello", hashes = mutableSetOf("hello2"), - simulcasts = mutableSetOf(simulcasts.first()) + simulcasts = mutableSetOf(simulcasts.first()), + genres = mutableSetOf(genres.first(), genres.last()), ) val anime3 = Anime( country = countries.first(), name = "Bleach", image = "hello", hashes = mutableSetOf("hello3"), - simulcasts = mutableSetOf(simulcasts.first()) + simulcasts = mutableSetOf(simulcasts.first()), + genres = mutableSetOf(genres.first(), genres.last()), ) animeRepository.saveAll(listOf(anime1, anime2, anime3)) val animes = animeRepository.getAll() diff --git a/src/test/kotlin/fr/ziedelth/controllers/GenreControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/GenreControllerTest.kt new file mode 100644 index 0000000..3f15512 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/GenreControllerTest.kt @@ -0,0 +1,88 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.Genre +import fr.ziedelth.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class GenreControllerTest : AbstractAPITest() { + @Test + fun getAll() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.get("/genres") + expect(HttpStatusCode.OK) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(3) { json.size } + } + } + + @Test + fun create() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val response = client.post("/genres") { + contentType(ContentType.Application.Json) + setBody(Genre(name = "test")) + } + + expect(HttpStatusCode.Created) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Genre::class.java) + checkNotNull(json.uuid) + } + } + + @Test + fun createError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + expect(HttpStatusCode.BadRequest) { + client.post("/genres") { + contentType(ContentType.Application.Json) + setBody(Genre()) + }.status + } + + expect(HttpStatusCode.Conflict) { + client.post("/genres") { + contentType(ContentType.Application.Json) + setBody(Genre(name = "Action")) + }.status + } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt index b8e3666..cff8c3e 100644 --- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -1,7 +1,6 @@ package fr.ziedelth.plugins import fr.ziedelth.controllers.* -import fr.ziedelth.controllers.GenreController.getGenres import fr.ziedelth.repositories.* import fr.ziedelth.utils.DatabaseTest import io.ktor.server.application.* @@ -9,8 +8,9 @@ import io.ktor.server.routing.* val countryRepository = CountryRepository { DatabaseTest.getSession() } val platformRepository = PlatformRepository { DatabaseTest.getSession() } -val animeRepository = AnimeRepository { DatabaseTest.getSession() } val simulcastRepository = SimulcastRepository { DatabaseTest.getSession() } +val genreRepository = GenreRepository { DatabaseTest.getSession() } +val animeRepository = AnimeRepository { DatabaseTest.getSession() } val episodeTypeRepository = EpisodeTypeRepository { DatabaseTest.getSession() } val langTypeRepository = LangTypeRepository { DatabaseTest.getSession() } val episodeRepository = EpisodeRepository { DatabaseTest.getSession() } @@ -21,7 +21,7 @@ fun Application.configureRoutingTest() { CountryController(countryRepository).getRoutes(this) PlatformController(platformRepository).getRoutes(this) SimulcastController(simulcastRepository).getRoutes(this) - getGenres() + GenreController(genreRepository).getRoutes(this) AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) EpisodeTypeController(episodeTypeRepository).getRoutes(this) LangTypeController(langTypeRepository).getRoutes(this) diff --git a/src/test/kotlin/fr/ziedelth/repositories/GenreRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/GenreRepositoryTest.kt new file mode 100644 index 0000000..5607f22 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/GenreRepositoryTest.kt @@ -0,0 +1,92 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.Genre +import fr.ziedelth.plugins.genreRepository +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.util.* +import kotlin.test.expect + +internal class GenreRepositoryTest : AbstractAPITest() { + @Test + fun find() { + val genre = genreRepository.find(UUID.randomUUID()) + expect(null) { genre } + + val genres = genreRepository.getAll() + expect(genres.first().uuid) { genreRepository.find(genres.first().uuid)?.uuid } + } + + @Test + fun exists() { + expect(true) { genreRepository.exists("name", "Action") } + expect(false) { genreRepository.exists("uuid", UUID.randomUUID()) } + } + + @Test + fun findAll() { + expect(emptyList()) { genreRepository.findAll(listOf(UUID.randomUUID())) } + + val genres = genreRepository.getAll() + val list = genreRepository.findAll(listOf(genres[0].uuid, genres[1].uuid)) + + expect(true) { list.any { it.uuid == genres.first().uuid } && list.any { it.uuid == genres[1].uuid } } + } + + @Test + fun getAll() { + expect(3) { genreRepository.getAll().size } + } + + @Test + fun save() { + assertThrows { + genreRepository.save(Genre(name = "Action")) + } + + val genre = Genre(name = "Fantasy") + genreRepository.save(genre) + + expect(4) { genreRepository.getAll().size } + checkNotNull { genre.uuid } + expect("Fantasy") { genre.name } + } + + @Test + fun saveAll() { + assertThrows { + genreRepository.saveAll( + listOf( + Genre(name = "Action"), + Genre(name = "Drama") + ) + ) + } + + val genre1 = Genre(name = "Fantasy") + val genre2 = Genre(name = "Horror") + genreRepository.saveAll(listOf(genre1, genre2)) + + expect(5) { genreRepository.getAll().size } + checkNotNull { genre1.uuid } + checkNotNull { genre2.uuid } + expect("Fantasy") { genre1.name } + expect("Horror") { genre2.name } + } + + @Test + fun delete() { + assertThrows { + genreRepository.delete( + Genre( + name = "Action" + ) + ) + } + + val genres = genreRepository.getAll() + genreRepository.delete(genres.first()) + expect(2) { genres.size - 1 } + } +} From b7a0f23550a444d4279efa46f7ca29a525e05d9b Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 15:28:37 +0100 Subject: [PATCH 19/35] Exclude packages --- pom.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3d0782c..5d6e379 100644 --- a/pom.xml +++ b/pom.xml @@ -229,8 +229,10 @@ 0.8.8 - fr/ziedelth/entities/* - fr/ziedelth/plugins/* + **/fr/ziedelth/events/** + **/fr/ziedelth/listeners/** + **/fr/ziedelth/plugins/** + **/fr/ziedelth/utils/** From 2732afd7826064db2f5f0b272105cfbe00acaf0f Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 16:20:44 +0100 Subject: [PATCH 20/35] change to xml report format --- pom.xml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 5d6e379..2af66e4 100644 --- a/pom.xml +++ b/pom.xml @@ -228,11 +228,14 @@ jacoco-maven-plugin 0.8.8 + + XML + - **/fr/ziedelth/events/** - **/fr/ziedelth/listeners/** - **/fr/ziedelth/plugins/** - **/fr/ziedelth/utils/** + fr/ziedelth/events/** + fr/ziedelth/listeners/** + fr/ziedelth/plugins/** + fr/ziedelth/utils/** From 33fdfedeb38074745f171254f467e2cb9a324740 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 16:24:11 +0100 Subject: [PATCH 21/35] Try sonar exclusion --- pom.xml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 2af66e4..ad5f33d 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ true fr.ziedelth.ApplicationKt 5.9.1 + **/fr/ziedelth/events/**,**/fr/ziedelth/listeners/**,**/fr/ziedelth/plugins/**,**/fr/ziedelth/utils/** @@ -227,17 +228,6 @@ org.jacoco jacoco-maven-plugin 0.8.8 - - - XML - - - fr/ziedelth/events/** - fr/ziedelth/listeners/** - fr/ziedelth/plugins/** - fr/ziedelth/utils/** - - prepare-agent From 2bdc638ab6280fab9de84809e27cccb0c2ba71eb Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Wed, 16 Nov 2022 16:29:59 +0100 Subject: [PATCH 22/35] Add main file to exclusion --- pom.xml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad5f33d..74e95ea 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,14 @@ true fr.ziedelth.ApplicationKt 5.9.1 - **/fr/ziedelth/events/**,**/fr/ziedelth/listeners/**,**/fr/ziedelth/plugins/**,**/fr/ziedelth/utils/** + + + **/fr/ziedelth/events/**, + **/fr/ziedelth/listeners/**, + **/fr/ziedelth/plugins/**, + **/fr/ziedelth/utils/**, + **/fr/ziedelth/Application.kt + From bc827f0125461be01da4912d752008d42abcefae Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Sat, 19 Nov 2022 11:58:57 +0100 Subject: [PATCH 23/35] Rename --- .../controllers/{IController.kt => AbstractController.kt} | 0 .../repositories/{IRepository.kt => AbstractRepository.kt} | 2 +- src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt | 2 +- src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt | 2 +- src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt | 2 +- .../kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt | 2 +- src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt | 2 +- src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt | 2 +- src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt | 2 +- src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt | 2 +- src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt | 2 +- 11 files changed, 10 insertions(+), 10 deletions(-) rename src/main/kotlin/fr/ziedelth/controllers/{IController.kt => AbstractController.kt} (100%) rename src/main/kotlin/fr/ziedelth/repositories/{IRepository.kt => AbstractRepository.kt} (97%) diff --git a/src/main/kotlin/fr/ziedelth/controllers/IController.kt b/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt similarity index 100% rename from src/main/kotlin/fr/ziedelth/controllers/IController.kt rename to src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt diff --git a/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt similarity index 97% rename from src/main/kotlin/fr/ziedelth/repositories/IRepository.kt rename to src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt index bc687db..ea2b99a 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/IRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt @@ -5,7 +5,7 @@ import org.hibernate.Session import java.lang.reflect.ParameterizedType import java.util.* -open class IRepository(val getSession: () -> Session = { Database.getSession() }) { +open class AbstractRepository(val getSession: () -> Session = { Database.getSession() }) { private val entityClass: Class = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class private val entityName: String = entityClass.simpleName diff --git a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt index ec0173e..eca5381 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt @@ -5,7 +5,7 @@ import fr.ziedelth.utils.Database import org.hibernate.Session import java.util.* -class AnimeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) { +class AnimeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { fun findByHash(tag: String, hash: String): UUID? { val session = getSession.invoke() val query = session.createQuery( diff --git a/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt index fd1942a..00d9a6b 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/CountryRepository.kt @@ -4,4 +4,4 @@ import fr.ziedelth.entities.Country import fr.ziedelth.utils.Database import org.hibernate.Session -class CountryRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file +class CountryRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt index 8ca2370..7ef7bfd 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt @@ -4,4 +4,4 @@ import fr.ziedelth.entities.Episode import fr.ziedelth.utils.Database import org.hibernate.Session -class EpisodeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file +class EpisodeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt index 27b8200..5f08661 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt @@ -4,4 +4,4 @@ import fr.ziedelth.entities.EpisodeType import fr.ziedelth.utils.Database import org.hibernate.Session -class EpisodeTypeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file +class EpisodeTypeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt index 68cf218..2ceddef 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/GenreRepository.kt @@ -4,4 +4,4 @@ import fr.ziedelth.entities.Genre import fr.ziedelth.utils.Database import org.hibernate.Session -class GenreRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file +class GenreRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt index 8038ef7..307b144 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/LangTypeRepository.kt @@ -4,4 +4,4 @@ import fr.ziedelth.entities.LangType import fr.ziedelth.utils.Database import org.hibernate.Session -class LangTypeRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file +class LangTypeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt index ddda5f6..b8e37f6 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt @@ -4,4 +4,4 @@ import fr.ziedelth.entities.Manga import fr.ziedelth.utils.Database import org.hibernate.Session -class MangaRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file +class MangaRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt index a0f2966..701fd40 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/PlatformRepository.kt @@ -4,4 +4,4 @@ import fr.ziedelth.entities.Platform import fr.ziedelth.utils.Database import org.hibernate.Session -class PlatformRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) \ No newline at end of file +class PlatformRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt index c0ab941..51d407c 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/SimulcastRepository.kt @@ -4,7 +4,7 @@ import fr.ziedelth.entities.Simulcast import fr.ziedelth.utils.Database import org.hibernate.Session -class SimulcastRepository(session: () -> Session = { Database.getSession() }) : IRepository(session) { +class SimulcastRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { fun getAll(tag: String?): List { val session = getSession.invoke() val query = session.createQuery( From 9097d4133bfb15b47efef73de5b17e6efaf1c508 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Sun, 20 Nov 2022 18:24:07 +0100 Subject: [PATCH 24/35] Change EpisodeController --- .../ziedelth/controllers/EpisodeController.kt | 101 +++++------------- .../repositories/EpisodeRepository.kt | 45 +++++++- .../repositories/EpisodeRepositoryTest.kt | 16 +++ 3 files changed, 86 insertions(+), 76 deletions(-) create mode 100644 src/test/kotlin/fr/ziedelth/repositories/EpisodeRepositoryTest.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt index 8315a0e..0c4835c 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt @@ -6,7 +6,6 @@ import fr.ziedelth.entities.Simulcast import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.EpisodesReleaseEvent import fr.ziedelth.repositories.* -import fr.ziedelth.utils.Database import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache import fr.ziedelth.utils.RequestCache @@ -24,6 +23,7 @@ class EpisodeController( private val simulcastRepository: SimulcastRepository, private val episodeTypeRepository: EpisodeTypeRepository, private val langTypeRepository: LangTypeRepository, + private val episodeRepository: EpisodeRepository, ) : IController("/episodes") { fun getRoutes(routing: Routing) { routing.route(prefix) { @@ -37,96 +37,47 @@ class EpisodeController( private fun Route.getWithPage() { get("/country/{country}/page/{page}/limit/{limit}") { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val page = call.parameters["page"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - val limit = call.parameters["limit"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - if (page < 1 || limit < 1) return@get call.respond(HttpStatusCode.BadRequest) - if (limit > 30) return@get call.respond(HttpStatusCode.BadRequest) - println("GET $prefix/country/$country/page/$page/limit/$limit") - val request = RequestCache.get(uuidRequest, country, page, limit) - - if (request == null || request.isExpired()) { - val session = Database.getSession() - - try { - val query = session.createQuery( - "FROM Episode WHERE anime.country.tag = :tag ORDER BY releaseDate DESC, anime.name, season DESC, number DESC, episodeType.name, langType.name", - Episode::class.java - ) - query.setParameter("tag", country) - query.firstResult = (limit * page) - limit - query.maxResults = limit - request?.update(query.list()) ?: RequestCache.put( - uuidRequest, - country, - page, - limit, - value = query.list() - ) - } catch (e: Exception) { - printError(call, e) - } finally { - session.close() + try { + val country = call.parameters["country"]!! + val (page, limit) = getPageAndLimit() + println("GET $prefix/country/$country/page/$page/limit/$limit") + val request = RequestCache.get(uuidRequest, country, page, limit) + + if (request == null || request.isExpired()) { + val list = episodeRepository.getByPage(country, page, limit) + request?.update(list) ?: RequestCache.put(uuidRequest, country, page, limit, value = list) } - } - call.respond(RequestCache.get(uuidRequest, country, page, limit)?.value ?: HttpStatusCode.NotFound) + call.respond(RequestCache.get(uuidRequest, country, page, limit)!!.value!!) + } catch (e: Exception) { + printError(call, e) + } } } private fun Route.getAnimeWithPage() { get("/anime/{uuid}/page/{page}/limit/{limit}") { - val animeUuid = call.parameters["uuid"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val page = call.parameters["page"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - val limit = call.parameters["limit"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - if (page < 1 || limit < 1) return@get call.respond(HttpStatusCode.BadRequest) - if (limit > 30) return@get call.respond(HttpStatusCode.BadRequest) - println("GET $prefix/anime/$animeUuid/page/$page/limit/$limit") - val session = Database.getSession() - try { - val query = session.createQuery( - "FROM Episode WHERE anime.uuid = :uuid ORDER BY season DESC, number DESC, episodeType.name, langType.name", - Episode::class.java - ) - query.setParameter("uuid", UUID.fromString(animeUuid)) - query.firstResult = (limit * page) - limit - query.maxResults = limit - call.respond(query.list() ?: HttpStatusCode.NotFound) + val animeUuid = call.parameters["uuid"]!! + val (page, limit) = getPageAndLimit() + println("GET $prefix/anime/$animeUuid/page/$page/limit/$limit") + call.respond(episodeRepository.getByPageWithAnime(UUID.fromString(animeUuid), page, limit)) } catch (e: Exception) { printError(call, e) - } finally { - session.close() } } } private fun Route.getWatchlistWithPage() { post("/watchlist/page/{page}/limit/{limit}") { - val watchlist = call.receive() - val page = call.parameters["page"]?.toInt() ?: return@post call.respond(HttpStatusCode.BadRequest) - val limit = call.parameters["limit"]?.toInt() ?: return@post call.respond(HttpStatusCode.BadRequest) - if (page < 1 || limit < 1) return@post call.respond(HttpStatusCode.BadRequest) - if (limit > 30) return@post call.respond(HttpStatusCode.BadRequest) - println("POST $prefix/watchlist/page/$page/limit/$limit") - val session = Database.getSession() - try { - val dataFromGzip = - Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } - - val query = session.createQuery( - "FROM $entityName WHERE anime.uuid IN :list ORDER BY releaseDate DESC, anime.name, season DESC, number DESC, episodeType.name, langType.name", - entityClass - ) - query.setParameter("list", dataFromGzip) - query.firstResult = (limit * page) - limit - query.maxResults = limit - call.respond(query.list()) + val watchlist = call.receive() + val (page, limit) = getPageAndLimit() + println("POST $prefix/watchlist/page/$page/limit/$limit") + val dataFromGzip = Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } + call.respond(episodeRepository.getByPageWithList(dataFromGzip, page, limit)) } catch (e: Exception) { printError(call, e) - } finally { - session.close() } } } @@ -156,17 +107,17 @@ class EpisodeController( println("POST $prefix/multiple") try { - val episodes = call.receive>().filter { !isExists("hash", it.hash!!) } + val episodes = call.receive>().filter { !episodeRepository.exists("hash", it.hash!!) } val savedEpisodes = mutableListOf() episodes.forEach { merge(it) - val savedEpisode = justSave(it) + val savedEpisode = episodeRepository.save(it) savedEpisodes.add(savedEpisode) ImageCache.cachingNetworkImage(savedEpisode.uuid, savedEpisode.image!!) } - call.respond(HttpStatusCode.Created, episodes) + call.respond(HttpStatusCode.Created, savedEpisodes) PluginManager.callEvent(EpisodesReleaseEvent(savedEpisodes)) } catch (e: Exception) { printError(call, e) diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt index 7ef7bfd..0d399e1 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt @@ -3,5 +3,48 @@ package fr.ziedelth.repositories import fr.ziedelth.entities.Episode import fr.ziedelth.utils.Database import org.hibernate.Session +import java.util.UUID -class EpisodeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file +class EpisodeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { + fun getByPage(tag: String, page: Int, limit: Int): List { + val session = getSession.invoke() + val query = session.createQuery( + "FROM Episode WHERE anime.country.tag = :tag ORDER BY releaseDate DESC, anime.name, season DESC, number DESC, episodeType.name, langType.name", + Episode::class.java + ) + query.setParameter("tag", tag) + query.firstResult = (limit * page) - limit + query.maxResults = limit + val list = query.list() + session.close() + return list + } + + fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List { + val session = getSession.invoke() + val query = session.createQuery( + "FROM Episode WHERE anime.uuid = :uuid ORDER BY season DESC, number DESC, episodeType.name, langType.name", + Episode::class.java + ) + query.setParameter("uuid", uuid) + query.firstResult = (limit * page) - limit + query.maxResults = limit + val list = query.list() + session.close() + return list + } + + fun getByPageWithList(list: List, page: Int, limit: Int): List { + val session = getSession.invoke() + val query = session.createQuery( + "FROM Episode WHERE anime.uuid IN :list ORDER BY releaseDate DESC, anime.name, season DESC, number DESC, episodeType.name, langType.name", + Episode::class.java + ) + query.setParameter("list", list) + query.firstResult = (limit * page) - limit + query.maxResults = limit + val result = query.list() + session.close() + return result + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/repositories/EpisodeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/EpisodeRepositoryTest.kt new file mode 100644 index 0000000..9249335 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/EpisodeRepositoryTest.kt @@ -0,0 +1,16 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.plugins.episodeRepository +import org.junit.jupiter.api.Test +import kotlin.test.expect + +internal class EpisodeRepositoryTest : AbstractAPITest() { + @Test + fun getByPage() { + val page1 = episodeRepository.getByPage("fr", 1, 2) + expect(2) { page1.size } + val page2 = episodeRepository.getByPage("fr", 2, 2) + expect(2) { page2.size } + } +} From 091062358fe062867d6a1efb704cef4c3a442ec9 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Sun, 20 Nov 2022 18:26:04 +0100 Subject: [PATCH 25/35] Fix --- src/main/kotlin/fr/ziedelth/plugins/Routing.kt | 2 +- src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index 700832c..2e1df27 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -24,7 +24,7 @@ fun Application.configureRouting() { AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) EpisodeTypeController(episodeTypeRepository).getRoutes(this) LangTypeController(langTypeRepository).getRoutes(this) - EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository, langTypeRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository, langTypeRepository, episodeRepository).getRoutes(this) NewsController(countryRepository, platformRepository).getRoutes(this) MangaController(platformRepository, animeRepository).getRoutes(this) } diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt index cff8c3e..f8df3f3 100644 --- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -25,7 +25,7 @@ fun Application.configureRoutingTest() { AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) EpisodeTypeController(episodeTypeRepository).getRoutes(this) LangTypeController(langTypeRepository).getRoutes(this) - EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository, langTypeRepository).getRoutes(this) + EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository, langTypeRepository, episodeRepository).getRoutes(this) NewsController(countryRepository, platformRepository).getRoutes(this) MangaController(platformRepository, animeRepository).getRoutes(this) } From bb4b6b9148e6f4a1f258548683378770322f7d26 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Sun, 20 Nov 2022 18:56:47 +0100 Subject: [PATCH 26/35] Add more tests for EpisodeRepository --- .../repositories/EpisodeRepositoryTest.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/kotlin/fr/ziedelth/repositories/EpisodeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/EpisodeRepositoryTest.kt index 9249335..42db2b0 100644 --- a/src/test/kotlin/fr/ziedelth/repositories/EpisodeRepositoryTest.kt +++ b/src/test/kotlin/fr/ziedelth/repositories/EpisodeRepositoryTest.kt @@ -1,6 +1,7 @@ package fr.ziedelth.repositories import fr.ziedelth.AbstractAPITest +import fr.ziedelth.plugins.animeRepository import fr.ziedelth.plugins.episodeRepository import org.junit.jupiter.api.Test import kotlin.test.expect @@ -13,4 +14,24 @@ internal class EpisodeRepositoryTest : AbstractAPITest() { val page2 = episodeRepository.getByPage("fr", 2, 2) expect(2) { page2.size } } + + @Test + fun getByPageWithAnime() { + val anime = animeRepository.getAll().first() + + val page1 = episodeRepository.getByPageWithAnime(anime.uuid, 1, 2) + expect(2) { page1.size } + val page2 = episodeRepository.getByPageWithAnime(anime.uuid, 2, 2) + expect(2) { page2.size } + } + + @Test + fun getByPageWithList() { + val animes = animeRepository.getAll().take(2).map { it.uuid } + + val page1 = episodeRepository.getByPageWithList(animes, 1, 2) + expect(2) { page1.size } + val page2 = episodeRepository.getByPageWithList(animes, 2, 2) + expect(2) { page2.size } + } } From 28a1c0724e22f9ffe30135f552635683506bb0d1 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Sun, 20 Nov 2022 19:21:41 +0100 Subject: [PATCH 27/35] Add tests for EpisodeController --- .../controllers/AnimeControllerTest.kt | 8 - .../controllers/EpisodeControllerTest.kt | 237 ++++++++++++++++++ 2 files changed, 237 insertions(+), 8 deletions(-) create mode 100644 src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt diff --git a/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt index c3691be..5633af9 100644 --- a/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt +++ b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt @@ -122,14 +122,6 @@ internal class AnimeControllerTest : AbstractAPITest() { expect(HttpStatusCode.OK) { response.status } expect(1) { json.size } - - // ERROR - - val responseError = client.post("/animes/watchlist/page/ae/limit/12") { - setBody(bodyRequest) - } - - expect(HttpStatusCode.InternalServerError) { responseError.status } } } diff --git a/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt new file mode 100644 index 0000000..5610342 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt @@ -0,0 +1,237 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.* +import fr.ziedelth.plugins.* +import fr.ziedelth.utils.Encoder +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class EpisodeControllerTest : AbstractAPITest() { + @Test + fun getByPage() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + + // NOT CACHED + + val responseNotCached = + client.get("/episodes/country/${country.tag}/page/1/limit/12") + val jsonNotCached = Gson().fromJson(responseNotCached.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { responseNotCached.status } + expect(12) { jsonNotCached.size } + + // CACHED + + val responseCached = + client.get("/episodes/country/${country.tag}/page/1/limit/12") + val jsonCached = Gson().fromJson(responseCached.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { responseCached.status } + expect(12) { jsonCached.size } + } + } + + @Test + fun getByPageError() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + + // ERROR + + val responseError = + client.get("/episodes/country/${country.tag}/page/ae/limit/12") + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun getByPageWithAnime() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val anime = animeRepository.getAll().first() + + val response = + client.get("/episodes/anime/${anime.uuid}/page/1/limit/12") + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { response.status } + expect(10) { json.size } + } + } + + @Test + fun getByPageWithAnimeError() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val anime = animeRepository.getAll().first() + + // ERROR + + val responseError = + client.get("/episodes/anime/${anime.uuid}/page/ae/limit/12") + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun getWatchlistByPage() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val anime = animeRepository.getAll().first() + val bodyRequest = Encoder.toGzip("[\"${anime.uuid}\"]") + + val response = client.post("/episodes/watchlist/page/1/limit/12") { + setBody(bodyRequest) + } + + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { response.status } + expect(10) { json.size } + } + } + + @Test + fun getWatchlistByPageError() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val anime = animeRepository.getAll().first() + val bodyRequest = Encoder.toGzip("[\"${anime.uuid}\"]") + + val responseError = client.post("/episodes/watchlist/page/ae/limit/12") { + setBody(bodyRequest) + } + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun save() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val platform = platformRepository.getAll().first() + val anime = animeRepository.getAll().first() + val episodeType = episodeTypeRepository.getAll().first() + val langType = langTypeRepository.getAll().first() + + val response = client.post("/episodes/multiple") { + contentType(ContentType.Application.Json) + setBody(listOf( + Episode( + anime = anime, + platform = platform, + episodeType = episodeType, + langType = langType, + number = 1, + season = 1, + url = "https://www.google.com", + image = "https://www.google.com", + hash = "hash", + ), + Episode( + anime = anime, + platform = platform, + episodeType = episodeType, + langType = langType, + number = 2, + season = 1, + url = "https://www.google.com", + image = "https://www.google.com", + hash = "azertyuiop", + ) + )) + } + + expect(HttpStatusCode.Created) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(2) { json.size } + } + } + + @Test + fun saveError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + expect(HttpStatusCode.InternalServerError) { + client.post("/episodes/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + Episode( + anime = Anime(), + platform = Platform(), + episodeType = EpisodeType(), + langType = LangType(), + number = 1, + season = 1, + url = "https://www.google.com", + image = "https://www.google.com", + hash = "hash", + ), + ) + ) + }.status + } + } + } +} \ No newline at end of file From abe8ee96a065bc945fb754199d3c7b13662ce14d Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Sun, 20 Nov 2022 19:35:59 +0100 Subject: [PATCH 28/35] Add more tests for EpisodeController --- .../controllers/EpisodeControllerTest.kt | 91 ++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt index 5610342..f7cb1a9 100644 --- a/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt +++ b/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt @@ -218,15 +218,102 @@ internal class EpisodeControllerTest : AbstractAPITest() { setBody( listOf( Episode( - anime = Anime(), platform = Platform(), + anime = Anime(), + episodeType = EpisodeType(), + langType = LangType(), + number = 1, + season = 1, + url = "https://www.google.com", + image = "https://www.google.com", + ), + ) + ) + }.status + } + + val platform = platformRepository.getAll().first() + + expect(HttpStatusCode.InternalServerError) { + client.post("/episodes/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + Episode( + platform = platform, + anime = Anime(), + episodeType = EpisodeType(), + langType = LangType(), + number = 1, + season = 1, + url = "https://www.google.com", + image = "https://www.google.com", + ), + ) + ) + }.status + } + + val anime = animeRepository.getAll().first() + + expect(HttpStatusCode.InternalServerError) { + client.post("/episodes/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + Episode( + platform = platform, + anime = anime, episodeType = EpisodeType(), langType = LangType(), number = 1, season = 1, url = "https://www.google.com", image = "https://www.google.com", - hash = "hash", + ), + ) + ) + }.status + } + + val episodeType = episodeTypeRepository.getAll().first() + + expect(HttpStatusCode.InternalServerError) { + client.post("/episodes/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + Episode( + platform = platform, + anime = anime, + episodeType = episodeType, + langType = LangType(), + number = 1, + season = 1, + url = "https://www.google.com", + image = "https://www.google.com", + ), + ) + ) + }.status + } + + val langType = langTypeRepository.getAll().first() + + expect(HttpStatusCode.InternalServerError) { + client.post("/episodes/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + Episode( + platform = platform, + anime = anime, + episodeType = episodeType, + langType = langType, + number = 1, + season = 1, + url = "https://www.google.com", + image = "https://www.google.com", ), ) ) From db9217c9aec880fce25adab96778ef2cab1895b0 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Sun, 20 Nov 2022 22:52:27 +0100 Subject: [PATCH 29/35] Update and add more tests --- .../controllers/AbstractController.kt | 131 +------- .../ziedelth/controllers/AnimeController.kt | 4 +- .../ziedelth/controllers/CountryController.kt | 2 +- .../ziedelth/controllers/EpisodeController.kt | 6 +- .../controllers/EpisodeTypeController.kt | 5 +- .../ziedelth/controllers/GenreController.kt | 2 +- .../controllers/LangTypeController.kt | 2 +- .../ziedelth/controllers/MangaController.kt | 128 ++------ .../fr/ziedelth/controllers/NewsController.kt | 54 ++-- .../controllers/PlatformController.kt | 2 +- src/main/kotlin/fr/ziedelth/entities/Manga.kt | 1 + .../kotlin/fr/ziedelth/plugins/Routing.kt | 14 +- .../repositories/AbstractRepository.kt | 11 + .../ziedelth/repositories/AnimeRepository.kt | 29 +- .../repositories/EpisodeRepository.kt | 41 +-- .../repositories/EpisodeTypeRepository.kt | 3 +- .../ziedelth/repositories/MangaRepository.kt | 41 ++- .../ziedelth/repositories/NewsRepository.kt | 16 + .../kotlin/fr/ziedelth/AbstractAPITest.kt | 39 +++ .../controllers/EpisodeControllerTest.kt | 48 +-- .../controllers/MangaControllerTest.kt | 306 ++++++++++++++++++ .../controllers/NewsControllerTest.kt | 187 +++++++++++ .../kotlin/fr/ziedelth/plugins/RoutingTest.kt | 14 +- .../repositories/MangaRepositoryTest.kt | 37 +++ .../repositories/NewsRepositoryTest.kt | 16 + 25 files changed, 795 insertions(+), 344 deletions(-) create mode 100644 src/main/kotlin/fr/ziedelth/repositories/NewsRepository.kt create mode 100644 src/test/kotlin/fr/ziedelth/controllers/MangaControllerTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/controllers/NewsControllerTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/repositories/MangaRepositoryTest.kt create mode 100644 src/test/kotlin/fr/ziedelth/repositories/NewsRepositoryTest.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt b/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt index 37b0973..f127648 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt @@ -1,6 +1,5 @@ package fr.ziedelth.controllers -import fr.ziedelth.utils.Database import fr.ziedelth.utils.ImageCache import io.ktor.http.* import io.ktor.server.application.* @@ -15,14 +14,14 @@ const val UNKNOWN_MESSAGE_ERROR = "Unknown error" const val MISSING_PARAMETERS_MESSAGE_ERROR = "Missing parameters" open class IController(val prefix: String) { - val entityClass: Class = + private val entityClass: Class = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class val entityName: String = entityClass.simpleName val uuidRequest: UUID = UUID.randomUUID() fun PipelineContext.getPageAndLimit(): Pair { - val page = call.parameters["page"]?.toInt() ?: throw IllegalArgumentException("Page is not valid") - val limit = call.parameters["limit"]?.toInt() ?: throw IllegalArgumentException("Limit is not valid") + val page = call.parameters["page"]!!.toIntOrNull() ?: throw IllegalArgumentException("Page is not valid") + val limit = call.parameters["limit"]!!.toIntOrNull() ?: throw IllegalArgumentException("Limit is not valid") if (page < 1 || limit < 1) { throw IllegalArgumentException("Page or limit is not valid") @@ -40,131 +39,9 @@ open class IController(val prefix: String) { call.respond(HttpStatusCode.InternalServerError, e.message ?: UNKNOWN_MESSAGE_ERROR) } - private fun getAll(): MutableList { - val session = Database.getSession() - - try { - val query = session.createQuery("FROM $entityName", entityClass) - return query.list() - } catch (e: Exception) { - e.printStackTrace() - println("Error while getting $prefix : ${e.message}") - throw e - } finally { - session.close() - } - } - - fun getAllBy(field: String, value: Any?): MutableList { - val session = Database.getSession() - - try { - val query = session.createQuery( - "FROM $entityName WHERE $field = :${field.filter { it.isLetterOrDigit() }.trim()}", - entityClass - ) - query.setParameter(field.filter { it.isLetterOrDigit() }.trim(), value) - return query.list() - } catch (e: Exception) { - e.printStackTrace() - println("Error while getting $prefix : ${e.message}") - throw e - } finally { - session.close() - } - } - - fun getBy(field: String, value: Any?): T? { - val session = Database.getSession() - - try { - val query = session.createQuery("FROM $entityName WHERE $field = :$field", entityClass) - query.maxResults = 1 - query.setParameter(field, value) - return query.uniqueResult() - } catch (e: Exception) { - e.printStackTrace() - println("Error while getting $prefix : ${e.message}") - throw e - } finally { - session.close() - } - } - - fun isExists(field: String, value: Any?): Boolean { - val session = Database.getSession() - val query = session.createQuery("SELECT COUNT(*) FROM $entityName WHERE $field = :$field", Long::class.java) - query.maxResults = 1 - query.setParameter(field, value) - val list = query.uniqueResult() - session.close() - return list > 0 - } - - fun contains(fieldList: String, searchValue: String?): Boolean { - val session = Database.getSession() - val query = session.createQuery( - "SELECT COUNT(*) FROM $entityName JOIN $fieldList l WHERE l = :search", - Long::class.java - ) - query.maxResults = 1 - query.setParameter("search", searchValue) - val list = query.uniqueResult() - session.close() - return list > 0 - } - - fun justSave(dtoIn: T): T { - val session = Database.getSession() - val transaction = session.beginTransaction() - - try { - val entity = session.merge(dtoIn) - session.persist(entity) - transaction.commit() - return entity - } catch (e: Exception) { - e.printStackTrace() - println("Error while saving $prefix : ${e.message}") - transaction.rollback() - throw e - } finally { - session.close() - } - } - - fun justUpdate(dtoIn: T) { - val session = Database.getSession() - val transaction = session.beginTransaction() - - try { - session.persist(session.merge(dtoIn)) - transaction.commit() - } catch (e: Exception) { - e.printStackTrace() - println("Error while updating $prefix : ${e.message}") - transaction.rollback() - throw e - } finally { - session.close() - } - } - - open fun Route.getAll() { - get { - println("GET $prefix") - - try { - call.respond(this@IController.getAll()) - } catch (e: Exception) { - printError(call, e) - } - } - } - fun Route.getAttachment() { get("/attachment/{uuid}") { - val string = call.parameters["uuid"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val string = call.parameters["uuid"]!! val uuidRegex = "^[0-9(a-f|A-F)]{8}-[0-9(a-f|A-F)]{4}-4[0-9(a-f|A-F)]{3}-[89ab][0-9(a-f|A-F)]{3}-[0-9(a-f|A-F)]{12}\$".toRegex() diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index 9d36d77..7f8c33d 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -197,8 +197,8 @@ class AnimeController( )!! ImageCache.cachingNetworkImage(savedAnime.uuid, savedAnime.image!!) - episodes.map { it.copy(anime = savedAnime) }.map { episodeRepository.save(it) } - mangas.map { it.copy(anime = savedAnime) }.map { mangaRepository.save(it) } + episodeRepository.saveAll(episodes.map { it.copy(anime = savedAnime) }) + mangaRepository.saveAll(mangas.map { it.copy(anime = savedAnime) }) // Delete animes animeRepository.deleteAll(animes) diff --git a/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt b/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt index a20be6f..f8a4945 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/CountryController.kt @@ -17,7 +17,7 @@ class CountryController(private val countryRepository: CountryRepository) : ICon } } - override fun Route.getAll() { + fun Route.getAll() { get { println("GET $prefix") call.respond(countryRepository.getAll()) diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt index 0c4835c..c3b9de8 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt @@ -74,7 +74,8 @@ class EpisodeController( val watchlist = call.receive() val (page, limit) = getPageAndLimit() println("POST $prefix/watchlist/page/$page/limit/$limit") - val dataFromGzip = Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } + val dataFromGzip = + Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } call.respond(episodeRepository.getByPageWithList(dataFromGzip, page, limit)) } catch (e: Exception) { printError(call, e) @@ -85,7 +86,8 @@ class EpisodeController( private fun merge(episode: Episode) { episode.platform = platformRepository.find(episode.platform!!.uuid) ?: throw Exception("Platform not found") episode.anime = animeRepository.find(episode.anime!!.uuid) ?: throw Exception("Anime not found") - episode.episodeType = episodeTypeRepository.find(episode.episodeType!!.uuid) ?: throw Exception("EpisodeType not found") + episode.episodeType = + episodeTypeRepository.find(episode.episodeType!!.uuid) ?: throw Exception("EpisodeType not found") episode.langType = langTypeRepository.find(episode.langType!!.uuid) ?: throw Exception("LangType not found") if (episode.isNullOrNotValid()) { diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt index ed05c24..a264eac 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeTypeController.kt @@ -9,7 +9,8 @@ import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -class EpisodeTypeController(private val episodeTypeRepository: EpisodeTypeRepository) : IController("/episodetypes") { +class EpisodeTypeController(private val episodeTypeRepository: EpisodeTypeRepository) : + IController("/episodetypes") { fun getRoutes(routing: Routing) { routing.route(prefix) { getAll() @@ -17,7 +18,7 @@ class EpisodeTypeController(private val episodeTypeRepository: EpisodeTypeReposi } } - override fun Route.getAll() { + fun Route.getAll() { get { println("GET $prefix") call.respond(episodeTypeRepository.getAll()) diff --git a/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt b/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt index 8273294..24cfcb4 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/GenreController.kt @@ -17,7 +17,7 @@ class GenreController(private val genreRepository: GenreRepository) : IControlle } } - override fun Route.getAll() { + fun Route.getAll() { get { println("GET $prefix") call.respond(genreRepository.getAll()) diff --git a/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt b/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt index 0170bb1..42822e3 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/LangTypeController.kt @@ -17,7 +17,7 @@ class LangTypeController(private val langTypeRepository: LangTypeRepository) : I } } - override fun Route.getAll() { + fun Route.getAll() { get { println("GET $prefix") call.respond(langTypeRepository.getAll()) diff --git a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt index 4ba9ddc..88006c7 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt @@ -5,8 +5,8 @@ import fr.ziedelth.entities.Manga import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.MangasReleaseEvent import fr.ziedelth.repositories.AnimeRepository +import fr.ziedelth.repositories.MangaRepository import fr.ziedelth.repositories.PlatformRepository -import fr.ziedelth.utils.Database import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache import fr.ziedelth.utils.RequestCache @@ -20,7 +20,8 @@ import java.util.* class MangaController( private val platformRepository: PlatformRepository, - private val animeRepository: AnimeRepository + private val animeRepository: AnimeRepository, + private val mangaRepository: MangaRepository, ) : IController("/mangas") { fun getRoutes(routing: Routing) { routing.route(prefix) { @@ -34,123 +35,62 @@ class MangaController( } private fun Route.search() { - route("/country/{country}/search") { - get("/ean/{ean}") { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val ean = call.parameters["ean"]?.toLongOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest) + get("/country/{country}/search/ean/{ean}") { + try { + val country = call.parameters["country"]!! + val ean = call.parameters["ean"]!!.toLongOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest) println("GET ${prefix}/country/$country/search/ean/$ean") - val session = Database.getSession() - - try { - val query = session.createQuery( - "FROM $entityName WHERE anime.country.tag = :tag AND ean = :ean", - entityClass - ) - query.maxResults = 1 - query.setParameter("tag", country) - query.setParameter("ean", ean) - call.respond(query.uniqueResult() ?: return@get call.respond(HttpStatusCode.NotFound)) - } catch (e: Exception) { - printError(call, e) - } finally { - session.close() - } + call.respond(mangaRepository.getByEAN(country, ean) ?: return@get call.respond(HttpStatusCode.NotFound)) + } catch (e: Exception) { + printError(call, e) } } } private fun Route.getWithPage() { get("/country/{country}/page/{page}/limit/{limit}") { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val page = call.parameters["page"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - val limit = call.parameters["limit"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - if (page < 1 || limit < 1) return@get call.respond(HttpStatusCode.BadRequest) - if (limit > 30) return@get call.respond(HttpStatusCode.BadRequest) - println("GET $prefix/country/$country/page/$page/limit/$limit") - val request = RequestCache.get(uuidRequest, country, page, limit) - - if (request == null || request.isExpired()) { - val session = Database.getSession() - - try { - val query = session.createQuery( - "FROM $entityName WHERE anime.country.tag = :tag AND ean IS NOT NULL ORDER BY releaseDate DESC, anime.name", - entityClass - ) - query.setParameter("tag", country) - query.firstResult = (limit * page) - limit - query.maxResults = limit - request?.update(query.list()) ?: RequestCache.put( - uuidRequest, - country, - page, - limit, - value = query.list() - ) - } catch (e: Exception) { - printError(call, e) - } finally { - session.close() + try { + val country = call.parameters["country"]!! + val (page, limit) = getPageAndLimit() + println("GET $prefix/country/$country/page/$page/limit/$limit") + val request = RequestCache.get(uuidRequest, country, page, limit) + + if (request == null || request.isExpired()) { + val list = mangaRepository.getByPage(country, page, limit) + request?.update(list) ?: RequestCache.put(uuidRequest, country, page, limit, value = list) } - } - call.respond(RequestCache.get(uuidRequest, country, page, limit)?.value ?: HttpStatusCode.NotFound) + call.respond(RequestCache.get(uuidRequest, country, page, limit)!!.value!!) + } catch (e: Exception) { + printError(call, e) + } } } private fun Route.getAnimeWithPage() { get("/anime/{uuid}/page/{page}/limit/{limit}") { - val animeUuid = call.parameters["uuid"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val page = call.parameters["page"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - val limit = call.parameters["limit"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - if (page < 1 || limit < 1) return@get call.respond(HttpStatusCode.BadRequest) - if (limit > 30) return@get call.respond(HttpStatusCode.BadRequest) - println("GET ${prefix}/anime/$animeUuid/page/$page/limit/$limit") - val session = Database.getSession() - try { - val query = session.createQuery( - "FROM $entityName WHERE anime.uuid = :uuid ORDER BY releaseDate DESC, anime.name", - entityClass - ) - query.setParameter("uuid", UUID.fromString(animeUuid)) - query.firstResult = (limit * page) - limit - query.maxResults = limit - call.respond(query.list() ?: HttpStatusCode.NotFound) + val animeUuid = call.parameters["uuid"]!! + val (page, limit) = getPageAndLimit() + println("GET $prefix/anime/$animeUuid/page/$page/limit/$limit") + call.respond(mangaRepository.getByPageWithAnime(UUID.fromString(animeUuid), page, limit)) } catch (e: Exception) { printError(call, e) - } finally { - session.close() } } } private fun Route.getWatchlistWithPage() { post("/watchlist/page/{page}/limit/{limit}") { - val watchlist = call.receive() - val page = call.parameters["page"]?.toInt() ?: return@post call.respond(HttpStatusCode.BadRequest) - val limit = call.parameters["limit"]?.toInt() ?: return@post call.respond(HttpStatusCode.BadRequest) - if (page < 1 || limit < 1) return@post call.respond(HttpStatusCode.BadRequest) - if (limit > 30) return@post call.respond(HttpStatusCode.BadRequest) - println("POST $prefix/watchlist/page/$page/limit/$limit") - val session = Database.getSession() - try { + val watchlist = call.receive() + val (page, limit) = getPageAndLimit() + println("POST $prefix/watchlist/page/$page/limit/$limit") val dataFromGzip = Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } - - val query = session.createQuery( - "FROM $entityName WHERE uuid IN :list ORDER BY releaseDate DESC, anime.name", - entityClass - ) - query.setParameter("list", dataFromGzip) - query.firstResult = (limit * page) - limit - query.maxResults = limit - call.respond(query.list()) + call.respond(mangaRepository.getByPageWithList(dataFromGzip, page, limit)) } catch (e: Exception) { printError(call, e) - } finally { - session.close() } } } @@ -171,17 +111,17 @@ class MangaController( println("POST $prefix/multiple") try { - val mangas = call.receive>().filter { !isExists("hash", it.hash!!) } + val mangas = call.receive>().filter { !mangaRepository.exists("hash", it.hash!!) } val savedMangas = mutableListOf() mangas.forEach { merge(it) - val savedManga = justSave(it) + val savedManga = mangaRepository.save(it) savedMangas.add(savedManga) ImageCache.cachingNetworkImage(savedManga.uuid, savedManga.cover!!) } - call.respond(HttpStatusCode.Created, mangas) + call.respond(HttpStatusCode.Created, savedMangas) PluginManager.callEvent(MangasReleaseEvent(savedMangas)) } catch (e: Exception) { printError(call, e) diff --git a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt index 11d9711..23afbd4 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt @@ -4,8 +4,8 @@ import fr.ziedelth.entities.News import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.NewsReleaseEvent import fr.ziedelth.repositories.CountryRepository +import fr.ziedelth.repositories.NewsRepository import fr.ziedelth.repositories.PlatformRepository -import fr.ziedelth.utils.Database import fr.ziedelth.utils.RequestCache import fr.ziedelth.utils.plugins.PluginManager import io.ktor.http.* @@ -16,7 +16,8 @@ import io.ktor.server.routing.* class NewsController( private val countryRepository: CountryRepository, - private val platformRepository: PlatformRepository + private val platformRepository: PlatformRepository, + private val newsRepository: NewsRepository, ) : IController("/news") { fun getRoutes(routing: Routing) { routing.route(prefix) { @@ -27,40 +28,21 @@ class NewsController( private fun Route.getWithPage() { get("/country/{country}/page/{page}/limit/{limit}") { - val country = call.parameters["country"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val page = call.parameters["page"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - val limit = call.parameters["limit"]?.toInt() ?: return@get call.respond(HttpStatusCode.BadRequest) - if (page < 1 || limit < 1) return@get call.respond(HttpStatusCode.BadRequest) - if (limit > 30) return@get call.respond(HttpStatusCode.BadRequest) - println("GET $prefix/country/$country/page/$page/limit/$limit") - val request = RequestCache.get(uuidRequest, country, page, limit) - - if (request == null || request.isExpired()) { - val session = Database.getSession() + try { + val country = call.parameters["country"]!! + val (page, limit) = getPageAndLimit() + println("GET $prefix/country/$country/page/$page/limit/$limit") + val request = RequestCache.get(uuidRequest, country, page, limit) - try { - val query = session.createQuery( - "FROM News WHERE country.tag = :tag ORDER BY releaseDate DESC", - News::class.java - ) - query.setParameter("tag", country) - query.firstResult = (limit * page) - limit - query.maxResults = limit - request?.update(query.list()) ?: RequestCache.put( - uuidRequest, - country, - page, - limit, - value = query.list() - ) - } catch (e: Exception) { - printError(call, e) - } finally { - session.close() + if (request == null || request.isExpired()) { + val list = newsRepository.getByPage(country, page, limit) + request?.update(list) ?: RequestCache.put(uuidRequest, country, page, limit, value = list) } - } - call.respond(RequestCache.get(uuidRequest, country, page, limit)?.value ?: HttpStatusCode.NotFound) + call.respond(RequestCache.get(uuidRequest, country, page, limit)!!.value!!) + } catch (e: Exception) { + printError(call, e) + } } } @@ -78,15 +60,15 @@ class NewsController( println("POST $prefix/multiple") try { - val news = call.receive>().filter { !isExists("hash", it.hash!!) } + val news = call.receive>().filter { !newsRepository.exists("hash", it.hash!!) } val savedNews = mutableListOf() news.forEach { merge(it) - savedNews.add(justSave(it)) + savedNews.add(newsRepository.save(it)) } - call.respond(HttpStatusCode.Created, news) + call.respond(HttpStatusCode.Created, savedNews) PluginManager.callEvent(NewsReleaseEvent(savedNews)) } catch (e: Exception) { printError(call, e) diff --git a/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt b/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt index dd57ba1..c5a51c9 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/PlatformController.kt @@ -18,7 +18,7 @@ class PlatformController(private val platformRepository: PlatformRepository) : I } } - override fun Route.getAll() { + fun Route.getAll() { get { println("GET $prefix") call.respond(platformRepository.getAll()) diff --git a/src/main/kotlin/fr/ziedelth/entities/Manga.kt b/src/main/kotlin/fr/ziedelth/entities/Manga.kt index 1ffba18..13b4c69 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Manga.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Manga.kt @@ -47,6 +47,7 @@ class Manga( )) || url.isNullOrBlank() || cover.isNullOrBlank() || editor.isNullOrBlank() fun copy(anime: Anime? = this.anime) = Manga( + uuid = uuid, platform = platform, anime = anime, hash = hash, diff --git a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt index 2e1df27..09e083d 100644 --- a/src/main/kotlin/fr/ziedelth/plugins/Routing.kt +++ b/src/main/kotlin/fr/ziedelth/plugins/Routing.kt @@ -16,6 +16,7 @@ fun Application.configureRouting() { val langTypeRepository = LangTypeRepository() val episodeRepository = EpisodeRepository() val mangaRepository = MangaRepository() + val newsRepository = NewsRepository() CountryController(countryRepository).getRoutes(this) PlatformController(platformRepository).getRoutes(this) @@ -24,8 +25,15 @@ fun Application.configureRouting() { AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) EpisodeTypeController(episodeTypeRepository).getRoutes(this) LangTypeController(langTypeRepository).getRoutes(this) - EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository, langTypeRepository, episodeRepository).getRoutes(this) - NewsController(countryRepository, platformRepository).getRoutes(this) - MangaController(platformRepository, animeRepository).getRoutes(this) + EpisodeController( + platformRepository, + animeRepository, + simulcastRepository, + episodeTypeRepository, + langTypeRepository, + episodeRepository + ).getRoutes(this) + NewsController(countryRepository, platformRepository, newsRepository).getRoutes(this) + MangaController(platformRepository, animeRepository, mangaRepository).getRoutes(this) } } diff --git a/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt index ea2b99a..f8e86ea 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/AbstractRepository.kt @@ -119,4 +119,15 @@ open class AbstractRepository(val getSession: () -> Session = { Database.getS session.close() } } + + fun getByPage(page: Int, limit: Int, queryRaw: String, vararg pair: Pair): List { + val session = getSession.invoke() + val query = session.createQuery(queryRaw, entityClass) + pair.forEach { query.setParameter(it.first, it.second) } + query.firstResult = (limit * page) - limit + query.maxResults = limit + val list = query.list() + session.close() + return list + } } diff --git a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt index eca5381..24804de 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt @@ -48,29 +48,22 @@ class AnimeRepository(session: () -> Session = { Database.getSession() }) : Abst } fun getByPage(tag: String, simulcast: UUID, page: Int, limit: Int): List { - val session = getSession.invoke() - val query = session.createQuery( + return super.getByPage( + page, + limit, "FROM Anime a JOIN a.simulcasts s WHERE a.country.tag = :tag AND s.uuid = :simulcast ORDER BY a.name", - Anime::class.java + "tag" to tag, + "simulcast" to simulcast ) - query.setParameter("tag", tag) - query.setParameter("simulcast", simulcast) - query.firstResult = (limit * page) - limit - query.maxResults = limit - val list = query.list() - session.close() - return list } fun findAllByPage(uuids: List, page: Int, limit: Int): List { - val session = getSession.invoke() - val query = session.createQuery("FROM Anime WHERE uuid IN :list ORDER BY name", Anime::class.java) - query.setParameter("list", uuids) - query.firstResult = (limit * page) - limit - query.maxResults = limit - val list = query.list() - session.close() - return list + return super.getByPage( + page, + limit, + "FROM Anime WHERE uuid IN :list ORDER BY name", + "list" to uuids + ) } fun getDiary(tag: String, day: Int): List { diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt index 0d399e1..d7a11b7 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt @@ -3,48 +3,33 @@ package fr.ziedelth.repositories import fr.ziedelth.entities.Episode import fr.ziedelth.utils.Database import org.hibernate.Session -import java.util.UUID +import java.util.* class EpisodeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { fun getByPage(tag: String, page: Int, limit: Int): List { - val session = getSession.invoke() - val query = session.createQuery( + return super.getByPage( + page, + limit, "FROM Episode WHERE anime.country.tag = :tag ORDER BY releaseDate DESC, anime.name, season DESC, number DESC, episodeType.name, langType.name", - Episode::class.java + "tag" to tag ) - query.setParameter("tag", tag) - query.firstResult = (limit * page) - limit - query.maxResults = limit - val list = query.list() - session.close() - return list } fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List { - val session = getSession.invoke() - val query = session.createQuery( + return super.getByPage( + page, + limit, "FROM Episode WHERE anime.uuid = :uuid ORDER BY season DESC, number DESC, episodeType.name, langType.name", - Episode::class.java + "uuid" to uuid ) - query.setParameter("uuid", uuid) - query.firstResult = (limit * page) - limit - query.maxResults = limit - val list = query.list() - session.close() - return list } fun getByPageWithList(list: List, page: Int, limit: Int): List { - val session = getSession.invoke() - val query = session.createQuery( + return super.getByPage( + page, + limit, "FROM Episode WHERE anime.uuid IN :list ORDER BY releaseDate DESC, anime.name, season DESC, number DESC, episodeType.name, langType.name", - Episode::class.java + "list" to list ) - query.setParameter("list", list) - query.firstResult = (limit * page) - limit - query.maxResults = limit - val result = query.list() - session.close() - return result } } \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt index 5f08661..4c2536b 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeTypeRepository.kt @@ -4,4 +4,5 @@ import fr.ziedelth.entities.EpisodeType import fr.ziedelth.utils.Database import org.hibernate.Session -class EpisodeTypeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file +class EpisodeTypeRepository(session: () -> Session = { Database.getSession() }) : + AbstractRepository(session) \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt index b8e37f6..475f68b 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt @@ -3,5 +3,44 @@ package fr.ziedelth.repositories import fr.ziedelth.entities.Manga import fr.ziedelth.utils.Database import org.hibernate.Session +import java.util.* -class MangaRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) \ No newline at end of file +class MangaRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { + fun getByEAN(tag: String, ean: Long): Manga? { + val session = getSession.invoke() + val query = session.createQuery("FROM Manga WHERE anime.country.tag = :tag AND ean = :ean", Manga::class.java) + query.maxResults = 1 + query.setParameter("tag", tag) + query.setParameter("ean", ean) + val result = query.uniqueResult() + session.close() + return result + } + + fun getByPage(tag: String, page: Int, limit: Int): List { + return super.getByPage( + page, + limit, + "FROM Manga WHERE anime.country.tag = :tag AND ean IS NOT NULL ORDER BY releaseDate DESC, anime.name", + "tag" to tag, + ) + } + + fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List { + return super.getByPage( + page, + limit, + "FROM Manga WHERE anime.uuid = :uuid ORDER BY releaseDate DESC, anime.name", + "uuid" to uuid, + ) + } + + fun getByPageWithList(list: List, page: Int, limit: Int): List { + return super.getByPage( + page, + limit, + "FROM Manga WHERE uuid IN :list ORDER BY releaseDate DESC, anime.name", + "list" to list + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/NewsRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/NewsRepository.kt new file mode 100644 index 0000000..abf40fb --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/NewsRepository.kt @@ -0,0 +1,16 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.entities.News +import fr.ziedelth.utils.Database +import org.hibernate.Session + +class NewsRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { + fun getByPage(tag: String, page: Int, limit: Int): List { + return super.getByPage( + page, + limit, + "FROM News WHERE country.tag = :tag ORDER BY releaseDate DESC", + "tag" to tag, + ) + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt b/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt index 7db1b3e..4248ee9 100644 --- a/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt +++ b/src/test/kotlin/fr/ziedelth/AbstractAPITest.kt @@ -92,7 +92,46 @@ internal abstract class AbstractAPITest { ) } episodeRepository.saveAll(episodes) + + val mangas = (1..10).map { manga -> + val platform = platforms.random() + + Manga( + platform = platform, + anime = it, + hash = "MA-$manga-${platform.name}-${Math.random()}", + url = "hello", + cover = "hello", + editor = "MyEditor $manga", + ref = "MyRef $manga", + ean = Math.random().toLong(), + age = 18, + price = 10.0, + ) + } + mangaRepository.saveAll(mangas) } + + newsRepository.saveAll( + listOf( + News( + country = countries.first(), + platform = platforms.first(), + title = "News 1", + description = "Content 1", + hash = "hello", + url = "hello", + ), + News( + country = countries.first(), + platform = platforms.first(), + title = "News 2", + description = "Content 2", + hash = "hello2", + url = "hello", + ), + ) + ) } @AfterEach diff --git a/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt index f7cb1a9..20dfe7f 100644 --- a/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt +++ b/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt @@ -166,30 +166,32 @@ internal class EpisodeControllerTest : AbstractAPITest() { val response = client.post("/episodes/multiple") { contentType(ContentType.Application.Json) - setBody(listOf( - Episode( - anime = anime, - platform = platform, - episodeType = episodeType, - langType = langType, - number = 1, - season = 1, - url = "https://www.google.com", - image = "https://www.google.com", - hash = "hash", - ), - Episode( - anime = anime, - platform = platform, - episodeType = episodeType, - langType = langType, - number = 2, - season = 1, - url = "https://www.google.com", - image = "https://www.google.com", - hash = "azertyuiop", + setBody( + listOf( + Episode( + anime = anime, + platform = platform, + episodeType = episodeType, + langType = langType, + number = 1, + season = 1, + url = "https://www.google.com", + image = "https://www.google.com", + hash = "hash", + ), + Episode( + anime = anime, + platform = platform, + episodeType = episodeType, + langType = langType, + number = 2, + season = 1, + url = "https://www.google.com", + image = "https://www.google.com", + hash = "azertyuiop", + ) ) - )) + ) } expect(HttpStatusCode.Created) { response.status } diff --git a/src/test/kotlin/fr/ziedelth/controllers/MangaControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/MangaControllerTest.kt new file mode 100644 index 0000000..268ffd5 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/MangaControllerTest.kt @@ -0,0 +1,306 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.* +import fr.ziedelth.plugins.* +import fr.ziedelth.utils.Encoder +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class MangaControllerTest : AbstractAPITest() { + @Test + fun searchByEAN() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + val ean = mangaRepository.getAll().first().ean + + val responseNotCached = client.get("/mangas/country/${country.tag}/search/ean/$ean") + val json = Gson().fromJson(responseNotCached.bodyAsText(), Manga::class.java) + + expect(HttpStatusCode.OK) { responseNotCached.status } + checkNotNull(json.uuid) + } + } + + @Test + fun getByPage() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + + // NOT CACHED + + val responseNotCached = + client.get("/mangas/country/${country.tag}/page/1/limit/12") + val jsonNotCached = Gson().fromJson(responseNotCached.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { responseNotCached.status } + expect(12) { jsonNotCached.size } + + // CACHED + + val responseCached = + client.get("/mangas/country/${country.tag}/page/1/limit/12") + val jsonCached = Gson().fromJson(responseCached.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { responseCached.status } + expect(12) { jsonCached.size } + } + } + + @Test + fun getByPageError() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + + // ERROR + + val responseError = + client.get("/mangas/country/${country.tag}/page/ae/limit/12") + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun getByPageWithAnime() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val anime = animeRepository.getAll().first() + + val response = + client.get("/mangas/anime/${anime.uuid}/page/1/limit/12") + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { response.status } + expect(10) { json.size } + } + } + + @Test + fun getByPageWithAnimeError() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val anime = animeRepository.getAll().first() + + // ERROR + + val responseError = + client.get("/mangas/anime/${anime.uuid}/page/ae/limit/12") + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun getWatchlistByPage() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val manga = mangaRepository.getAll().first() + val bodyRequest = Encoder.toGzip("[\"${manga.uuid}\"]") + + val response = client.post("/mangas/watchlist/page/1/limit/12") { + setBody(bodyRequest) + } + + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { response.status } + expect(1) { json.size } + } + } + + @Test + fun getWatchlistByPageError() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val manga = mangaRepository.getAll().first() + val bodyRequest = Encoder.toGzip("[\"${manga.uuid}\"]") + + val responseError = client.post("/mangas/watchlist/page/ae/limit/12") { + setBody(bodyRequest) + } + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun save() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val platform = platformRepository.getAll().first() + val anime = animeRepository.getAll().first() + + val response = client.post("/mangas/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + Manga( + platform = platform, + anime = anime, + hash = "hash", + url = "test", + cover = "test", + editor = "test", + ref = "test", + ean = Math.random().toLong(), + age = 12, + price = 7.5, + ), + Manga( + platform = platform, + anime = anime, + hash = "hash2", + url = "test2", + cover = "test2", + editor = "test2", + ref = "test2", + ean = Math.random().toLong(), + age = 12, + price = 7.5, + ) + ) + ) + } + + expect(HttpStatusCode.Created) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(2) { json.size } + } + } + + @Test + fun saveError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + expect(HttpStatusCode.InternalServerError) { + client.post("/mangas/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + Manga( + platform = Platform(), + anime = Anime(), + hash = "hash2", + url = "test2", + cover = "test2", + editor = "test2", + ref = "test2", + ean = Math.random().toLong(), + age = 12, + price = 7.5, + ), + ) + ) + }.status + } + + val platform = platformRepository.getAll().first() + + expect(HttpStatusCode.InternalServerError) { + client.post("/mangas/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + Manga( + platform = platform, + anime = Anime(), + hash = "hash2", + url = "test2", + cover = "test2", + editor = "test2", + ref = "test2", + ean = Math.random().toLong(), + age = 12, + price = 7.5, + ), + ) + ) + }.status + } + + val anime = animeRepository.getAll().first() + + expect(HttpStatusCode.InternalServerError) { + client.post("/episodes/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + Manga( + platform = platform, + anime = anime, + url = "test2", + cover = "test2", + editor = "test2", + ref = "test2", + ean = Math.random().toLong(), + age = 12, + price = 7.5, + ), + ) + ) + }.status + } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/controllers/NewsControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/NewsControllerTest.kt new file mode 100644 index 0000000..5934290 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/controllers/NewsControllerTest.kt @@ -0,0 +1,187 @@ +package fr.ziedelth.controllers + +import com.google.gson.Gson +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.entities.* +import fr.ziedelth.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.gson.* +import io.ktor.server.testing.* +import io.ktor.util.* +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.expect + +internal class NewsControllerTest : AbstractAPITest() { + @Test + fun getByPage() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + + // NOT CACHED + + val responseNotCached = + client.get("/news/country/${country.tag}/page/1/limit/12") + val jsonNotCached = Gson().fromJson(responseNotCached.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { responseNotCached.status } + expect(2) { jsonNotCached.size } + + // CACHED + + val responseCached = + client.get("/news/country/${country.tag}/page/1/limit/12") + val jsonCached = Gson().fromJson(responseCached.bodyAsText(), Array::class.java) + + expect(HttpStatusCode.OK) { responseCached.status } + expect(2) { jsonCached.size } + } + } + + @Test + fun getByPageError() { + testApplication { + application { + configureHTTP() + configureRoutingTest() + } + + val country = countryRepository.getAll().first() + + // ERROR + + val responseError = + client.get("/news/country/${country.tag}/page/ae/limit/12") + + expect(HttpStatusCode.InternalServerError) { responseError.status } + } + } + + @Test + fun save() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + val platform = platformRepository.getAll().first() + val country = countryRepository.getAll().first() + + val response = client.post("/news/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + News( + country = country, + platform = platform, + title = "News 3", + description = "Content 3", + hash = "hello3", + url = "hello", + ), + News( + country = country, + platform = platform, + title = "News 4", + description = "Content 4", + hash = "hello4", + url = "hello", + ), + ) + ) + } + + expect(HttpStatusCode.Created) { response.status } + val json = Gson().fromJson(response.bodyAsText(), Array::class.java) + expect(2) { json.size } + } + } + + @Test + fun saveError() { + testApplication { + val client = createClient { + install(ContentNegotiation) { + gson() + } + } + + application { + configureHTTP() + configureRoutingTest() + } + + expect(HttpStatusCode.InternalServerError) { + client.post("/news/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + News( + country = Country(), + platform = Platform(), + title = "News 3", + description = "Content 3", + hash = "hello3", + url = "hello", + ), + ) + ) + }.status + } + + val platform = platformRepository.getAll().first() + + expect(HttpStatusCode.InternalServerError) { + client.post("/news/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + News( + country = Country(), + platform = platform, + title = "News 3", + description = "Content 3", + hash = "hello3", + url = "hello", + ), + ) + ) + }.status + } + + val country = countryRepository.getAll().first() + + expect(HttpStatusCode.InternalServerError) { + client.post("/news/multiple") { + contentType(ContentType.Application.Json) + setBody( + listOf( + News( + country = country, + platform = platform, + title = "News 3", + description = "Content 3", + url = "hello", + ), + ) + ) + }.status + } + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt index f8df3f3..879aac3 100644 --- a/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt +++ b/src/test/kotlin/fr/ziedelth/plugins/RoutingTest.kt @@ -15,6 +15,7 @@ val episodeTypeRepository = EpisodeTypeRepository { DatabaseTest.getSession() } val langTypeRepository = LangTypeRepository { DatabaseTest.getSession() } val episodeRepository = EpisodeRepository { DatabaseTest.getSession() } val mangaRepository = MangaRepository { DatabaseTest.getSession() } +val newsRepository = NewsRepository { DatabaseTest.getSession() } fun Application.configureRoutingTest() { routing { @@ -25,8 +26,15 @@ fun Application.configureRoutingTest() { AnimeController(countryRepository, animeRepository, episodeRepository, mangaRepository).getRoutes(this) EpisodeTypeController(episodeTypeRepository).getRoutes(this) LangTypeController(langTypeRepository).getRoutes(this) - EpisodeController(platformRepository, animeRepository, simulcastRepository, episodeTypeRepository, langTypeRepository, episodeRepository).getRoutes(this) - NewsController(countryRepository, platformRepository).getRoutes(this) - MangaController(platformRepository, animeRepository).getRoutes(this) + EpisodeController( + platformRepository, + animeRepository, + simulcastRepository, + episodeTypeRepository, + langTypeRepository, + episodeRepository + ).getRoutes(this) + NewsController(countryRepository, platformRepository, newsRepository).getRoutes(this) + MangaController(platformRepository, animeRepository, mangaRepository).getRoutes(this) } } \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/repositories/MangaRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/MangaRepositoryTest.kt new file mode 100644 index 0000000..c86cf0c --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/MangaRepositoryTest.kt @@ -0,0 +1,37 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.plugins.animeRepository +import fr.ziedelth.plugins.mangaRepository +import org.junit.jupiter.api.Test +import kotlin.test.expect + +internal class MangaRepositoryTest : AbstractAPITest() { + @Test + fun getByPage() { + val page1 = mangaRepository.getByPage("fr", 1, 2) + expect(2) { page1.size } + val page2 = mangaRepository.getByPage("fr", 2, 2) + expect(2) { page2.size } + } + + @Test + fun getByPageWithAnime() { + val anime = animeRepository.getAll().first() + + val page1 = mangaRepository.getByPageWithAnime(anime.uuid, 1, 2) + expect(2) { page1.size } + val page2 = mangaRepository.getByPageWithAnime(anime.uuid, 2, 2) + expect(2) { page2.size } + } + + @Test + fun getByPageWithList() { + val mangas = mangaRepository.getAll().take(3).map { it.uuid } + + val page1 = mangaRepository.getByPageWithList(mangas, 1, 2) + expect(2) { page1.size } + val page2 = mangaRepository.getByPageWithList(mangas, 2, 2) + expect(1) { page2.size } + } +} diff --git a/src/test/kotlin/fr/ziedelth/repositories/NewsRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/NewsRepositoryTest.kt new file mode 100644 index 0000000..5abb952 --- /dev/null +++ b/src/test/kotlin/fr/ziedelth/repositories/NewsRepositoryTest.kt @@ -0,0 +1,16 @@ +package fr.ziedelth.repositories + +import fr.ziedelth.AbstractAPITest +import fr.ziedelth.plugins.newsRepository +import org.junit.jupiter.api.Test +import kotlin.test.expect + +internal class NewsRepositoryTest : AbstractAPITest() { + @Test + fun getByPage() { + val page1 = newsRepository.getByPage("fr", 1, 2) + expect(2) { page1.size } + val page2 = newsRepository.getByPage("fr", 2, 2) + expect(0) { page2.size } + } +} From e2b41797dcb7118ce8030131554eb564d52ef9a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 10:13:36 +0000 Subject: [PATCH 30/35] Bump logback-classic from 1.4.4 to 1.4.5 Bumps [logback-classic](https://github.com/qos-ch/logback) from 1.4.4 to 1.4.5. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.4...v_1.4.5) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4242c24..931663d 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ official 1.7.20 11 - 1.4.4 + 1.4.5 UTF-8 true fr.ziedelth.ApplicationKt From 6641b61253f7f601baff5da4aa45e730d5b4295d Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 22 Nov 2022 14:25:25 +0100 Subject: [PATCH 31/35] More tests --- .../controllers/AbstractController.kt | 57 +++++++++++++++++- .../ziedelth/controllers/AnimeController.kt | 20 +------ .../ziedelth/controllers/EpisodeController.kt | 58 +----------------- .../ziedelth/controllers/MangaController.kt | 59 +------------------ .../fr/ziedelth/controllers/NewsController.kt | 23 +------- .../ziedelth/repositories/AnimeRepository.kt | 15 ++++- .../repositories/EpisodeRepository.kt | 9 +-- .../ziedelth/repositories/IPageRepository.kt | 9 +++ .../ziedelth/repositories/MangaRepository.kt | 9 +-- .../ziedelth/repositories/NewsRepository.kt | 14 ++++- .../controllers/EpisodeControllerTest.kt | 9 +-- .../repositories/AnimeRepositoryTest.kt | 4 +- 12 files changed, 112 insertions(+), 174 deletions(-) create mode 100644 src/main/kotlin/fr/ziedelth/repositories/IPageRepository.kt diff --git a/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt b/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt index f127648..68b936d 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt @@ -1,8 +1,13 @@ package fr.ziedelth.controllers +import com.google.gson.Gson +import fr.ziedelth.repositories.IPageRepository +import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache +import fr.ziedelth.utils.RequestCache import io.ktor.http.* import io.ktor.server.application.* +import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.util.pipeline.* @@ -14,9 +19,7 @@ const val UNKNOWN_MESSAGE_ERROR = "Unknown error" const val MISSING_PARAMETERS_MESSAGE_ERROR = "Missing parameters" open class IController(val prefix: String) { - private val entityClass: Class = - (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class - val entityName: String = entityClass.simpleName + val entityName: String = ((javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<*>).simpleName val uuidRequest: UUID = UUID.randomUUID() fun PipelineContext.getPageAndLimit(): Pair { @@ -39,6 +42,54 @@ open class IController(val prefix: String) { call.respond(HttpStatusCode.InternalServerError, e.message ?: UNKNOWN_MESSAGE_ERROR) } + protected fun Route.getWithPage(iPageRepository: IPageRepository) { + get("/country/{country}/page/{page}/limit/{limit}") { + try { + val country = call.parameters["country"]!! + val (page, limit) = getPageAndLimit() + println("GET $prefix/country/$country/page/$page/limit/$limit") + val request = RequestCache.get(uuidRequest, country, page, limit) + + if (request == null || request.isExpired()) { + val list = iPageRepository.getByPage(country, page, limit) + request?.update(list) ?: RequestCache.put(uuidRequest, country, page, limit, value = list) + } + + call.respond(RequestCache.get(uuidRequest, country, page, limit)!!.value!!) + } catch (e: Exception) { + printError(call, e) + } + } + } + + protected fun Route.getAnimeWithPage(iPageRepository: IPageRepository) { + get("/anime/{uuid}/page/{page}/limit/{limit}") { + try { + val animeUuid = call.parameters["uuid"]!! + val (page, limit) = getPageAndLimit() + println("GET $prefix/anime/$animeUuid/page/$page/limit/$limit") + call.respond(iPageRepository.getByPageWithAnime(UUID.fromString(animeUuid), page, limit)) + } catch (e: Exception) { + printError(call, e) + } + } + } + + protected fun Route.getWatchlistWithPage(iPageRepository: IPageRepository) { + post("/watchlist/page/{page}/limit/{limit}") { + try { + val watchlist = call.receive() + val (page, limit) = getPageAndLimit() + println("POST $prefix/watchlist/page/$page/limit/$limit") + val dataFromGzip = + Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } + call.respond(iPageRepository.getByPageWithList(dataFromGzip, page, limit)) + } catch (e: Exception) { + printError(call, e) + } + } + } + fun Route.getAttachment() { get("/attachment/{uuid}") { val string = call.parameters["uuid"]!! diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index 7f8c33d..31de997 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -1,13 +1,11 @@ package fr.ziedelth.controllers -import com.google.gson.Gson import fr.ziedelth.entities.Anime import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.repositories.AnimeRepository import fr.ziedelth.repositories.CountryRepository import fr.ziedelth.repositories.EpisodeRepository import fr.ziedelth.repositories.MangaRepository -import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache import fr.ziedelth.utils.RequestCache import io.ktor.http.* @@ -15,7 +13,6 @@ import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import io.ktor.util.pipeline.* import java.util.* class AnimeController( @@ -29,7 +26,7 @@ class AnimeController( routing.route(prefix) { search() getByPage() - getWatchlistWithPage() + getWatchlistWithPage(animeRepository) getAttachment() create() merge() @@ -76,21 +73,6 @@ class AnimeController( } } - private fun Route.getWatchlistWithPage() { - post("/watchlist/page/{page}/limit/{limit}") { - try { - val watchlist = call.receive() - val (page, limit) = getPageAndLimit() - println("POST $prefix/watchlist/page/$page/limit/$limit") - val dataFromGzip = - Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } - call.respond(animeRepository.findAllByPage(dataFromGzip, page, limit)) - } catch (e: Exception) { - printError(call, e) - } - } - } - private fun Route.create() { post { println("POST $prefix") diff --git a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt index c3b9de8..50fde26 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/EpisodeController.kt @@ -1,21 +1,17 @@ package fr.ziedelth.controllers -import com.google.gson.Gson import fr.ziedelth.entities.Episode import fr.ziedelth.entities.Simulcast import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.EpisodesReleaseEvent import fr.ziedelth.repositories.* -import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache -import fr.ziedelth.utils.RequestCache import fr.ziedelth.utils.plugins.PluginManager import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import java.util.* class EpisodeController( private val platformRepository: PlatformRepository, @@ -27,62 +23,14 @@ class EpisodeController( ) : IController("/episodes") { fun getRoutes(routing: Routing) { routing.route(prefix) { - getWithPage() - getAnimeWithPage() - getWatchlistWithPage() + getWithPage(episodeRepository) + getAnimeWithPage(episodeRepository) + getWatchlistWithPage(episodeRepository) getAttachment() create() } } - private fun Route.getWithPage() { - get("/country/{country}/page/{page}/limit/{limit}") { - try { - val country = call.parameters["country"]!! - val (page, limit) = getPageAndLimit() - println("GET $prefix/country/$country/page/$page/limit/$limit") - val request = RequestCache.get(uuidRequest, country, page, limit) - - if (request == null || request.isExpired()) { - val list = episodeRepository.getByPage(country, page, limit) - request?.update(list) ?: RequestCache.put(uuidRequest, country, page, limit, value = list) - } - - call.respond(RequestCache.get(uuidRequest, country, page, limit)!!.value!!) - } catch (e: Exception) { - printError(call, e) - } - } - } - - private fun Route.getAnimeWithPage() { - get("/anime/{uuid}/page/{page}/limit/{limit}") { - try { - val animeUuid = call.parameters["uuid"]!! - val (page, limit) = getPageAndLimit() - println("GET $prefix/anime/$animeUuid/page/$page/limit/$limit") - call.respond(episodeRepository.getByPageWithAnime(UUID.fromString(animeUuid), page, limit)) - } catch (e: Exception) { - printError(call, e) - } - } - } - - private fun Route.getWatchlistWithPage() { - post("/watchlist/page/{page}/limit/{limit}") { - try { - val watchlist = call.receive() - val (page, limit) = getPageAndLimit() - println("POST $prefix/watchlist/page/$page/limit/$limit") - val dataFromGzip = - Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } - call.respond(episodeRepository.getByPageWithList(dataFromGzip, page, limit)) - } catch (e: Exception) { - printError(call, e) - } - } - } - private fun merge(episode: Episode) { episode.platform = platformRepository.find(episode.platform!!.uuid) ?: throw Exception("Platform not found") episode.anime = animeRepository.find(episode.anime!!.uuid) ?: throw Exception("Anime not found") diff --git a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt index 88006c7..5b0d7e2 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/MangaController.kt @@ -1,22 +1,18 @@ package fr.ziedelth.controllers -import com.google.gson.Gson import fr.ziedelth.entities.Manga import fr.ziedelth.entities.isNullOrNotValid import fr.ziedelth.events.MangasReleaseEvent import fr.ziedelth.repositories.AnimeRepository import fr.ziedelth.repositories.MangaRepository import fr.ziedelth.repositories.PlatformRepository -import fr.ziedelth.utils.Decoder import fr.ziedelth.utils.ImageCache -import fr.ziedelth.utils.RequestCache import fr.ziedelth.utils.plugins.PluginManager import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import java.util.* class MangaController( private val platformRepository: PlatformRepository, @@ -26,9 +22,9 @@ class MangaController( fun getRoutes(routing: Routing) { routing.route(prefix) { search() - getWithPage() - getAnimeWithPage() - getWatchlistWithPage() + getWithPage(mangaRepository) + getAnimeWithPage(mangaRepository) + getWatchlistWithPage(mangaRepository) getAttachment() create() } @@ -47,55 +43,6 @@ class MangaController( } } - private fun Route.getWithPage() { - get("/country/{country}/page/{page}/limit/{limit}") { - try { - val country = call.parameters["country"]!! - val (page, limit) = getPageAndLimit() - println("GET $prefix/country/$country/page/$page/limit/$limit") - val request = RequestCache.get(uuidRequest, country, page, limit) - - if (request == null || request.isExpired()) { - val list = mangaRepository.getByPage(country, page, limit) - request?.update(list) ?: RequestCache.put(uuidRequest, country, page, limit, value = list) - } - - call.respond(RequestCache.get(uuidRequest, country, page, limit)!!.value!!) - } catch (e: Exception) { - printError(call, e) - } - } - } - - private fun Route.getAnimeWithPage() { - get("/anime/{uuid}/page/{page}/limit/{limit}") { - try { - val animeUuid = call.parameters["uuid"]!! - val (page, limit) = getPageAndLimit() - println("GET $prefix/anime/$animeUuid/page/$page/limit/$limit") - call.respond(mangaRepository.getByPageWithAnime(UUID.fromString(animeUuid), page, limit)) - } catch (e: Exception) { - printError(call, e) - } - } - } - - private fun Route.getWatchlistWithPage() { - post("/watchlist/page/{page}/limit/{limit}") { - try { - val watchlist = call.receive() - val (page, limit) = getPageAndLimit() - println("POST $prefix/watchlist/page/$page/limit/$limit") - val dataFromGzip = - Gson().fromJson(Decoder.fromGzip(watchlist), Array::class.java).map { UUID.fromString(it) } - call.respond(mangaRepository.getByPageWithList(dataFromGzip, page, limit)) - } catch (e: Exception) { - printError(call, e) - } - } - } - - private fun merge(manga: Manga) { manga.platform = platformRepository.find(manga.platform!!.uuid) ?: throw Exception("Platform not found") diff --git a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt index 23afbd4..9c3f9ac 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/NewsController.kt @@ -6,7 +6,6 @@ import fr.ziedelth.events.NewsReleaseEvent import fr.ziedelth.repositories.CountryRepository import fr.ziedelth.repositories.NewsRepository import fr.ziedelth.repositories.PlatformRepository -import fr.ziedelth.utils.RequestCache import fr.ziedelth.utils.plugins.PluginManager import io.ktor.http.* import io.ktor.server.application.* @@ -21,31 +20,11 @@ class NewsController( ) : IController("/news") { fun getRoutes(routing: Routing) { routing.route(prefix) { - getWithPage() + getWithPage(newsRepository) create() } } - private fun Route.getWithPage() { - get("/country/{country}/page/{page}/limit/{limit}") { - try { - val country = call.parameters["country"]!! - val (page, limit) = getPageAndLimit() - println("GET $prefix/country/$country/page/$page/limit/$limit") - val request = RequestCache.get(uuidRequest, country, page, limit) - - if (request == null || request.isExpired()) { - val list = newsRepository.getByPage(country, page, limit) - request?.update(list) ?: RequestCache.put(uuidRequest, country, page, limit, value = list) - } - - call.respond(RequestCache.get(uuidRequest, country, page, limit)!!.value!!) - } catch (e: Exception) { - printError(call, e) - } - } - } - private fun merge(news: News) { news.platform = platformRepository.find(news.platform!!.uuid) ?: throw Exception("Platform not found") news.country = countryRepository.find(news.country!!.uuid) ?: throw Exception("Country not found") diff --git a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt index 24804de..72433f2 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/AnimeRepository.kt @@ -5,7 +5,8 @@ import fr.ziedelth.utils.Database import org.hibernate.Session import java.util.* -class AnimeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { +class AnimeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session), + IPageRepository { fun findByHash(tag: String, hash: String): UUID? { val session = getSession.invoke() val query = session.createQuery( @@ -57,12 +58,12 @@ class AnimeRepository(session: () -> Session = { Database.getSession() }) : Abst ) } - fun findAllByPage(uuids: List, page: Int, limit: Int): List { + override fun getByPageWithList(list: List, page: Int, limit: Int): List { return super.getByPage( page, limit, "FROM Anime WHERE uuid IN :list ORDER BY name", - "list" to uuids + "list" to list ) } @@ -78,4 +79,12 @@ class AnimeRepository(session: () -> Session = { Database.getSession() }) : Abst session.close() return list ?: emptyList() } + + override fun getByPage(tag: String, page: Int, limit: Int): List { + TODO("Not yet implemented") + } + + override fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt index d7a11b7..8b3b61c 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/EpisodeRepository.kt @@ -5,8 +5,9 @@ import fr.ziedelth.utils.Database import org.hibernate.Session import java.util.* -class EpisodeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { - fun getByPage(tag: String, page: Int, limit: Int): List { +class EpisodeRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session), + IPageRepository { + override fun getByPage(tag: String, page: Int, limit: Int): List { return super.getByPage( page, limit, @@ -15,7 +16,7 @@ class EpisodeRepository(session: () -> Session = { Database.getSession() }) : Ab ) } - fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List { + override fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List { return super.getByPage( page, limit, @@ -24,7 +25,7 @@ class EpisodeRepository(session: () -> Session = { Database.getSession() }) : Ab ) } - fun getByPageWithList(list: List, page: Int, limit: Int): List { + override fun getByPageWithList(list: List, page: Int, limit: Int): List { return super.getByPage( page, limit, diff --git a/src/main/kotlin/fr/ziedelth/repositories/IPageRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/IPageRepository.kt new file mode 100644 index 0000000..92b4e67 --- /dev/null +++ b/src/main/kotlin/fr/ziedelth/repositories/IPageRepository.kt @@ -0,0 +1,9 @@ +package fr.ziedelth.repositories + +import java.util.* + +interface IPageRepository { + fun getByPage(tag: String, page: Int, limit: Int): List + fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List + fun getByPageWithList(list: List, page: Int, limit: Int): List +} \ No newline at end of file diff --git a/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt index 475f68b..8e52cc2 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/MangaRepository.kt @@ -5,7 +5,8 @@ import fr.ziedelth.utils.Database import org.hibernate.Session import java.util.* -class MangaRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { +class MangaRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session), + IPageRepository { fun getByEAN(tag: String, ean: Long): Manga? { val session = getSession.invoke() val query = session.createQuery("FROM Manga WHERE anime.country.tag = :tag AND ean = :ean", Manga::class.java) @@ -17,7 +18,7 @@ class MangaRepository(session: () -> Session = { Database.getSession() }) : Abst return result } - fun getByPage(tag: String, page: Int, limit: Int): List { + override fun getByPage(tag: String, page: Int, limit: Int): List { return super.getByPage( page, limit, @@ -26,7 +27,7 @@ class MangaRepository(session: () -> Session = { Database.getSession() }) : Abst ) } - fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List { + override fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List { return super.getByPage( page, limit, @@ -35,7 +36,7 @@ class MangaRepository(session: () -> Session = { Database.getSession() }) : Abst ) } - fun getByPageWithList(list: List, page: Int, limit: Int): List { + override fun getByPageWithList(list: List, page: Int, limit: Int): List { return super.getByPage( page, limit, diff --git a/src/main/kotlin/fr/ziedelth/repositories/NewsRepository.kt b/src/main/kotlin/fr/ziedelth/repositories/NewsRepository.kt index abf40fb..55159f3 100644 --- a/src/main/kotlin/fr/ziedelth/repositories/NewsRepository.kt +++ b/src/main/kotlin/fr/ziedelth/repositories/NewsRepository.kt @@ -3,9 +3,11 @@ package fr.ziedelth.repositories import fr.ziedelth.entities.News import fr.ziedelth.utils.Database import org.hibernate.Session +import java.util.* -class NewsRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session) { - fun getByPage(tag: String, page: Int, limit: Int): List { +class NewsRepository(session: () -> Session = { Database.getSession() }) : AbstractRepository(session), + IPageRepository { + override fun getByPage(tag: String, page: Int, limit: Int): List { return super.getByPage( page, limit, @@ -13,4 +15,12 @@ class NewsRepository(session: () -> Session = { Database.getSession() }) : Abstr "tag" to tag, ) } + + override fun getByPageWithAnime(uuid: UUID, page: Int, limit: Int): List { + TODO("Not yet implemented") + } + + override fun getByPageWithList(list: List, page: Int, limit: Int): List { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt index 20dfe7f..3cce111 100644 --- a/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt +++ b/src/test/kotlin/fr/ziedelth/controllers/EpisodeControllerTest.kt @@ -59,10 +59,11 @@ internal class EpisodeControllerTest : AbstractAPITest() { // ERROR - val responseError = - client.get("/episodes/country/${country.tag}/page/ae/limit/12") - - expect(HttpStatusCode.InternalServerError) { responseError.status } + expect(HttpStatusCode.InternalServerError) { client.get("/episodes/country/${country.tag}/page/ae/limit/12").status } + expect(HttpStatusCode.InternalServerError) { client.get("/episodes/country/${country.tag}/page/1/limit/ae").status } + expect(HttpStatusCode.InternalServerError) { client.get("/episodes/country/${country.tag}/page/0/limit/12").status } + expect(HttpStatusCode.InternalServerError) { client.get("/episodes/country/${country.tag}/page/1/limit/0").status } + expect(HttpStatusCode.InternalServerError) { client.get("/episodes/country/${country.tag}/page/1/limit/31").status } } } diff --git a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt index 5239f81..4a6d15c 100644 --- a/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt +++ b/src/test/kotlin/fr/ziedelth/repositories/AnimeRepositoryTest.kt @@ -158,9 +158,9 @@ internal class AnimeRepositoryTest : AbstractAPITest() { val animes = animeRepository.getAll() val uuids = listOf(animes[0].uuid, animes[1].uuid, animes[2].uuid) - val page1 = animeRepository.findAllByPage(uuids, 1, 2) + val page1 = animeRepository.getByPageWithList(uuids, 1, 2) expect(2) { page1.size } - val page2 = animeRepository.findAllByPage(uuids, 2, 2) + val page2 = animeRepository.getByPageWithList(uuids, 2, 2) expect(1) { page2.size } } From fb0c044c9629b3e31144af9a79d4da40081b22a2 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 22 Nov 2022 14:30:24 +0100 Subject: [PATCH 32/35] Fix --- .../kotlin/fr/ziedelth/controllers/AbstractController.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt b/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt index 68b936d..155a0b3 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AbstractController.kt @@ -110,11 +110,7 @@ open class IController(val prefix: String) { return@get } - val image = ImageCache.get(uuid) ?: run { - println("Attachment $uuid not found") - return@get call.respond(HttpStatusCode.NoContent) - } - + val image = ImageCache.get(uuid)!! println("Attachment $uuid found (${image.bytes.size} bytes)") call.respondBytes(image.bytes, ContentType("image", "webp")) } From 170d2274a7eda20766173db6662d40ce3df70167 Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 22 Nov 2022 14:47:28 +0100 Subject: [PATCH 33/35] Fix --- src/main/kotlin/fr/ziedelth/entities/Simulcast.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt b/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt index f6f78ca..5bb89d6 100644 --- a/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt +++ b/src/main/kotlin/fr/ziedelth/entities/Simulcast.kt @@ -4,8 +4,6 @@ import jakarta.persistence.* import java.io.Serializable import java.util.* -fun Simulcast?.isNullOrNotValid() = this == null || this.isNotValid() - @Entity @Table(name = "simulcast", uniqueConstraints = [UniqueConstraint(columnNames = arrayOf("season", "year"))]) class Simulcast( @@ -17,8 +15,6 @@ class Simulcast( @Column(nullable = false, name = "\"year\"") val year: Int? = null ) : Serializable { - fun isNotValid(): Boolean = season.isNullOrBlank() || year == null - companion object { fun getSimulcast(year: Int, month: Int): Simulcast { val seasons = arrayOf("WINTER", "SPRING", "SUMMER", "AUTUMN") From fc1d670dd05b91fa0bef7bc1f2a8cb7d9cb6e5bf Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 22 Nov 2022 15:15:01 +0100 Subject: [PATCH 34/35] Fix bugs --- src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt | 3 ++- src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt index 31de997..00fb76c 100644 --- a/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt +++ b/src/main/kotlin/fr/ziedelth/controllers/AnimeController.kt @@ -40,7 +40,8 @@ class AnimeController( val country = call.parameters["country"]!! val hash = call.parameters["hash"]!! println("GET $prefix/country/$country/search/hash/$hash") - call.respond(mapOf("uuid" to animeRepository.findByHash(country, hash))) + val anime = animeRepository.findByHash(country, hash) + call.respond(if (anime != null) mapOf("uuid" to anime) else HttpStatusCode.NotFound) } get("/name/{name}") { diff --git a/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt index 5633af9..e8d1306 100644 --- a/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt +++ b/src/test/kotlin/fr/ziedelth/controllers/AnimeControllerTest.kt @@ -33,6 +33,8 @@ internal class AnimeControllerTest : AbstractAPITest() { expect(HttpStatusCode.OK) { response.status } checkNotNull(uuid) + + expect(HttpStatusCode.NotFound) { client.get("/animes/country/fr/search/hash/azertyuiop").status } } } From 6d15251fe652b88a76b7bc9600a979c4c9cc1e1e Mon Sep 17 00:00:00 2001 From: Ziedelth Date: Tue, 22 Nov 2022 15:21:35 +0100 Subject: [PATCH 35/35] Remove sonar on pull requests --- .github/workflows/develop.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index a11b7aa..b820ab4 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -3,7 +3,6 @@ on: push: branches-ignore: - stable - pull_request: jobs: build: