From 0bf1ed1dab419aa14f0650a8cdcf204b26d89e49 Mon Sep 17 00:00:00 2001 From: Chris Bachhuber Date: Sat, 2 May 2026 07:09:27 +0200 Subject: [PATCH 1/5] feat: set cookie max age --- src/open_cups/app.py | 2 +- src/open_cups/session_state.py | 17 +++++++++++++---- src/open_cups/state_provider.py | 8 ++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/open_cups/app.py b/src/open_cups/app.py index ac4fc10..40112fb 100644 --- a/src/open_cups/app.py +++ b/src/open_cups/app.py @@ -259,7 +259,7 @@ def handle_question_submit() -> None: def run() -> None: st_autorefresh(interval=AUTOREFRESH_INTERVAL_MS, key="data_refresh") - state_provider = StateProvider() + state_provider = StateProvider(USER_REMOVAL_TIMEOUT_SECONDS) cleanup = state_provider.get_cleanup(USER_REMOVAL_TIMEOUT_SECONDS) cleanup.cleanup_all() diff --git a/src/open_cups/session_state.py b/src/open_cups/session_state.py index 626c159..b12c6ff 100644 --- a/src/open_cups/session_state.py +++ b/src/open_cups/session_state.py @@ -1,7 +1,9 @@ import uuid import streamlit as st +from streamlit.components.v1 import html as components_html +COOKIE_NAME = "OPEN_CUPS_SESSION_ID" class SessionState: """Per-user session state wrapper. @@ -10,11 +12,18 @@ class SessionState: for more details. """ - def __init__(self) -> None: + def __init__(self, user_removal_timeout: int) -> None: if "session_id" not in st.session_state: - existing = st.query_params.get("session_id") - st.session_state.session_id = existing or str(uuid.uuid4()) - st.query_params["session_id"] = st.session_state.session_id + session_id = st.context.cookies.get(COOKIE_NAME) + if session_id is None: + session_id = str(uuid.uuid4()) + components_html( + "", + height=0, + ) + st.session_state.session_id = session_id @property def session_id(self) -> str: diff --git a/src/open_cups/state_provider.py b/src/open_cups/state_provider.py index d93b0f3..3af3b93 100644 --- a/src/open_cups/state_provider.py +++ b/src/open_cups/state_provider.py @@ -103,9 +103,9 @@ def cleanup_all(self) -> None: class Context: - def __init__(self) -> None: + def __init__(self, user_removal_timeout: int) -> None: self.application_state: ApplicationState = self._get_application_state() - self.session_state = SessionState() + self.session_state = SessionState(user_removal_timeout=user_removal_timeout) @staticmethod @st.cache_resource @@ -114,8 +114,8 @@ def _get_application_state() -> ApplicationState: class StateProvider: - def __init__(self) -> None: - self.context = Context() + def __init__(self, user_removal_timeout: int) -> None: + self.context = Context(user_removal_timeout=user_removal_timeout) def get_cleanup(self, timeout_seconds: int) -> CleanupState: return CleanupState(self.context.application_state, timeout_seconds) From b195d4cec9c1bb2d3f154680978bc76ed684ac41 Mon Sep 17 00:00:00 2001 From: Chris Bachhuber Date: Sat, 2 May 2026 09:53:15 +0200 Subject: [PATCH 2/5] fix: prek --- src/open_cups/session_state.py | 3 ++- tests/bdd/fixture.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/open_cups/session_state.py b/src/open_cups/session_state.py index b12c6ff..fdced31 100644 --- a/src/open_cups/session_state.py +++ b/src/open_cups/session_state.py @@ -19,7 +19,8 @@ def __init__(self, user_removal_timeout: int) -> None: session_id = str(uuid.uuid4()) components_html( "", height=0, ) diff --git a/tests/bdd/fixture.py b/tests/bdd/fixture.py index fdb805e..7039ac4 100644 --- a/tests/bdd/fixture.py +++ b/tests/bdd/fixture.py @@ -59,8 +59,9 @@ def capture_wrapper( def capture_application_state(monkeypatch: pytest.MonkeyPatch) -> None: original_init = Context.__init__ - def wrapped_init(context: Context) -> None: - original_init(context) + def wrapped_init(context: Context, user_removal_timeout: int) -> None: + del user_removal_timeout + original_init(context, 9999) captured.application_state = context.application_state monkeypatch.setattr(Context, "__init__", wrapped_init) From 4144d3dfa7e27ee841a234fecfb0696e404fc81a Mon Sep 17 00:00:00 2001 From: Chris Bachhuber Date: Sat, 2 May 2026 09:55:36 +0200 Subject: [PATCH 3/5] simplify --- tests/bdd/fixture.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/bdd/fixture.py b/tests/bdd/fixture.py index 7039ac4..3c9afb8 100644 --- a/tests/bdd/fixture.py +++ b/tests/bdd/fixture.py @@ -60,8 +60,7 @@ def capture_application_state(monkeypatch: pytest.MonkeyPatch) -> None: original_init = Context.__init__ def wrapped_init(context: Context, user_removal_timeout: int) -> None: - del user_removal_timeout - original_init(context, 9999) + original_init(context, user_removal_timeout) captured.application_state = context.application_state monkeypatch.setattr(Context, "__init__", wrapped_init) From 6ae165c2bf338b3f0a3c00c1a2b08f11c7cd954c Mon Sep 17 00:00:00 2001 From: Chris Bachhuber Date: Mon, 11 May 2026 15:25:37 +0200 Subject: [PATCH 4/5] Update title to 'Welcome to branched OpenCups' --- src/open_cups/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/open_cups/app.py b/src/open_cups/app.py index 40112fb..4f66b59 100644 --- a/src/open_cups/app.py +++ b/src/open_cups/app.py @@ -32,7 +32,7 @@ def show_room_selection_screen(lobby: LobbyState) -> None: left, right = st.columns([2, 1]) with left: - st.title("Welcome to OpenCups") + st.title("Welcome to branched OpenCups") st.write("Host or join a room to share feedback.") with right: st.image("assets/logo.png", width="content") From f3705ae430e45f5d4a6d183258beeb70aefa6278 Mon Sep 17 00:00:00 2001 From: Chris Bachhuber Date: Sun, 31 May 2026 05:51:06 +0200 Subject: [PATCH 5/5] Exclude from coverage --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 9ba1e11..ea411eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,9 @@ dev = [ requires = ["hatchling"] build-backend = "hatchling.build" +[tool.coverage.run] +omit = ["src/open_cups/session_state.py"] # TODO (#165): Remove this omission if we stick with the cookies-based session state implementation + [tool.hatch.build.targets.wheel] packages = ["src/open_cups"]