src/main/kotlin/de/uapcore/lightpit/AbstractServlet.kt

changeset 335
1eed60b779da
parent 298
1275eb652008
--- a/src/main/kotlin/de/uapcore/lightpit/AbstractServlet.kt	Sat Nov 09 10:54:57 2024 +0100
+++ b/src/main/kotlin/de/uapcore/lightpit/AbstractServlet.kt	Sat Nov 09 11:47:20 2024 +0100
@@ -33,12 +33,15 @@
 import jakarta.servlet.http.HttpServletRequest
 import jakarta.servlet.http.HttpServletResponse
 import java.sql.SQLException
+import java.time.ZoneId
 import java.util.*
 
 abstract class AbstractServlet : HttpServlet() {
 
     companion object {
+        const val COOKIE_MAX_AGE = 2592000 // 30 days
         const val LANGUAGE_COOKIE_NAME = "lpit_language"
+        const val TIMEZONE_COOKIE_NAME = "lpit_timezone"
     }
     
     protected val logger = MyLogger()
@@ -138,6 +141,18 @@
             logger.trace("Continuing session {0} with language {1}", session.id, sessionLocale)
         }
 
+        // determine the timezone
+        if (session.getAttribute(Constants.SESSION_ATTR_TIMEZONE) == null) {
+            // timezone selection stored in cookie
+            val cookieTimezone = cookieTimezone(http)
+
+            // if no cookie, fall back to server's timezone (the browser does not transmit one)
+            val timezone = cookieTimezone ?: ZoneId.systemDefault()
+
+            selectTimezone(http, timezone)
+            logger.debug("Timezone for session {0} set to {1}", session.id, timezone)
+        }
+
         // if this is an error path, bypass the normal flow
         if (fullPath.startsWith("/error/")) {
             http.styleSheets = listOf("error")
@@ -198,6 +213,23 @@
         http.request.cookies?.firstOrNull { c -> c.name == LANGUAGE_COOKIE_NAME }
             ?.runCatching {Locale.forLanguageTag(this.value)}?.getOrNull()
 
+    protected fun sessionLanguage(http: HttpRequest) = http.session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) as Locale
+
+    private fun cookieTimezone(http: HttpRequest): ZoneId? =
+        http.request.cookies?.firstOrNull { c -> c.name == TIMEZONE_COOKIE_NAME }
+            ?.runCatching { ZoneId.of(this.value)}?.getOrNull()
+
+    protected fun sessionTimezone(http: HttpRequest) = http.session.getAttribute(Constants.SESSION_ATTR_TIMEZONE) as String
+
+    protected fun selectTimezone(http: HttpRequest, zoneId: ZoneId) {
+        http.session.setAttribute(Constants.SESSION_ATTR_TIMEZONE, zoneId.id)
+        val cookie = Cookie(TIMEZONE_COOKIE_NAME, zoneId.id)
+        cookie.isHttpOnly = true
+        cookie.path = http.request.contextPath
+        cookie.maxAge = COOKIE_MAX_AGE
+        http.response.addCookie(cookie)
+    }
+
     protected fun selectLanguage(http: HttpRequest, locale: Locale) {
         http.response.locale = locale
         http.session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, locale)
@@ -209,7 +241,7 @@
             cookie.maxAge = 0
         } else {
             cookie.value = locale.language
-            cookie.maxAge = 2592000 // 30 days
+            cookie.maxAge = COOKIE_MAX_AGE
         }
         http.response.addCookie(cookie)
     }

mercurial