From 6e97c91b2fcd7c153be7dcc13316afbc4447697d Mon Sep 17 00:00:00 2001 From: Claude Brisson Date: Sat, 27 Jul 2024 15:53:41 +0200 Subject: [PATCH] Table numbers exclusion: handle saving --- .../jeudego/pairgoth/api/TournamentHandler.kt | 36 +++++++++++++------ .../org/jeudego/pairgoth/model/Tournament.kt | 24 +++++++------ view-webapp/src/main/sass/tour.scss | 4 +++ .../src/main/webapp/js/tour-pairing.inc.js | 31 ++++++++++++---- .../src/main/webapp/tour-pairing.inc.html | 8 +++++ 5 files changed, 77 insertions(+), 26 deletions(-) diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/TournamentHandler.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/TournamentHandler.kt index c11065f..d276ddc 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/TournamentHandler.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/TournamentHandler.kt @@ -67,24 +67,40 @@ object TournamentHandler: PairgothApiHandler { val payload = getObjectPayload(request) // 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) - // copy players, games, criteria (this copy should be provided by the Tournament class - CB TODO) - updated.players.putAll(tournament.players) - if (tournament is TeamTournament && updated is TeamTournament) { - updated.teams.putAll(tournament.teams) + // specific handling for 'excludeTables' + if (payload.containsKey("excludeTables")) { + val tablesExclusion = payload.getString("excludeTables") ?: badRequest("missing 'excludeTables'") + validateTablesExclusion(tablesExclusion) + val round = payload.getInt("round") ?: badRequest("missing 'round'") + while (tournament.tablesExclusion.size < round) tournament.tablesExclusion.add("") + tournament.tablesExclusion[round - 1] = tablesExclusion + tournament.dispatchEvent(TournamentUpdated, request, tournament.toJson()) + } else { + val updated = Tournament.fromJson(payload, tournament) + // copy players, games, criteria (this copy should be provided by the Tournament class - CB TODO) + updated.players.putAll(tournament.players) + if (tournament is TeamTournament && updated is TeamTournament) { + updated.teams.putAll(tournament.teams) + } + for (round in 1..tournament.lastRound()) updated.games(round).apply { + clear() + putAll(tournament.games(round)) + } + updated.dispatchEvent(TournamentUpdated, request, updated.toJson()) } - for (round in 1..tournament.lastRound()) updated.games(round).apply { - clear() - putAll(tournament.games(round)) - } - updated.dispatchEvent(TournamentUpdated, request, updated.toJson()) return Json.Object("success" to true) } + private fun validateTablesExclusion(exclusion: String) { + if (!tablesExclusionValidator.matches(exclusion)) badRequest("invalid tables exclusion pattern") + } + override fun delete(request: HttpServletRequest, response: HttpServletResponse): Json { val tournament = getTournament(request) getStore(request).deleteTournament(tournament) tournament.dispatchEvent(TournamentDeleted, request, Json.Object("id" to tournament.id)) return Json.Object("success" to true) } + + private val tablesExclusionValidator = Regex("^(?:(?:\\s+|,)*\\d+(?:-\\d+)?)*$") } diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt index f1b0c5e..d3304fa 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt @@ -6,8 +6,6 @@ import com.republicate.kson.toJsonArray //import kotlinx.datetime.LocalDate import java.time.LocalDate import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest -import org.jeudego.pairgoth.pairing.solver.MacMahonSolver -import org.jeudego.pairgoth.pairing.solver.SwissSolver import org.jeudego.pairgoth.store.nextPlayerId import org.jeudego.pairgoth.store.nextTournamentId import kotlin.math.max @@ -30,7 +28,8 @@ sealed class Tournament ( val pairing: Pairing, val rules: Rules = Rules.FRENCH, val gobanSize: Int = 19, - val komi: Double = 7.5 + val komi: Double = 7.5, + val tablesExclusion: MutableList = mutableListOf() ) { companion object {} enum class Type(val playersNumber: Int, val individual: Boolean = true) { @@ -170,8 +169,9 @@ class StandardTournament( pairing: Pairing, rules: Rules = Rules.FRENCH, gobanSize: Int = 19, - komi: Double = 7.5 -): Tournament(id, type, name, shortName, startDate, endDate, director, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi) { + komi: Double = 7.5, + tablesExclusion: MutableList = mutableListOf() +): Tournament(id, type, name, shortName, startDate, endDate, director, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi, tablesExclusion) { override val players get() = _pairables } @@ -192,8 +192,9 @@ class TeamTournament( pairing: Pairing, rules: Rules = Rules.FRENCH, gobanSize: Int = 19, - komi: Double = 7.5 -): Tournament(id, type, name, shortName, startDate, endDate, director, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi) { + komi: Double = 7.5, + tablesExclusion: MutableList = mutableListOf() +): Tournament(id, type, name, shortName, startDate, endDate, director, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi, tablesExclusion) { companion object { private val epsilon = 0.0001 } @@ -267,7 +268,8 @@ fun Tournament.Companion.fromJson(json: Json.Object, default: Tournament<*>? = n gobanSize = json.getInt("gobanSize") ?: default?.gobanSize ?: 19, timeSystem = json.getObject("timeSystem")?.let { TimeSystem.fromJson(it) } ?: default?.timeSystem ?: badRequest("missing timeSystem"), rounds = json.getInt("rounds") ?: default?.rounds ?: badRequest("missing rounds"), - pairing = json.getObject("pairing")?.let { Pairing.fromJson(it, default?.pairing) } ?: default?.pairing ?: badRequest("missing pairing") + pairing = json.getObject("pairing")?.let { Pairing.fromJson(it, default?.pairing) } ?: default?.pairing ?: badRequest("missing pairing"), + tablesExclusion = json.getArray("tablesExclusion")?.map { item -> item as String }?.toMutableList() ?: default?.tablesExclusion ?: mutableListOf() ) else TeamTournament( @@ -286,7 +288,8 @@ fun Tournament.Companion.fromJson(json: Json.Object, default: Tournament<*>? = n gobanSize = json.getInt("gobanSize") ?: default?.gobanSize ?: 19, timeSystem = json.getObject("timeSystem")?.let { TimeSystem.fromJson(it) } ?: default?.timeSystem ?: badRequest("missing timeSystem"), rounds = json.getInt("rounds") ?: default?.rounds ?: badRequest("missing rounds"), - pairing = json.getObject("pairing")?.let { Pairing.fromJson(it, default?.pairing) } ?: default?.pairing ?: badRequest("missing pairing") + pairing = json.getObject("pairing")?.let { Pairing.fromJson(it, default?.pairing) } ?: default?.pairing ?: badRequest("missing pairing"), + tablesExclusion = json.getArray("tablesExclusion")?.map { item -> item as String }?.toMutableList() ?: default?.tablesExclusion ?: mutableListOf() ) json.getArray("players")?.forEach { obj -> val pairable = obj as Json.Object @@ -326,7 +329,8 @@ fun Tournament<*>.toJson() = Json.MutableObject( "gobanSize" to gobanSize, "timeSystem" to timeSystem.toJson(), "rounds" to rounds, - "pairing" to pairing.toJson() + "pairing" to pairing.toJson(), + "tablesExclusion" to tablesExclusion.toJsonArray() ) fun Tournament<*>.toFullJson(): Json.Object { diff --git a/view-webapp/src/main/sass/tour.scss b/view-webapp/src/main/sass/tour.scss index d182047..deaf4cf 100644 --- a/view-webapp/src/main/sass/tour.scss +++ b/view-webapp/src/main/sass/tour.scss @@ -405,6 +405,10 @@ margin-top: 0.2em; } + .tables-exclusion { + margin-top: 0.2em; + } + /* results section */ #results-filter { diff --git a/view-webapp/src/main/webapp/js/tour-pairing.inc.js b/view-webapp/src/main/webapp/js/tour-pairing.inc.js index 381234d..4df7bcf 100644 --- a/view-webapp/src/main/webapp/js/tour-pairing.inc.js +++ b/view-webapp/src/main/webapp/js/tour-pairing.inc.js @@ -1,12 +1,31 @@ let focused = undefined; function pair(parts) { - api.postJson(`tour/${tour_id}/pair/${activeRound}`, parts) - .then(rst => { - if (rst !== 'error') { - document.location.reload(); - } - }); + + let doWork = () => { + api.postJson(`tour/${tour_id}/pair/${activeRound}`, parts) + .then(rst => { + if (rst !== 'error') { + document.location.reload(); + } + }); + } + + let tablesExclusionControl = $('#exclude-tables'); + let value = tablesExclusionControl[0].value; + let origValue = tablesExclusionControl.data('orig'); + if (value === origValue) { + // tables exclusion value did not change + doWork(); + } else { + // tables exclusion value has change, we must save it first + api.putJson(`tour/${tour_id}`, { round: activeRound, excludeTables: value }) + .then(rst => { + if (rst !== 'error') { + doWork(); + } + }); + } } function unpair(games) { diff --git a/view-webapp/src/main/webapp/tour-pairing.inc.html b/view-webapp/src/main/webapp/tour-pairing.inc.html index 685ecc4..14c317e 100644 --- a/view-webapp/src/main/webapp/tour-pairing.inc.html +++ b/view-webapp/src/main/webapp/tour-pairing.inc.html @@ -22,6 +22,14 @@
( $pairables.size() pairable, $games.size() games )
+
+#if($tour.tablesExclusion && $round <= $tour.tablesExclusion.size()) + #set($tablesExclusion = $!tour.tablesExclusion[$round - 1]) +#else + #set($tablesExclusion = '') +#end + Exclude table numbers: +