Add CaptureTimezone plug to extract cf-timezone header

This commit is contained in:
Graham McIntire 2026-02-01 11:02:57 -06:00
parent 45f8bc7459
commit c4e8c70e7d
No known key found for this signature in database
2 changed files with 73 additions and 0 deletions

View file

@ -0,0 +1,25 @@
defmodule ToweropsWeb.Plugs.CaptureTimezone do
@moduledoc """
Captures the cf-timezone header from Cloudflare and stores it in session.
Cloudflare provides timezone detection via the cf-timezone header using
IANA timezone database format (e.g., "America/Chicago", "Europe/London").
Falls back to "UTC" if the header is not present (development, non-Cloudflare).
"""
import Plug.Conn
@doc false
def init(opts), do: opts
@doc false
def call(conn, _opts) do
timezone =
case get_req_header(conn, "cf-timezone") do
[tz] when is_binary(tz) and byte_size(tz) > 0 -> tz
_ -> "UTC"
end
put_session(conn, :detected_timezone, timezone)
end
end

View file

@ -0,0 +1,48 @@
defmodule ToweropsWeb.Plugs.CaptureTimezoneTest do
use ToweropsWeb.ConnCase, async: true
alias ToweropsWeb.Plugs.CaptureTimezone
describe "call/2" do
test "captures cf-timezone header and stores in session", %{conn: conn} do
conn =
conn
|> init_test_session(%{})
|> put_req_header("cf-timezone", "America/Chicago")
|> CaptureTimezone.call([])
assert get_session(conn, :detected_timezone) == "America/Chicago"
end
test "defaults to UTC when cf-timezone header is missing", %{conn: conn} do
conn =
conn
|> init_test_session(%{})
|> CaptureTimezone.call([])
assert get_session(conn, :detected_timezone) == "UTC"
end
test "defaults to UTC when cf-timezone header is empty", %{conn: conn} do
conn =
conn
|> init_test_session(%{})
|> put_req_header("cf-timezone", "")
|> CaptureTimezone.call([])
assert get_session(conn, :detected_timezone) == "UTC"
end
test "handles overridden timezone headers by taking last", %{conn: conn} do
# put_req_header replaces the header value, so the last one wins
conn =
conn
|> init_test_session(%{})
|> put_req_header("cf-timezone", "America/Chicago")
|> put_req_header("cf-timezone", "Europe/London")
|> CaptureTimezone.call([])
assert get_session(conn, :detected_timezone) == "Europe/London"
end
end
end