Code cleaning in handlers; implement result handler

This commit is contained in:
Claude Brisson
2023-05-19 11:11:28 +02:00
parent 5a85e16d06
commit 1e20247fe9
6 changed files with 72 additions and 24 deletions

View File

@@ -6,6 +6,10 @@ import javax.servlet.http.HttpServletRequest
interface PairgothApiHandler: ApiHandler { interface PairgothApiHandler: ApiHandler {
fun getTournament(request: HttpServletRequest): Tournament? = getSelector(request)?.toIntOrNull()?.let { Store.getTournament(it) } fun getTournament(request: HttpServletRequest): Tournament {
val tournamentId = getSelector(request)?.toIntOrNull() ?: ApiHandler.badRequest("invalid tournament id")
return Store.getTournament(tournamentId) ?: ApiHandler.badRequest("unknown tournament id")
}
} }

View File

@@ -9,18 +9,15 @@ import org.jeudego.pairgoth.model.toJson
import org.jeudego.pairgoth.store.Store import org.jeudego.pairgoth.store.Store
import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletRequest
object PairingHandler: ApiHandler { object PairingHandler: PairgothApiHandler {
private fun getTournament(request: HttpServletRequest): Tournament {
val tournamentId = getSelector(request)?.toIntOrNull() ?: badRequest("invalid tournament id")
return Store.getTournament(tournamentId) ?: badRequest("unknown tournament id")
}
override fun get(request: HttpServletRequest): Json { override fun get(request: HttpServletRequest): Json {
val tournament = getTournament(request) val tournament = getTournament(request)
val round = getSubSelector(request)?.toIntOrNull() ?: badRequest("invalid round number") val round = getSubSelector(request)?.toIntOrNull() ?: badRequest("invalid round number")
val games = tournament.games.getOrNull(round)?.values ?: emptyList() val playing = (tournament.games.getOrNull(round)?.values ?: emptyList()).flatMap {
return games.map { it.toJson() }.toJsonArray() listOf(it.black, it.white)
}.toSet()
return tournament.pairables.values.filter { !it.skip.contains(round) && !playing.contains(it.id) }.toJsonArray()
} }
override fun post(request: HttpServletRequest): Json { override fun post(request: HttpServletRequest): Json {
@@ -29,25 +26,21 @@ object PairingHandler: ApiHandler {
val payload = getArrayPayload(request) val payload = getArrayPayload(request)
val allPlayers = payload.size == 1 && payload[0] == "all" val allPlayers = payload.size == 1 && payload[0] == "all"
if (!allPlayers && tournament.pairing.type == Pairing.PairingType.SWISS) badRequest("Swiss pairing requires all pairable players") if (!allPlayers && tournament.pairing.type == Pairing.PairingType.SWISS) badRequest("Swiss pairing requires all pairable players")
val playing = (tournament.games.getOrNull(round)?.values ?: emptyList()).flatMap {
listOf(it.black, it.white)
}.toSet()
val pairables = val pairables =
if (allPlayers) if (allPlayers)
tournament.pairables.values.filter { !it.skip.contains(round) } tournament.pairables.values.filter { !it.skip.contains(round) && !playing.contains(it.id) }
else payload.map { else payload.map {
// CB - because of the '["all"]' map, conversion to int lands here... Better API syntax for 'all players'?
if (it is Number) it.toInt() else badRequest("invalid pairable id: #$it") if (it is Number) it.toInt() else badRequest("invalid pairable id: #$it")
}.map { id -> }.map { id ->
tournament.pairables[id]?.also { tournament.pairables[id]?.also {
if (it.skip.contains(round)) badRequest("pairable #$id does not play round $round") if (it.skip.contains(round)) badRequest("pairable #$id does not play round $round")
if (playing.contains(it.id)) badRequest("pairable #$id already plays round $round")
} ?: badRequest("invalid pairable id: #$id") } ?: badRequest("invalid pairable id: #$id")
} }
// check players are not already implied in games in this round
val pairablesIDs = pairables.map { it.id }.toSet()
tournament.games.getOrNull(round)?.let { games ->
games.values.mapNotNull { game ->
if (pairablesIDs.contains(game.black)) game.black else if (pairablesIDs.contains(game.white)) game.white else null
}.let {
if (it.isNotEmpty()) badRequest("The following players are already playing this round: ${it.joinToString { id -> "#${id}" }}")
}
}
val games = tournament.pair(round, pairables) val games = tournament.pair(round, pairables)
return games.map { it.toJson() }.toJsonArray() return games.map { it.toJson() }.toJsonArray()
} }

View File

@@ -1,4 +1,47 @@
package org.jeudego.pairgoth.api package org.jeudego.pairgoth.api
class ResultsHandler: ApiHandler { import com.republicate.kson.Json
} import com.republicate.kson.toJsonArray
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.model.Game
import org.jeudego.pairgoth.model.Tournament
import org.jeudego.pairgoth.model.toJson
import org.jeudego.pairgoth.store.Store
import javax.servlet.http.HttpServletRequest
object ResultsHandler: PairgothApiHandler {
override fun get(request: HttpServletRequest): Json {
val tournament = getTournament(request)
val round = getSubSelector(request)?.toIntOrNull() ?: badRequest("invalid round number")
val games = tournament.games.getOrNull(round)?.values ?: emptyList()
return games.map { it.toJson() }.toJsonArray()
}
override fun post(request: HttpServletRequest): Json {
val tournament = getTournament(request)
val round = getSubSelector(request)?.toIntOrNull() ?: badRequest("invalid round number")
val payload = getObjectPayload(request)
val game = tournament.games[round][payload.getInt("id")] ?: badRequest("invalid game id")
game.result = Game.Result.valueOf(payload.getString("result") ?: badRequest("missing result"))
return Json.Object("success" to true)
}
override fun put(request: HttpServletRequest): Json {
val tournament = getTournament(request)
val round = getSubSelector(request)?.toIntOrNull() ?: badRequest("invalid round number")
val payload = getObjectPayload(request)
val game = tournament.games[round][payload.getInt("id")] ?: badRequest("invalid game id")
game.result = Game.Result.valueOf(payload.getString("result") ?: badRequest("missing result"))
return Json.Object("success" to true)
}
override fun delete(request: HttpServletRequest): Json {
val tournament = getTournament(request)
val round = getSubSelector(request)?.toIntOrNull() ?: badRequest("invalid round number")
val payload = getObjectPayload(request)
val game = tournament.games[round][payload.getInt("id")] ?: badRequest("invalid game id")
tournament.games[round].remove(payload.getInt("id") ?: badRequest("invalid game id")) ?: badRequest("invalid game id")
return Json.Object("success" to true)
}
}

View File

@@ -1,4 +1,4 @@
package org.jeudego.pairgoth.api package org.jeudego.pairgoth.api
class StandingsHandler: ApiHandler { object StandingsHandler: PairgothApiHandler {
} }

View File

@@ -4,6 +4,7 @@ import com.republicate.kson.Json
import org.jeudego.pairgoth.api.ApiHandler 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.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
@@ -84,6 +85,7 @@ class ApiServlet : HttpServlet() {
null -> TournamentHandler null -> TournamentHandler
"part" -> PlayerHandler "part" -> PlayerHandler
"pair" -> PairingHandler "pair" -> PairingHandler
"res" -> ResultsHandler
else -> ApiHandler.badRequest("unknown sub-entity: $subEntity") else -> ApiHandler.badRequest("unknown sub-entity: $subEntity")
} }
"player" -> PlayerHandler "player" -> PlayerHandler

View File

@@ -13,8 +13,14 @@ class ImportTests: TestBase() {
val resource = file.readText(StandardCharsets.UTF_8) val resource = file.readText(StandardCharsets.UTF_8)
val resp = TestAPI.post("/api/tour", resource) val resp = TestAPI.post("/api/tour", resource)
val id = resp.asObject().getInt("id") val id = resp.asObject().getInt("id")
val tournament = TestAPI.get("/api/tour/$id") val tournament = TestAPI.get("/api/tour/$id").asObject()
logger.info(tournament.toString()) logger.info(tournament.toString())
val players = TestAPI.get("/api/tour/$id/part").asArray()
logger.info(players.toString())
for (round in 1..tournament.getInt("rounds")!!) {
val games = TestAPI.get("/api/tour/$id/res/1").asArray()
logger.info("games for round $round: {}", games.toString())
}
} }
} }
} }