diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/StandingsHandler.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/StandingsHandler.kt index c9fa677..ad97f1c 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/StandingsHandler.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/StandingsHandler.kt @@ -23,6 +23,8 @@ import javax.servlet.http.HttpServletResponse import kotlin.math.max import kotlin.math.min import org.jeudego.pairgoth.model.TimeSystem.TimeSystemType.* +import java.io.OutputStreamWriter +import java.nio.charset.StandardCharsets import java.text.DecimalFormat object StandingsHandler: PairgothApiHandler { @@ -71,17 +73,29 @@ object StandingsHandler: PairgothApiHandler { } } } - val accept = request.getHeader("Accept")?.substringBefore(";") - return when(accept) { + val acceptHeader = request.getHeader("Accept") as String? + val accept = acceptHeader?.substringBefore(";") + val acceptEncoding = acceptHeader?.substringAfter(";charset=", "utf-8") ?: "utf-8" + val encoding = when (acceptEncoding) { + "utf-8" -> StandardCharsets.UTF_8 + "iso-8859-1" -> StandardCharsets.ISO_8859_1 + else -> ApiHandler.badRequest("unknown encoding in Accept header: $accept") + } + val writer by lazy { + PrintWriter(OutputStreamWriter(response.outputStream, encoding)) + } + return when (accept) { "application/json" -> sortedPairables.toJsonArray() "application/egf" -> { + response.contentType = "text/plain;charset=${encoding}" val neededCriteria = ArrayList(tournament.pairing.placementParams.criteria) if (!neededCriteria.contains(NBW)) neededCriteria.add(NBW) - exportToEGFFormat(tournament, sortedPairables, neededCriteria, response.writer) + exportToEGFFormat(tournament, sortedPairables, neededCriteria, writer) return null } "application/ffg" -> { - exportToFFGFormat(tournament, sortedPairables, response.writer) + response.contentType = "text/plain;charset=${encoding}" + exportToFFGFormat(tournament, sortedPairables, writer) return null } else -> ApiHandler.badRequest("invalid Accept header: $accept") @@ -159,7 +173,6 @@ ${ } private fun exportToFFGFormat(tournament: Tournament<*>, lines: List, writer: PrintWriter) { - // let's try in UTF-8 val ret = """;name=${tournament.shortName} ;date=${frDate.format(tournament.startDate)} diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/server/ApiServlet.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/server/ApiServlet.kt index d48013a..909895b 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/server/ApiServlet.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/server/ApiServlet.kt @@ -235,7 +235,7 @@ class ApiServlet: HttpServlet() { // 2) there will be other content types: .tou, .h9, .html if (!isJson(accept) && (!isXml(accept) || !request.requestURI.matches(Regex("/api/tour/\\d+"))) && - (accept != "application/ffg" && accept != "application/egf" || !request.requestURI.matches(Regex("/api/tour/\\d+/standings/\\d+"))) + (!accept.startsWith("application/ffg") && !accept.startsWith("application/egf") || !request.requestURI.matches(Regex("/api/tour/\\d+/standings/\\d+"))) ) throw ApiException( HttpServletResponse.SC_BAD_REQUEST, diff --git a/view-webapp/src/main/webapp/WEB-INF/translations/fr b/view-webapp/src/main/webapp/WEB-INF/translations/fr index b6061fd..689f8ab 100644 --- a/view-webapp/src/main/webapp/WEB-INF/translations/fr +++ b/view-webapp/src/main/webapp/WEB-INF/translations/fr @@ -32,6 +32,7 @@ Dates Dates Download Télécharger Download the standalone web interface module which suits your need, then follow Télécharger le module d’interface web qui correspond à vos besoins, puis suivez Edit Éditer +Encoding Encodage Enter the magic word Entrer le mot magique Export Exporter Export tournament Exporter le tournoi diff --git a/view-webapp/src/main/webapp/js/tour-standings.inc.js b/view-webapp/src/main/webapp/js/tour-standings.inc.js index b185732..51ea9a5 100644 --- a/view-webapp/src/main/webapp/js/tour-standings.inc.js +++ b/view-webapp/src/main/webapp/js/tour-standings.inc.js @@ -1,15 +1,18 @@ function publish(format, extension) { let form = $('#tournament-infos')[0]; let shortName = form.val('shortName'); + let encoding = $('#encoding')[0].value; let hdrs = headers(); - hdrs['Accept'] = `application/${format}` + hdrs['Accept'] = `application/${format};charset=${encoding}` fetch(`api/tour/${tour_id}/standings/${activeRound}`, { headers: hdrs }).then(resp => { - if (resp.ok) return resp.text() + if (resp.ok) return resp.arrayBuffer() else throw "publish error" - }).then(txt => { - let blob = new Blob(['\uFEFF', txt.trim()], {type: 'text/plain;charset=utf-8'}); + }).then(bytes => { + let blob = new Blob( + encoding === 'utf-8' ? ['\uFEFF', bytes] : [bytes], + { type: `text/plain;charset=${encoding}` }); downloadFile(blob, `${shortName}.${extension}`); close_modal(); }).catch(err => showError(err)); diff --git a/view-webapp/src/main/webapp/tour-standings.inc.html b/view-webapp/src/main/webapp/tour-standings.inc.html index 084485c..c16f18d 100644 --- a/view-webapp/src/main/webapp/tour-standings.inc.html +++ b/view-webapp/src/main/webapp/tour-standings.inc.html @@ -88,7 +88,10 @@
- +