Sanitize character set in ISO exports

This commit is contained in:
Claude Brisson
2024-08-20 15:33:37 +02:00
parent bae30c7465
commit 773b9b7b1e

View File

@@ -2,16 +2,13 @@ package org.jeudego.pairgoth.api
import com.republicate.kson.Json import com.republicate.kson.Json
import com.republicate.kson.toJsonArray import com.republicate.kson.toJsonArray
import org.jeudego.pairgoth.api.PairingHandler.dispatchEvent
import org.jeudego.pairgoth.model.Criterion import org.jeudego.pairgoth.model.Criterion
import org.jeudego.pairgoth.model.Criterion.* import org.jeudego.pairgoth.model.Criterion.*
import org.jeudego.pairgoth.model.Game.Result.*
import org.jeudego.pairgoth.model.ID import org.jeudego.pairgoth.model.ID
import org.jeudego.pairgoth.model.PairingType import org.jeudego.pairgoth.model.PairingType
import org.jeudego.pairgoth.model.Tournament import org.jeudego.pairgoth.model.Tournament
import org.jeudego.pairgoth.model.adjustedTime import org.jeudego.pairgoth.model.adjustedTime
import org.jeudego.pairgoth.model.displayRank import org.jeudego.pairgoth.model.displayRank
import org.jeudego.pairgoth.model.getID
import java.io.PrintWriter import java.io.PrintWriter
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletRequest
@@ -23,6 +20,9 @@ import org.jeudego.pairgoth.server.WebappManager
import java.io.OutputStreamWriter import java.io.OutputStreamWriter
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.Normalizer
import java.util.*
import kotlin.collections.ArrayList
object StandingsHandler: PairgothApiHandler { object StandingsHandler: PairgothApiHandler {
override fun get(request: HttpServletRequest, response: HttpServletResponse): Json? { override fun get(request: HttpServletRequest, response: HttpServletResponse): Json? {
@@ -31,7 +31,7 @@ object StandingsHandler: PairgothApiHandler {
val includePreliminary = request.getParameter("include_preliminary")?.let { it.toBoolean() } ?: false val includePreliminary = request.getParameter("include_preliminary")?.let { it.toBoolean() } ?: false
val sortedPairables = tournament.getSortedPairables(round, includePreliminary) val sortedPairables = tournament.getSortedPairables(round, includePreliminary)
tournament.populateResultsArray(sortedPairables, round) tournament.populateFrozenStandings(sortedPairables, round)
val acceptHeader = request.getHeader("Accept") as String? val acceptHeader = request.getHeader("Accept") as String?
val accept = acceptHeader?.substringBefore(";") val accept = acceptHeader?.substringBefore(";")
@@ -123,13 +123,18 @@ ${
"${ "${
player.getString("num")!!.padStart(4, ' ') player.getString("num")!!.padStart(4, ' ')
} ${ } ${
"${player.getString("name")} ${player.getString("firstname") ?: ""}".padEnd(30, ' ').take(30) "${
player.getString("name")?.toSnake(true)
} ${
player.getString("firstname")?.toSnake() ?: ""
}".padEnd(30, ' ').take(30)
} ${ } ${
displayRank(player.getInt("rank")!!).uppercase().padStart(3, ' ') displayRank(player.getInt("rank")!!).uppercase().padStart(3, ' ')
} ${ } ${
player.getString("country")?.uppercase() ?: "" player.getString("country")?.uppercase() ?: ""
} ${ } ${
(player.getString("club") ?: "").padStart(4).take(4) (player.getString("club") ?: "").toSnake().padStart(4).take(4)
} ${ } ${
criteria.joinToString(" ") { numFormat.format(player.getDouble(it.name)!!).let { if (it.contains('.')) it else "$it " }.padStart(7, ' ') } criteria.joinToString(" ") { numFormat.format(player.getDouble(it.name)!!).let { if (it.contains('.')) it else "$it " }.padStart(7, ' ') }
} ${ } ${
@@ -143,6 +148,24 @@ ${
writer.println(ret) writer.println(ret)
} }
private fun String.toSnake(upper: Boolean = false): String {
val sanitized = sanitizeISO()
val parts = sanitized.trim().split(Regex("(?:\\s|\\xA0)+"))
val snake = parts.joinToString("_") { part ->
if (upper) part.uppercase(Locale.ROOT)
else part.capitalize()
}
return snake
}
private fun String.sanitizeISO(): String {
val ret = Normalizer.normalize(this, Normalizer.Form.NFD)
return ret.replace(Regex("\\p{M}"), "")
// some non accented letters give problems in ISO, there may be other
.replace('Ð', 'D')
.replace('ø', 'o')
}
private fun exportToFFGFormat(tournament: Tournament<*>, lines: List<Json.Object>, writer: PrintWriter) { private fun exportToFFGFormat(tournament: Tournament<*>, lines: List<Json.Object>, writer: PrintWriter) {
val version = WebappManager.properties.getProperty("version")!! val version = WebappManager.properties.getProperty("version")!!
val ret = val ret =
@@ -171,14 +194,14 @@ ${
"${ "${
player.getString("num")!!.padStart(4, ' ') player.getString("num")!!.padStart(4, ' ')
} ${ } ${
"${player.getString("name")} ${player.getString("firstname") ?: ""}".padEnd(24, ' ').take(24) "${player.getString("name")?.toSnake(true)} ${player.getString("firstname")?.toSnake() ?: ""}".padEnd(24, ' ').take(24)
} ${ } ${
displayRank(player.getInt("rank")!!).uppercase().padStart(3, ' ') displayRank(player.getInt("rank")!!).uppercase().padStart(3, ' ')
} ${ } ${
player.getString("ffg") ?: " " player.getString("ffg") ?: " "
} ${ } ${
if (player.getString("country") == "FR") if (player.getString("country") == "FR")
(player.getString("club") ?: "").padEnd(4).take(4) (player.getString("club") ?: "").toSnake().padEnd(4).take(4)
else else
(player.getString("country") ?: "").padEnd(4).take(4) (player.getString("country") ?: "").padEnd(4).take(4)
} ${ } ${