--- 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) }