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"] diff --git a/src/open_cups/app.py b/src/open_cups/app.py index ac4fc10..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") @@ -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..fdced31 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,19 @@ 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) diff --git a/tests/bdd/fixture.py b/tests/bdd/fixture.py index fdb805e..3c9afb8 100644 --- a/tests/bdd/fixture.py +++ b/tests/bdd/fixture.py @@ -59,8 +59,8 @@ 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: + original_init(context, user_removal_timeout) captured.application_state = context.application_state monkeypatch.setattr(Context, "__init__", wrapped_init)