From fef8bee71c3ae264a244249dd435f0e4d8f1d3bd Mon Sep 17 00:00:00 2001 From: ccornu <ccornu@takima.fr> Date: Fri, 7 Feb 2025 18:20:45 +0100 Subject: [PATCH] feat: add all required endpoints --- README.md | 6 +-- build.gradle.kts | 2 + gradle.properties | 1 + src/main/kotlin/player/PlayerInfoDTO.kt | 7 ++++ src/main/kotlin/player/PlayerRepository.kt | 21 +++++++++-- src/main/kotlin/player/PlayerRoute.kt | 41 +++++++++++++++------ src/main/kotlin/player/PlayerService.kt | 8 +++- src/main/kotlin/player/PlayerServiceImpl.kt | 30 ++++++++++++++- 8 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 src/main/kotlin/player/PlayerInfoDTO.kt diff --git a/README.md b/README.md index dcd8dbf..a656b2c 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,11 @@ docker compose up -d - [x] créer le repo et le connecter à la BD - [x] tester unitairement le service - [ ] tester l'intégration complète - - [ ] endpoint fonctionnel pour l'ajout d'un avec test + - [x] endpoint fonctionnel pour l'ajout d'un joueur avec test - [ ] tests d'intégration - [ ] tests unitaires -- [ ] tous les endpoints autres -- gestion de la sécurité +- [x] tous les endpoints demandés +- [ ] gestion de la sécurité ## Going further diff --git a/build.gradle.kts b/build.gradle.kts index ade3b6f..29241d0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,6 +4,7 @@ val logback_version: String by project val dynamo_version: String by project val dynamo_kt_version: String by project val mockk_version: String by project +val kotlin_reactive_version: String by project plugins { @@ -46,6 +47,7 @@ dependencies { implementation("software.amazon.awssdk:dynamodb-enhanced:$dynamo_version") implementation("software.amazon.awssdk:dynamodb:$dynamo_version") implementation("dev.andrewohara:dynamokt:$dynamo_kt_version") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactive:$kotlin_reactive_version") // Tests testImplementation("io.ktor:ktor-server-test-host") diff --git a/gradle.properties b/gradle.properties index 4bf19e4..89aec6c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,3 +6,4 @@ dynamo_kt_version=1.0.0 ktor_version=2.3.13 logback_version=1.4.14 mockk_version=1.10.0 +kotlin_reactive_version=1.9.0 diff --git a/src/main/kotlin/player/PlayerInfoDTO.kt b/src/main/kotlin/player/PlayerInfoDTO.kt new file mode 100644 index 0000000..c74c977 --- /dev/null +++ b/src/main/kotlin/player/PlayerInfoDTO.kt @@ -0,0 +1,7 @@ +package betclic.test.player + +class PlayerInfoDTO( + val pseudo: String, + val pointsNumber: Int, + val ranking: Int, +) \ No newline at end of file diff --git a/src/main/kotlin/player/PlayerRepository.kt b/src/main/kotlin/player/PlayerRepository.kt index c85d2a0..3a15fd9 100644 --- a/src/main/kotlin/player/PlayerRepository.kt +++ b/src/main/kotlin/player/PlayerRepository.kt @@ -4,6 +4,7 @@ import dev.andrewohara.dynamokt.DataClassTableSchema import io.ktor.server.application.* import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.future.await +import kotlinx.coroutines.reactive.asFlow import org.slf4j.LoggerFactory import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient import software.amazon.awssdk.enhanced.dynamodb.Key @@ -24,10 +25,24 @@ class PlayerRepository(dynamoDbEnhancedClient: DynamoDbEnhancedAsyncClient) { return updatedPlayer.toPlayer() } - suspend fun findPlayerByPseudo(pseudo: String): Player { + suspend fun findPlayerByPseudo(pseudo: String): Player? { val foundPlayer = table.getItem( Key.builder().partitionValue(pseudo).build() ).await() - return foundPlayer.toPlayer() + return foundPlayer?.toPlayer() } -} \ No newline at end of file + + suspend fun findAll(): List<Player> { + return buildList { + table.scan().asFlow().collect { it.items().stream().forEach { item -> add(item.toPlayer()) } } + } + } + + + suspend fun deleteAllPlayers() { + table.deleteTable() + table.createTable().await() + + } +} + diff --git a/src/main/kotlin/player/PlayerRoute.kt b/src/main/kotlin/player/PlayerRoute.kt index ff94f41..c55907f 100644 --- a/src/main/kotlin/player/PlayerRoute.kt +++ b/src/main/kotlin/player/PlayerRoute.kt @@ -9,19 +9,36 @@ import org.koin.ktor.ext.inject fun Routing.playerRoutes() { val playerService by inject<PlayerService>() - post("/players") { - val request = call.receive<String>() - playerService.createNewPlayer(request) - call.respond(HttpStatusCode.Created) - } + route("/players") { + post { + val request = call.receive<String>() + playerService.createNewPlayer(request) + call.respond(HttpStatusCode.Created) + } - put("/players") { - val request = call.receive<Player>() - call.respond(playerService.updatePlayer(request)) - } + put { + val request = call.receive<Player>() + call.respond(playerService.updatePlayer(request)) + } + + get("/{pseudo}") { + val pseudo = call.parameters["pseudo"] ?: return@get call.respond(HttpStatusCode.BadRequest) + call.respond<Player>(playerService.findPlayerByPseudo(pseudo)) + } - get("/players/{pseudo}") { - val pseudo = call.parameters["pseudo"] ?: return@get call.respond(HttpStatusCode.BadRequest) - call.respond<Player>(playerService.getPlayerByPseudo(pseudo)) + get("/{pseudo}/info") { + val pseudo = call.parameters["pseudo"] ?: return@get call.respond(HttpStatusCode.BadRequest) + call.respond<PlayerInfoDTO>(playerService.getPlayerInfoByPseudo(pseudo)) + } + + get("/ranking") { + call.respond(playerService.getPlayersRanked()) + } + + delete { + playerService.deleteAllPlayers() + call.respond(HttpStatusCode.NoContent) + } } + } \ No newline at end of file diff --git a/src/main/kotlin/player/PlayerService.kt b/src/main/kotlin/player/PlayerService.kt index 2f06a29..2b12d17 100644 --- a/src/main/kotlin/player/PlayerService.kt +++ b/src/main/kotlin/player/PlayerService.kt @@ -5,5 +5,11 @@ interface PlayerService { suspend fun updatePlayer(player: Player): Player - suspend fun getPlayerByPseudo(pseudo: String): Player + suspend fun findPlayerByPseudo(pseudo: String): Player + + suspend fun getPlayerInfoByPseudo(pseudo: String): PlayerInfoDTO + + suspend fun getPlayersRanked(): List<PlayerInfoDTO> + + suspend fun deleteAllPlayers() } \ No newline at end of file diff --git a/src/main/kotlin/player/PlayerServiceImpl.kt b/src/main/kotlin/player/PlayerServiceImpl.kt index 9af6cdc..a9fc7a4 100644 --- a/src/main/kotlin/player/PlayerServiceImpl.kt +++ b/src/main/kotlin/player/PlayerServiceImpl.kt @@ -1,5 +1,7 @@ package betclic.test.player +import io.ktor.server.plugins.* + class PlayerServiceImpl(private val playerRepository: PlayerRepository) : PlayerService { override suspend fun createNewPlayer(pseudo: String) { @@ -10,7 +12,31 @@ class PlayerServiceImpl(private val playerRepository: PlayerRepository) : Player return playerRepository.updatePlayer(player) } - override suspend fun getPlayerByPseudo(pseudo: String): Player { - return playerRepository.findPlayerByPseudo(pseudo) + override suspend fun findPlayerByPseudo(pseudo: String): Player { + val player = playerRepository.findPlayerByPseudo(pseudo) ?: throw NotFoundException("Player $pseudo not found") + return player + } + + override suspend fun getPlayerInfoByPseudo(pseudo: String): PlayerInfoDTO { + val allPlayersRanked = getPlayersRanked() + val player = allPlayersRanked.find { it.pseudo == pseudo } + ?: throw NotFoundException("Player $pseudo not found in ranking") + return player + } + + override suspend fun getPlayersRanked(): List<PlayerInfoDTO> { + val allPlayers = playerRepository.findAll() + return allPlayers.sortedByDescending { it.pointsNumber }.mapIndexed { index, player -> + PlayerInfoDTO( + pseudo = player.pseudo, + pointsNumber = player.pointsNumber, + ranking = index + 1 + ) + } + + } + + override suspend fun deleteAllPlayers() { + playerRepository.deleteAllPlayers() } } \ No newline at end of file -- GitLab