Team / individual tournaments almost ok

This commit is contained in:
Claude Brisson
2023-05-23 07:37:57 +02:00
parent dda1b7e69e
commit ed7bcac3fe
6 changed files with 91 additions and 30 deletions

View File

@@ -23,7 +23,6 @@ object PlayerHandler: PairgothApiHandler {
override fun post(request: HttpServletRequest): Json { override fun post(request: HttpServletRequest): Json {
val tournament = getTournament(request) val tournament = getTournament(request)
val payload = getObjectPayload(request) val payload = getObjectPayload(request)
// player parsing (CB TODO - team handling, based on tournament type)
val player = Player.fromJson(payload) val player = Player.fromJson(payload)
tournament.players[player.id] = player tournament.players[player.id] = player
Event.dispatch(playerAdded, Json.Object("tournament" to tournament.id, "data" to player.toJson())) 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 { override fun put(request: HttpServletRequest): Json {
val tournament = getTournament(request) val tournament = getTournament(request)
val id = getSubSelector(request)?.toIntOrNull() ?: badRequest("missing or invalid player selector") 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 payload = getObjectPayload(request)
val updated = Player.fromJson(payload, player as Player) val updated = Player.fromJson(payload, player)
tournament.players[updated.id] = updated tournament.players[updated.id] = updated
Event.dispatch(playerUpdated, Json.Object("tournament" to tournament.id, "data" to player.toJson())) Event.dispatch(playerUpdated, Json.Object("tournament" to tournament.id, "data" to player.toJson()))
return Json.Object("success" to true) return Json.Object("success" to true)

View File

@@ -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)
}
}

View File

@@ -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() }) 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<Player>()
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")
}

View File

@@ -1,9 +1,11 @@
package org.jeudego.pairgoth.model package org.jeudego.pairgoth.model
import com.republicate.kson.Json import com.republicate.kson.Json
import com.republicate.kson.toJsonArray
import kotlinx.datetime.LocalDate import kotlinx.datetime.LocalDate
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.store.Store import org.jeudego.pairgoth.store.Store
import kotlin.math.roundToInt
sealed class Tournament <P: Pairable>( sealed class Tournament <P: Pairable>(
val id: Int, val id: Int,
@@ -106,9 +108,37 @@ class TeamTournament(
rules: Rules = Rules.FRENCH, rules: Rules = Rules.FRENCH,
gobanSize: Int = 19, gobanSize: Int = 19,
komi: Double = 7.5 komi: Double = 7.5
): Tournament<Team>(id, type, name, shortName, startDate, endDate, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi) { ): Tournament<TeamTournament.Team>(id, type, name, shortName, startDate, endDate, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi) {
companion object {}
override val players = mutableMapOf<Int, Player>() override val players = mutableMapOf<Int, Player>()
val teams: MutableMap<Int, Team> = _pairables val teams: MutableMap<Int, Team> = _pairables
inner class Team(id: Int, name: String): Pairable(id, name, 0, 0) {
val playerIds = mutableSetOf<Int>()
val teamPlayers: Set<Player> 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 // Serialization

View File

@@ -5,6 +5,7 @@ import org.jeudego.pairgoth.api.ApiHandler
import org.jeudego.pairgoth.api.PairingHandler import org.jeudego.pairgoth.api.PairingHandler
import org.jeudego.pairgoth.api.PlayerHandler import org.jeudego.pairgoth.api.PlayerHandler
import org.jeudego.pairgoth.api.ResultsHandler import org.jeudego.pairgoth.api.ResultsHandler
import org.jeudego.pairgoth.api.TeamHandler
import org.jeudego.pairgoth.api.TournamentHandler import org.jeudego.pairgoth.api.TournamentHandler
import org.jeudego.pairgoth.util.Colorizer.blue import org.jeudego.pairgoth.util.Colorizer.blue
import org.jeudego.pairgoth.util.Colorizer.green import org.jeudego.pairgoth.util.Colorizer.green
@@ -86,6 +87,7 @@ class ApiServlet : HttpServlet() {
"part" -> PlayerHandler "part" -> PlayerHandler
"pair" -> PairingHandler "pair" -> PairingHandler
"res" -> ResultsHandler "res" -> ResultsHandler
"team" -> TeamHandler
else -> ApiHandler.badRequest("unknown sub-entity: $subEntity") else -> ApiHandler.badRequest("unknown sub-entity: $subEntity")
} }
"player" -> PlayerHandler "player" -> PlayerHandler

View File

@@ -10,6 +10,9 @@ enum class Event {
playerAdded, playerAdded,
playerUpdated, playerUpdated,
playerDeleted, playerDeleted,
teamAdded,
teamUpdated,
teamDeleted,
gamesAdded, gamesAdded,
gamesDeleted, gamesDeleted,
resultUpdated, resultUpdated,