From ed7bcac3feb3b35eefc244aa11629ae4394091a5 Mon Sep 17 00:00:00 2001 From: Claude Brisson Date: Tue, 23 May 2023 07:37:57 +0200 Subject: [PATCH] Team / individual tournaments almost ok --- .../org/jeudego/pairgoth/api/PlayerHandler.kt | 5 +- .../org/jeudego/pairgoth/api/TeamHandler.kt | 53 +++++++++++++++++++ .../org/jeudego/pairgoth/model/Pairable.kt | 26 --------- .../org/jeudego/pairgoth/model/Tournament.kt | 32 ++++++++++- .../org/jeudego/pairgoth/web/ApiServlet.kt | 2 + .../kotlin/org/jeudego/pairgoth/web/Event.kt | 3 ++ 6 files changed, 91 insertions(+), 30 deletions(-) create mode 100644 webapp/src/main/kotlin/org/jeudego/pairgoth/api/TeamHandler.kt diff --git a/webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt b/webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt index 99a15f8..5a68180 100644 --- a/webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt +++ b/webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt @@ -23,7 +23,6 @@ object PlayerHandler: PairgothApiHandler { override fun post(request: HttpServletRequest): Json { val tournament = getTournament(request) val payload = getObjectPayload(request) - // player parsing (CB TODO - team handling, based on tournament type) val player = Player.fromJson(payload) tournament.players[player.id] = player Event.dispatch(playerAdded, Json.Object("tournament" to tournament.id, "data" to player.toJson())) @@ -33,9 +32,9 @@ object PlayerHandler: PairgothApiHandler { override fun put(request: HttpServletRequest): Json { val tournament = getTournament(request) val id = getSubSelector(request)?.toIntOrNull() ?: badRequest("missing or invalid player selector") - val player = tournament.pairables[id] ?: badRequest("invalid player id") + val player = tournament.players[id] ?: badRequest("invalid player id") val payload = getObjectPayload(request) - val updated = Player.fromJson(payload, player as Player) + val updated = Player.fromJson(payload, player) tournament.players[updated.id] = updated Event.dispatch(playerUpdated, Json.Object("tournament" to tournament.id, "data" to player.toJson())) return Json.Object("success" to true) diff --git a/webapp/src/main/kotlin/org/jeudego/pairgoth/api/TeamHandler.kt b/webapp/src/main/kotlin/org/jeudego/pairgoth/api/TeamHandler.kt new file mode 100644 index 0000000..e440a9d --- /dev/null +++ b/webapp/src/main/kotlin/org/jeudego/pairgoth/api/TeamHandler.kt @@ -0,0 +1,53 @@ +package org.jeudego.pairgoth.api + +import com.republicate.kson.Json +import com.republicate.kson.toJsonArray +import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest +import org.jeudego.pairgoth.model.TeamTournament +import org.jeudego.pairgoth.web.Event +import org.jeudego.pairgoth.web.Event.* +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse + +object TeamHandler: PairgothApiHandler { + + override fun get(request: HttpServletRequest, response: HttpServletResponse): Json? { + val tournament = getTournament(request) + if (tournament !is TeamTournament) badRequest("tournament is not a team tournament") + return when (val pid = getSubSelector(request)?.toIntOrNull()) { + null -> tournament.teams.values.map { it.toJson() }.toJsonArray() + else -> tournament.teams[pid]?.toJson() ?: badRequest("no team with id #${pid}") + } + } + + override fun post(request: HttpServletRequest): Json { + val tournament = getTournament(request) + if (tournament !is TeamTournament) badRequest("tournament is not a team tournament") + val payload = getObjectPayload(request) + val team = tournament.teamFromJson(payload) + tournament.teams[team.id] = team + Event.dispatch(teamAdded, Json.Object("tournament" to tournament.id, "data" to team.toJson())) + return Json.Object("success" to true, "id" to team.id) + } + + override fun put(request: HttpServletRequest): Json { + val tournament = getTournament(request) + if (tournament !is TeamTournament) badRequest("tournament is not a team tournament") + val id = getSubSelector(request)?.toIntOrNull() ?: badRequest("missing or invalid player selector") + val team = tournament.teams[id] ?: badRequest("invalid team id") + val payload = getObjectPayload(request) + val updated = tournament.teamFromJson(payload, team) + tournament.teams[updated.id] = updated + Event.dispatch(teamUpdated, Json.Object("tournament" to tournament.id, "data" to team.toJson())) + return Json.Object("success" to true) + } + + override fun delete(request: HttpServletRequest): Json { + val tournament = getTournament(request) + if (tournament !is TeamTournament) badRequest("tournament is not a team tournament") + val id = getSubSelector(request)?.toIntOrNull() ?: badRequest("missing or invalid team selector") + tournament.teams.remove(id) ?: badRequest("invalid team id") + Event.dispatch(teamDeleted, Json.Object("tournament" to tournament.id, "data" to id)) + return Json.Object("success" to true) + } +} diff --git a/webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairable.kt b/webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairable.kt index 72dddc7..ecc0e68 100644 --- a/webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairable.kt +++ b/webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairable.kt @@ -83,29 +83,3 @@ fun Player.Companion.fromJson(json: Json.Object, default: Player? = null) = Play if (it.isNotEmpty()) player.skip.addAll(it.map { id -> (id as Number).toInt() }) } } - -// Team - -class Team(id: Int, name: String): Pairable(id, name, 0, 0) { - companion object {} - val players = mutableSetOf() - override val rating: Int get() = if (players.isEmpty()) super.rating else (players.sumOf { player -> player.rating.toDouble() } / players.size).roundToInt() - override val rank: Int get() = if (players.isEmpty()) super.rank else (players.sumOf { player -> player.rank.toDouble() } / players.size).roundToInt() - override fun toJson() = Json.Object( - "id" to id, - "name" to name, - "players" to players.map { it.toJson() }.toJsonArray() - ) -} - -fun Team.Companion.fromJson(json: Json.Object) = Team( - id = json.getInt("id") ?: Store.nextPlayerId, - name = json.getString("name") ?: badRequest("missing name") -).apply { - json.getArray("players")?.let { arr -> - arr.map { - if (it != null && it is Json.Object) Player.fromJson(it) - else badRequest("invalid players array") - } - } ?: badRequest("missing players") -} diff --git a/webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt b/webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt index b297afc..b5ad1e6 100644 --- a/webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt +++ b/webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt @@ -1,9 +1,11 @@ package org.jeudego.pairgoth.model import com.republicate.kson.Json +import com.republicate.kson.toJsonArray import kotlinx.datetime.LocalDate import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest import org.jeudego.pairgoth.store.Store +import kotlin.math.roundToInt sealed class Tournament ( val id: Int, @@ -106,9 +108,37 @@ class TeamTournament( rules: Rules = Rules.FRENCH, gobanSize: Int = 19, komi: Double = 7.5 -): Tournament(id, type, name, shortName, startDate, endDate, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi) { +): Tournament(id, type, name, shortName, startDate, endDate, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi) { + companion object {} override val players = mutableMapOf() val teams: MutableMap = _pairables + + inner class Team(id: Int, name: String): Pairable(id, name, 0, 0) { + val playerIds = mutableSetOf() + val teamPlayers: Set get() = playerIds.mapNotNull { players[id] }.toSet() + override val rating: Int get() = if (players.isEmpty()) super.rating else (teamPlayers.sumOf { player -> player.rating.toDouble() } / players.size).roundToInt() + override val rank: Int get() = if (players.isEmpty()) super.rank else (teamPlayers.sumOf { player -> player.rank.toDouble() } / players.size).roundToInt() + val club: String? get() = players.map { club }.distinct().let { if (it.size == 1) it[0] else null } + val country: String? get() = players.map { country }.distinct().let { if (it.size == 1) it[0] else null } + override fun toJson() = Json.Object( + "id" to id, + "name" to name, + "players" to playerIds.toList().toJsonArray() + ) + } + + fun teamFromJson(json: Json.Object, default: TeamTournament.Team? = null) = Team( + id = json.getInt("id") ?: default?.id ?: Store.nextPlayerId, + name = json.getString("name") ?: default?.name ?: badRequest("missing name") + ).apply { + json.getArray("players")?.let { arr -> + arr.map { + if (it != null && it is Json.Object) Player.fromJson(it) + else badRequest("invalid players array") + } + } ?: badRequest("missing players") + } + } // Serialization diff --git a/webapp/src/main/kotlin/org/jeudego/pairgoth/web/ApiServlet.kt b/webapp/src/main/kotlin/org/jeudego/pairgoth/web/ApiServlet.kt index aea6753..269fca1 100644 --- a/webapp/src/main/kotlin/org/jeudego/pairgoth/web/ApiServlet.kt +++ b/webapp/src/main/kotlin/org/jeudego/pairgoth/web/ApiServlet.kt @@ -5,6 +5,7 @@ import org.jeudego.pairgoth.api.ApiHandler import org.jeudego.pairgoth.api.PairingHandler import org.jeudego.pairgoth.api.PlayerHandler import org.jeudego.pairgoth.api.ResultsHandler +import org.jeudego.pairgoth.api.TeamHandler import org.jeudego.pairgoth.api.TournamentHandler import org.jeudego.pairgoth.util.Colorizer.blue import org.jeudego.pairgoth.util.Colorizer.green @@ -86,6 +87,7 @@ class ApiServlet : HttpServlet() { "part" -> PlayerHandler "pair" -> PairingHandler "res" -> ResultsHandler + "team" -> TeamHandler else -> ApiHandler.badRequest("unknown sub-entity: $subEntity") } "player" -> PlayerHandler diff --git a/webapp/src/main/kotlin/org/jeudego/pairgoth/web/Event.kt b/webapp/src/main/kotlin/org/jeudego/pairgoth/web/Event.kt index 2f46f56..2949aaf 100644 --- a/webapp/src/main/kotlin/org/jeudego/pairgoth/web/Event.kt +++ b/webapp/src/main/kotlin/org/jeudego/pairgoth/web/Event.kt @@ -10,6 +10,9 @@ enum class Event { playerAdded, playerUpdated, playerDeleted, + teamAdded, + teamUpdated, + teamDeleted, gamesAdded, gamesDeleted, resultUpdated,