API in progress: tournament and registration ok
This commit is contained in:
18
test.sh
18
test.sh
@@ -3,25 +3,17 @@
|
|||||||
curl -s --header "Accept: application/json" --header "Content-Type: application/json" \
|
curl -s --header "Accept: application/json" --header "Content-Type: application/json" \
|
||||||
--request POST \
|
--request POST \
|
||||||
--data '{ "type":"INDIVIDUAL","name":"Mon Tournoi", "shortName": "mon-tournoi", "startDate": "2023-05-10", "endDate": "2023-05-12", "country": "FR", "location": "Marseille", "online": false, "timeSystem": { "type": "fisher", "mainTime": "1200", "increment": "10" }, "pairing": { "type": "ROUNDROBIN" } }' \
|
--data '{ "type":"INDIVIDUAL","name":"Mon Tournoi", "shortName": "mon-tournoi", "startDate": "2023-05-10", "endDate": "2023-05-12", "country": "FR", "location": "Marseille", "online": false, "timeSystem": { "type": "fisher", "mainTime": "1200", "increment": "10" }, "pairing": { "type": "ROUNDROBIN" } }' \
|
||||||
http://localhost:8080/api/tournament
|
http://localhost:8080/api/tour
|
||||||
|
|
||||||
curl -s --header "Accept: application/json" http://localhost:8080/api/tournament
|
curl -s --header "Accept: application/json" http://localhost:8080/api/tour
|
||||||
|
|
||||||
curl -s --header "Accept: application/json" http://localhost:8080/api/tournament/1
|
curl -s --header "Accept: application/json" http://localhost:8080/api/tour/1
|
||||||
|
|
||||||
curl -s --header "Accept: application/json" --header "Content-Type: application/json" \
|
curl -s --header "Accept: application/json" --header "Content-Type: application/json" \
|
||||||
--request POST \
|
--request POST \
|
||||||
--data '{ "name": "Burma", "firstname": "Nestor", "rating": 1600, "rank": -2, "country": "FR", "club": "13Ma" }' \
|
--data '{ "name": "Burma", "firstname": "Nestor", "rating": 1600, "rank": -2, "country": "FR", "club": "13Ma" }' \
|
||||||
http://localhost:8080/api/player
|
http://localhost:8080/api/tour/1/part
|
||||||
|
|
||||||
curl -s --header "Accept: application/json" http://localhost:8080/api/player
|
|
||||||
|
|
||||||
curl -s --header "Accept: application/json" --header "Content-Type: application/json" \
|
|
||||||
--request POST \
|
|
||||||
--data '{ "id": 1 }' \
|
|
||||||
http://localhost:8080/api/tournament/1/registration
|
|
||||||
|
|
||||||
curl -s --header "Accept: application/json" http://localhost:8080/api/tournament/1/registration
|
|
||||||
|
|
||||||
|
curl -s --header "Accept: application/json" http://localhost:8080/api/tour/1/part
|
||||||
|
|
||||||
|
|
||||||
|
@@ -0,0 +1,11 @@
|
|||||||
|
package org.jeudego.pairgoth.api
|
||||||
|
|
||||||
|
import org.jeudego.pairgoth.model.Tournament
|
||||||
|
import org.jeudego.pairgoth.store.Store
|
||||||
|
import javax.servlet.http.HttpServletRequest
|
||||||
|
|
||||||
|
interface PairgothApiHandler: ApiHandler {
|
||||||
|
|
||||||
|
fun getTournament(request: HttpServletRequest): Tournament? = getSelector(request)?.toIntOrNull()?.let { Store.getTournament(it) }
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
package org.jeudego.pairgoth.api
|
||||||
|
|
||||||
|
import com.republicate.kson.Json
|
||||||
|
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
|
||||||
|
import org.jeudego.pairgoth.model.Tournament
|
||||||
|
import org.jeudego.pairgoth.store.Store
|
||||||
|
import javax.servlet.http.HttpServletRequest
|
||||||
|
|
||||||
|
object PairingHandler: ApiHandler {
|
||||||
|
|
||||||
|
private fun getTournament(request: HttpServletRequest): Tournament {
|
||||||
|
val tournamentId = getSelector(request)?.toIntOrNull() ?: ApiHandler.badRequest("invalid tournament id")
|
||||||
|
return Store.getTournament(tournamentId) ?: ApiHandler.badRequest("unknown tournament id")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(request: HttpServletRequest): Json {
|
||||||
|
val tournament = getTournament(request)
|
||||||
|
val round = request.getParameter("round")?.toIntOrNull() ?: badRequest("invalid round number")
|
||||||
|
return Json.Object();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,35 +1,43 @@
|
|||||||
package org.jeudego.pairgoth.api
|
package org.jeudego.pairgoth.api
|
||||||
|
|
||||||
import com.republicate.kson.Json
|
import com.republicate.kson.Json
|
||||||
|
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
|
||||||
import org.jeudego.pairgoth.model.Player
|
import org.jeudego.pairgoth.model.Player
|
||||||
import org.jeudego.pairgoth.model.Tournament
|
|
||||||
import org.jeudego.pairgoth.model.fromJson
|
import org.jeudego.pairgoth.model.fromJson
|
||||||
import org.jeudego.pairgoth.model.toJson
|
|
||||||
import org.jeudego.pairgoth.store.Store
|
|
||||||
import javax.servlet.http.HttpServletRequest
|
import javax.servlet.http.HttpServletRequest
|
||||||
|
|
||||||
object PlayerHandler: ApiHandler {
|
object PlayerHandler: PairgothApiHandler {
|
||||||
|
|
||||||
|
override fun get(request: HttpServletRequest): Json {
|
||||||
|
val tournament = getTournament(request) ?: badRequest("invalid tournament")
|
||||||
|
return when (val pid = getSubSelector(request)?.toIntOrNull()) {
|
||||||
|
null -> Json.Array(tournament.pairables.values.map { it.toJson() })
|
||||||
|
else -> tournament.pairables[pid]?.toJson() ?: badRequest("no player with id #${pid}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun post(request: HttpServletRequest): Json {
|
override fun post(request: HttpServletRequest): Json {
|
||||||
|
val tournament = getTournament(request) ?: badRequest("invalid tournament")
|
||||||
val payload = getObjectPayload(request)
|
val payload = getObjectPayload(request)
|
||||||
|
// player parsing (CB TODO - team handling, based on tournament type)
|
||||||
// player parsing
|
|
||||||
val player = Player.fromJson(payload)
|
val player = Player.fromJson(payload)
|
||||||
|
// CB TODO - handle concurrency
|
||||||
Store.addPlayer(player)
|
tournament.pairables[player.id] = player
|
||||||
|
// CB TODO - handle event broadcasting
|
||||||
return Json.Object("success" to true, "id" to player.id)
|
return Json.Object("success" to true, "id" to player.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun get(request: HttpServletRequest): Json {
|
|
||||||
return when (val id = getSelector(request)?.toIntOrNull()) {
|
|
||||||
null -> Json.Array(Store.getPlayersIDs())
|
|
||||||
else -> Store.getPlayer(id)?.toJson() ?: ApiHandler.badRequest("no player with id #${id}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun put(request: HttpServletRequest): Json {
|
override fun put(request: HttpServletRequest): Json {
|
||||||
val id = getSelector(request)?.toIntOrNull() ?: ApiHandler.badRequest("missing or invalid player selector")
|
val tournament = getTournament(request) ?: badRequest("invalid tournament")
|
||||||
TODO()
|
val id = getSubSelector(request)?.toIntOrNull() ?: badRequest("missing or invalid player selector")
|
||||||
|
val player = tournament.pairables[id] ?: badRequest("invalid player id")
|
||||||
|
val payload = getObjectPayload(request)
|
||||||
|
val updated = Player.fromJson(payload, player as Player)
|
||||||
|
tournament.pairables[updated.id] = updated
|
||||||
|
return Json.Object("success" to true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun delete(request: HttpServletRequest): Json {
|
||||||
|
return super.delete(request)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,43 +0,0 @@
|
|||||||
package org.jeudego.pairgoth.api
|
|
||||||
|
|
||||||
import com.republicate.kson.Json
|
|
||||||
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
|
|
||||||
import org.jeudego.pairgoth.model.Tournament
|
|
||||||
import org.jeudego.pairgoth.store.Store
|
|
||||||
import javax.servlet.http.HttpServletRequest
|
|
||||||
|
|
||||||
object RegistrationHandler: ApiHandler {
|
|
||||||
|
|
||||||
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 {
|
|
||||||
val tournament = getTournament(request)
|
|
||||||
return when (val pairableId = getSubSelector(request)?.toIntOrNull()) {
|
|
||||||
null -> when (val round = request.getParameter("round")?.toIntOrNull()) {
|
|
||||||
null -> Json.Array(tournament.pairables.map {
|
|
||||||
Json.Object(
|
|
||||||
"id" to it.key,
|
|
||||||
"skip" to Json.Array(it.value)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
else -> Json.Array(tournament.pairables.filter { !it.value.contains(round) }.keys)
|
|
||||||
}
|
|
||||||
else -> Json.Array(tournament.pairables[pairableId])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun post(request: HttpServletRequest): Json {
|
|
||||||
val tournament = getTournament(request)
|
|
||||||
val payload = getObjectPayload(request)
|
|
||||||
val pairableId = payload.getInt("id") ?: badRequest("missing player id")
|
|
||||||
val skip = ( payload.getArray("skip") ?: Json.Array() ).map { Json.TypeUtils.toInt(it) ?: badRequest("invalid round number") }
|
|
||||||
if (tournament.pairables.contains(pairableId)) badRequest("already registered player: $pairableId")
|
|
||||||
/* CB TODO - update action for SSE channel */
|
|
||||||
tournament.pairables[pairableId] = skip.toMutableSet()
|
|
||||||
return Json.Object("success" to true)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -0,0 +1,4 @@
|
|||||||
|
package org.jeudego.pairgoth.api
|
||||||
|
|
||||||
|
class ResultsHandler: ApiHandler {
|
||||||
|
}
|
@@ -0,0 +1,4 @@
|
|||||||
|
package org.jeudego.pairgoth.api
|
||||||
|
|
||||||
|
class StandingsHandler: ApiHandler {
|
||||||
|
}
|
@@ -2,21 +2,20 @@ package org.jeudego.pairgoth.api
|
|||||||
|
|
||||||
import com.republicate.kson.Json
|
import com.republicate.kson.Json
|
||||||
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
|
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
|
||||||
import org.jeudego.pairgoth.model.CanadianByoyomi
|
|
||||||
import org.jeudego.pairgoth.model.FisherTime
|
|
||||||
import org.jeudego.pairgoth.model.MacMahon
|
|
||||||
import org.jeudego.pairgoth.model.Rules
|
|
||||||
import org.jeudego.pairgoth.model.StandardByoyomi
|
|
||||||
import org.jeudego.pairgoth.model.SuddenDeath
|
|
||||||
import org.jeudego.pairgoth.model.TimeSystem
|
|
||||||
import org.jeudego.pairgoth.model.Tournament
|
import org.jeudego.pairgoth.model.Tournament
|
||||||
import org.jeudego.pairgoth.model.TournamentType
|
|
||||||
import org.jeudego.pairgoth.model.fromJson
|
import org.jeudego.pairgoth.model.fromJson
|
||||||
import org.jeudego.pairgoth.model.toJson
|
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 TournamentHandler: ApiHandler {
|
object TournamentHandler: PairgothApiHandler {
|
||||||
|
|
||||||
|
override fun get(request: HttpServletRequest): Json {
|
||||||
|
return when (val id = getSelector(request)?.toIntOrNull()) {
|
||||||
|
null -> Json.Array(Store.getTournamentsIDs())
|
||||||
|
else -> Store.getTournament(id)?.toJson() ?: badRequest("no tournament with id #${id}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun post(request: HttpServletRequest): Json {
|
override fun post(request: HttpServletRequest): Json {
|
||||||
val payload = getObjectPayload(request)
|
val payload = getObjectPayload(request)
|
||||||
@@ -28,15 +27,22 @@ object TournamentHandler: ApiHandler {
|
|||||||
return Json.Object("success" to true, "id" to tournament.id)
|
return Json.Object("success" to true, "id" to tournament.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun get(request: HttpServletRequest): Json {
|
override fun put(request: HttpServletRequest): Json {
|
||||||
return when (val id = getSelector(request)?.toIntOrNull()) {
|
val tournament = getTournament(request) ?: badRequest("missing or invalid tournament id")
|
||||||
null -> Json.Array(Store.getTournamentsIDs())
|
val payload = getObjectPayload(request)
|
||||||
else -> Store.getTournament(id)?.toJson() ?: badRequest("no tournament with id #${id}")
|
// disallow changing type
|
||||||
}
|
if (payload.getString("type")?.let { it != tournament.type.name } == true) badRequest("tournament type cannot be changed")
|
||||||
|
val updated = Tournament.fromJson(payload, tournament)
|
||||||
|
updated.pairables.putAll(tournament.pairables)
|
||||||
|
updated.games.addAll(tournament.games)
|
||||||
|
updated.criteria.addAll(tournament.criteria)
|
||||||
|
Store.replaceTournament(updated)
|
||||||
|
return Json.Object("success" to true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun put(request: HttpServletRequest): Json {
|
override fun delete(request: HttpServletRequest): Json {
|
||||||
val id = getSelector(request)?.toIntOrNull() ?: badRequest("missing or invalid tournament selector")
|
val tournament = getTournament(request) ?: badRequest("missing or invalid tournament id")
|
||||||
TODO()
|
Store.deleteTournament(tournament)
|
||||||
|
return Json.Object("success" to true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
package org.jeudego.pairgoth.model
|
||||||
|
|
||||||
|
import org.jeudego.pairgoth.store.Store
|
||||||
|
|
||||||
|
data class Game(val white: Int, val black: Int, var result: Char = '?', val id: Int = Store.nextGameId)
|
@@ -1,6 +1,16 @@
|
|||||||
package org.jeudego.pairgoth.model
|
package org.jeudego.pairgoth.model
|
||||||
|
|
||||||
sealed class Pairable(val id: Int, val name: String, val rating: Double, val rank: Int) {
|
import com.republicate.kson.Json
|
||||||
|
import org.jeudego.pairgoth.api.ApiHandler
|
||||||
|
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
|
||||||
|
import org.jeudego.pairgoth.store.Store
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
// Pairable
|
||||||
|
|
||||||
|
sealed class Pairable(val id: Int, val name: String, open val rating: Double, open val rank: Int) {
|
||||||
|
abstract fun toJson(): Json.Object
|
||||||
|
val skip = mutableSetOf<Int>() // skipped rounds
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Pairable.displayRank(): String = when {
|
fun Pairable.displayRank(): String = when {
|
||||||
@@ -24,3 +34,63 @@ fun Pairable.setRank(rankStr: String): Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Player
|
||||||
|
|
||||||
|
class Player(
|
||||||
|
id: Int,
|
||||||
|
name: String,
|
||||||
|
var firstname: String,
|
||||||
|
rating: Double,
|
||||||
|
rank: Int,
|
||||||
|
var country: String,
|
||||||
|
var club: String
|
||||||
|
): Pairable(id, name, rating, rank) {
|
||||||
|
companion object
|
||||||
|
// used to store external IDs ("FFG" => FFG ID, "EGF" => EGF PIN, "AGA" => AGA ID ...)
|
||||||
|
val externalIds = mutableMapOf<String, String>()
|
||||||
|
override fun toJson() = Json.Object(
|
||||||
|
"id" to id,
|
||||||
|
"name" to name,
|
||||||
|
"firstname" to firstname,
|
||||||
|
"rating" to rating,
|
||||||
|
"rank" to rank,
|
||||||
|
"country" to country,
|
||||||
|
"club" to club
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Player.Companion.fromJson(json: Json.Object, default: Player? = null) = Player(
|
||||||
|
id = json.getInt("id") ?: default?.id ?: Store.nextPlayerId,
|
||||||
|
name = json.getString("name") ?: default?.name ?: badRequest("missing name"),
|
||||||
|
firstname = json.getString("firstname") ?: default?.firstname ?: badRequest("missing firstname"),
|
||||||
|
rating = json.getDouble("rating") ?: default?.rating ?: badRequest("missing rating"),
|
||||||
|
rank = json.getInt("rank") ?: default?.rank ?: badRequest("missing rank"),
|
||||||
|
country = json.getString("country") ?: default?.country ?: badRequest("missing country"),
|
||||||
|
club = json.getString("club") ?: default?.club ?: badRequest("missing club")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Team
|
||||||
|
|
||||||
|
class Team(id: Int, name: String): Pairable(id, name, 0.0, 0) {
|
||||||
|
companion object {}
|
||||||
|
val players = mutableSetOf<Player>()
|
||||||
|
override val rating: Double get() = if (players.isEmpty()) super.rating else players.sumOf { player -> player.rating } / players.size
|
||||||
|
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 Json.Array(players.map { it.toJson() })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
@@ -1,39 +0,0 @@
|
|||||||
package org.jeudego.pairgoth.model
|
|
||||||
|
|
||||||
import com.republicate.kson.Json
|
|
||||||
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
|
|
||||||
import org.jeudego.pairgoth.store.Store
|
|
||||||
|
|
||||||
class Player(
|
|
||||||
id: Int,
|
|
||||||
name: String,
|
|
||||||
var firstname: String,
|
|
||||||
rating: Double,
|
|
||||||
rank: Int,
|
|
||||||
var country: String,
|
|
||||||
var club: String
|
|
||||||
): Pairable(id, name, rating, rank) {
|
|
||||||
companion object
|
|
||||||
// used to store external IDs ("FFG" => FFG ID, "EGF" => EGF PIN, "AGA" => AGA ID ...)
|
|
||||||
val externalIds = mutableMapOf<String, String>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Player.Companion.fromJson(json: Json.Object) = Player(
|
|
||||||
id = json.getInt("id") ?: Store.nextPlayerId,
|
|
||||||
name = json.getString("name") ?: badRequest("missing name"),
|
|
||||||
firstname = json.getString("firstname") ?: badRequest("missing firstname"),
|
|
||||||
rating = json.getDouble("rating") ?: badRequest("missing rating"),
|
|
||||||
rank = json.getInt("rank") ?: badRequest("missing rank"),
|
|
||||||
country = json.getString("country") ?: badRequest("missing country"),
|
|
||||||
club = json.getString("club") ?: ""
|
|
||||||
)
|
|
||||||
|
|
||||||
fun Player.toJson() = Json.Object(
|
|
||||||
"id" to id,
|
|
||||||
"name" to name,
|
|
||||||
"firstname" to firstname,
|
|
||||||
"rating" to rating,
|
|
||||||
"rank" to rank,
|
|
||||||
"country" to country,
|
|
||||||
"club" to club
|
|
||||||
)
|
|
@@ -1,6 +1,2 @@
|
|||||||
package org.jeudego.pairgoth.model
|
package org.jeudego.pairgoth.model
|
||||||
|
|
||||||
class Team(id: Int, name: String, rating: Double, rank: Int): Pairable(id, name, rating, rank) {
|
|
||||||
companion object {}
|
|
||||||
val players = mutableSetOf<Player>()
|
|
||||||
}
|
|
||||||
|
@@ -6,7 +6,24 @@ import org.jeudego.pairgoth.api.ApiHandler
|
|||||||
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
|
||||||
|
|
||||||
enum class TournamentType(val playersNumber: Int) {
|
data class Tournament(
|
||||||
|
val id: Int,
|
||||||
|
val type: Type,
|
||||||
|
val name: String,
|
||||||
|
val shortName: String,
|
||||||
|
val startDate: LocalDate,
|
||||||
|
val endDate: LocalDate,
|
||||||
|
val country: String,
|
||||||
|
val location: String,
|
||||||
|
val online: Boolean,
|
||||||
|
val timeSystem: TimeSystem,
|
||||||
|
val pairing: Pairing,
|
||||||
|
val rules: Rules = Rules.FRENCH,
|
||||||
|
val gobanSize: Int = 19,
|
||||||
|
val komi: Double = 7.5
|
||||||
|
) {
|
||||||
|
companion object {}
|
||||||
|
enum class Type(val playersNumber: Int) {
|
||||||
INDIVIDUAL(1),
|
INDIVIDUAL(1),
|
||||||
PAIRGO(2),
|
PAIRGO(2),
|
||||||
RENGO2(2),
|
RENGO2(2),
|
||||||
@@ -17,44 +34,41 @@ enum class TournamentType(val playersNumber: Int) {
|
|||||||
TEAM5(5);
|
TEAM5(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Tournament(
|
enum class Criterion {
|
||||||
var id: Int,
|
NBW, MMS, SOS, SOSOS, SODOS
|
||||||
var type: TournamentType,
|
}
|
||||||
var name: String,
|
|
||||||
var shortName: String,
|
// pairables
|
||||||
var startDate: LocalDate,
|
val pairables = mutableMapOf<Int, Pairable>()
|
||||||
var endDate: LocalDate,
|
|
||||||
var country: String,
|
// games per round
|
||||||
var location: String,
|
val games = mutableListOf<MutableMap<Int, Game>>()
|
||||||
var online: Boolean,
|
|
||||||
var timeSystem: TimeSystem,
|
// standings criteria
|
||||||
var pairing: Pairing,
|
val criteria = mutableListOf<Criterion>(
|
||||||
var rules: Rules = Rules.FRENCH,
|
if (pairing.type == Pairing.PairingType.MACMAHON) Criterion.MMS else Criterion.NBW,
|
||||||
var gobanSize: Int = 19,
|
Criterion.SOS,
|
||||||
var komi: Double = 7.5
|
Criterion.SOSOS
|
||||||
) {
|
)
|
||||||
companion object
|
|
||||||
// player/team id -> set of skipped rounds
|
|
||||||
val pairables = mutableMapOf<Int, MutableSet<Int>>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialization
|
// Serialization
|
||||||
|
|
||||||
fun Tournament.Companion.fromJson(json: Json.Object) = Tournament(
|
fun Tournament.Companion.fromJson(json: Json.Object, default: Tournament? = null) = Tournament(
|
||||||
id = json.getInt("id") ?: Store.nextTournamentId,
|
id = json.getInt("id") ?: default?.id ?: Store.nextTournamentId,
|
||||||
type = json.getString("type")?.uppercase()?.let { TournamentType.valueOf(it) } ?: badRequest("missing type"),
|
type = json.getString("type")?.uppercase()?.let { Tournament.Type.valueOf(it) } ?: default?.type ?: badRequest("missing type"),
|
||||||
name = json.getString("name") ?: ApiHandler.badRequest("missing name"),
|
name = json.getString("name") ?: default?.name ?: badRequest("missing name"),
|
||||||
shortName = json.getString("shortName") ?: ApiHandler.badRequest("missing shortName"),
|
shortName = json.getString("shortName") ?: default?.shortName ?: badRequest("missing shortName"),
|
||||||
startDate = json.getLocalDate("startDate") ?: ApiHandler.badRequest("missing startDate"),
|
startDate = json.getLocalDate("startDate") ?: default?.startDate ?: badRequest("missing startDate"),
|
||||||
endDate = json.getLocalDate("endDate") ?: ApiHandler.badRequest("missing endDate"),
|
endDate = json.getLocalDate("endDate") ?: default?.endDate ?: badRequest("missing endDate"),
|
||||||
country = json.getString("country") ?: ApiHandler.badRequest("missing country"),
|
country = json.getString("country") ?: default?.country ?: badRequest("missing country"),
|
||||||
location = json.getString("location") ?: ApiHandler.badRequest("missing location"),
|
location = json.getString("location") ?: default?.location ?: badRequest("missing location"),
|
||||||
online = json.getBoolean("online") ?: false,
|
online = json.getBoolean("online") ?: default?.online ?: false,
|
||||||
komi = json.getDouble("komi") ?: 7.5,
|
komi = json.getDouble("komi") ?: default?.komi ?: 7.5,
|
||||||
rules = json.getString("rules")?.let { Rules.valueOf(it) } ?: Rules.FRENCH,
|
rules = json.getString("rules")?.let { Rules.valueOf(it) } ?: default?.rules ?: Rules.FRENCH,
|
||||||
gobanSize = json.getInt("gobanSize") ?: 19,
|
gobanSize = json.getInt("gobanSize") ?: default?.gobanSize ?: 19,
|
||||||
timeSystem = TimeSystem.fromJson(json.getObject("timeSystem") ?: badRequest("missing timeSystem")),
|
timeSystem = json.getObject("timeSystem")?.let { TimeSystem.fromJson(it) } ?: default?.timeSystem ?: badRequest("missing timeSystem"),
|
||||||
pairing = MacMahon()
|
pairing = json.getObject("pairing")?.let { Pairing.fromJson(it) } ?: default?.pairing ?: badRequest("missing pairing")
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Tournament.toJson() = Json.Object(
|
fun Tournament.toJson() = Json.Object(
|
||||||
|
@@ -5,14 +5,19 @@ import org.jeudego.pairgoth.model.Tournament
|
|||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.math.E
|
import kotlin.math.E
|
||||||
|
|
||||||
|
// CB TODO - handle concurrency:
|
||||||
|
// - either with concurrent maps
|
||||||
|
// - or with a thread isolation (better, covers more operations)
|
||||||
|
|
||||||
object Store {
|
object Store {
|
||||||
private val _nextTournamentId = AtomicInteger()
|
private val _nextTournamentId = AtomicInteger()
|
||||||
private val _nextPlayerId = AtomicInteger()
|
private val _nextPlayerId = AtomicInteger()
|
||||||
|
private val _nextGameId = AtomicInteger()
|
||||||
val nextTournamentId get() = _nextTournamentId.incrementAndGet()
|
val nextTournamentId get() = _nextTournamentId.incrementAndGet()
|
||||||
val nextPlayerId get() = _nextPlayerId.incrementAndGet()
|
val nextPlayerId get() = _nextPlayerId.incrementAndGet()
|
||||||
|
val nextGameId get() = _nextGameId.incrementAndGet()
|
||||||
|
|
||||||
private val tournaments = mutableMapOf<Int, Tournament>()
|
private val tournaments = mutableMapOf<Int, Tournament>()
|
||||||
private val players = mutableMapOf<Int, Player>()
|
|
||||||
|
|
||||||
fun addTournament(tournament: Tournament) {
|
fun addTournament(tournament: Tournament) {
|
||||||
if (tournaments.containsKey(tournament.id)) throw Error("tournament id #${tournament.id} already exists")
|
if (tournaments.containsKey(tournament.id)) throw Error("tournament id #${tournament.id} already exists")
|
||||||
@@ -23,12 +28,14 @@ object Store {
|
|||||||
|
|
||||||
fun getTournamentsIDs(): Set<Int> = tournaments.keys
|
fun getTournamentsIDs(): Set<Int> = tournaments.keys
|
||||||
|
|
||||||
fun addPlayer(player: Player) {
|
fun replaceTournament(tournament: Tournament) {
|
||||||
if (players.containsKey(player.id)) throw Error("player id #${player.id} already exists")
|
if (!tournaments.containsKey(tournament.id)) throw Error("tournament id #${tournament.id} not known")
|
||||||
players[player.id] = player
|
tournaments[tournament.id] = tournament
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPlayer(id: Int) = players[id]
|
fun deleteTournament(tournament: Tournament) {
|
||||||
|
if (!tournaments.containsKey(tournament.id)) throw Error("tournament id #${tournament.id} not known")
|
||||||
|
tournaments.remove(tournament.id)
|
||||||
|
|
||||||
fun getPlayersIDs(): Set<Int> = players.keys
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ package org.jeudego.pairgoth.web
|
|||||||
|
|
||||||
import com.republicate.kson.Json
|
import com.republicate.kson.Json
|
||||||
import org.jeudego.pairgoth.api.ApiHandler
|
import org.jeudego.pairgoth.api.ApiHandler
|
||||||
import org.jeudego.pairgoth.api.RegistrationHandler
|
import org.jeudego.pairgoth.api.PairingHandler
|
||||||
import org.jeudego.pairgoth.api.PlayerHandler
|
import org.jeudego.pairgoth.api.PlayerHandler
|
||||||
import org.jeudego.pairgoth.api.TournamentHandler
|
import org.jeudego.pairgoth.api.TournamentHandler
|
||||||
import org.jeudego.pairgoth.util.Colorizer.green
|
import org.jeudego.pairgoth.util.Colorizer.green
|
||||||
@@ -63,10 +63,11 @@ class ApiServlet : HttpServlet() {
|
|||||||
// choose handler
|
// choose handler
|
||||||
|
|
||||||
val handler = when (entity) {
|
val handler = when (entity) {
|
||||||
"tournament" ->
|
"tour" ->
|
||||||
when (subEntity) {
|
when (subEntity) {
|
||||||
null -> TournamentHandler
|
null -> TournamentHandler
|
||||||
"registration" -> RegistrationHandler
|
"part" -> PlayerHandler
|
||||||
|
"pair" -> PairingHandler
|
||||||
else -> ApiHandler.badRequest("unknown sub-entity: $subEntity")
|
else -> ApiHandler.badRequest("unknown sub-entity: $subEntity")
|
||||||
}
|
}
|
||||||
"player" -> PlayerHandler
|
"player" -> PlayerHandler
|
||||||
@@ -223,8 +224,8 @@ class ApiServlet : HttpServlet() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
protected var logger = LoggerFactory.getLogger("api")
|
private var logger = LoggerFactory.getLogger("api")
|
||||||
protected const val EXPECTED_CHARSET = "utf8"
|
private const val EXPECTED_CHARSET = "utf8"
|
||||||
const val AUTH_HEADER = "Authorization"
|
const val AUTH_HEADER = "Authorization"
|
||||||
const val AUTH_PREFIX = "Bearer"
|
const val AUTH_PREFIX = "Bearer"
|
||||||
private fun isJson(mimeType: String): Boolean {
|
private fun isJson(mimeType: String): Boolean {
|
||||||
|
Reference in New Issue
Block a user