From 779dd7a7f796909f877df120aa2e682b60120c15 Mon Sep 17 00:00:00 2001 From: JS Date: Tue, 20 Oct 2026 21:34:11 +0800 Subject: [PATCH] feat(audit): expose journey_id filter in Traces.search() (#110) The audit server's /traces/search honours a journey_id query param (login-journey tag, campus#803, shipped in campus#812), but the Python client did not carry it, so library consumers could not filter by journey. Add the keyword-only journey_id filter to Traces.search(), passed through as a query value exactly like the other optional filters (omitted when None), documented in the docstring. --- campus_python/audit/v1/traces.py | 4 ++++ tests/unit/test_audit.py | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/campus_python/audit/v1/traces.py b/campus_python/audit/v1/traces.py index 1fc6984..8323648 100644 --- a/campus_python/audit/v1/traces.py +++ b/campus_python/audit/v1/traces.py @@ -92,6 +92,7 @@ def search( api_key_id: "str | None" = None, client_id: "str | None" = None, user_id: "str | None" = None, + journey_id: "str | None" = None, since: "str | None" = None, until: "str | None" = None, limit: "int | None" = None, @@ -105,6 +106,7 @@ def search( api_key_id: Filter by audit API key client_id: Filter by OAuth client user_id: Filter by user + journey_id: Filter by login-journey tag (campus#803) since, until, limit, cursor: As in list() Returns: @@ -121,6 +123,8 @@ def search( query["client_id"] = client_id if user_id is not None: query["user_id"] = user_id + if journey_id is not None: + query["journey_id"] = journey_id if since is not None: query["since"] = since if until is not None: diff --git a/tests/unit/test_audit.py b/tests/unit/test_audit.py index ad76110..d38958a 100644 --- a/tests/unit/test_audit.py +++ b/tests/unit/test_audit.py @@ -151,6 +151,19 @@ def test_search_gets_leaf_route_with_filters(self): query={"path": "/api/v1/timetable/", "status": 404}, ) + def test_search_sends_journey_id_when_given(self): + # journey_id rides as a query param like the other optional + # filters (#110); the exact-dict assertion above covers its + # omission when not passed. + self.client.get.return_value.json.return_value = { + "traces": [], "cursor": {"next": None, "has_more": False} + } + self.audit.traces.search(journey_id="uid-journey-abc123") + self.client.get.assert_called_once_with( + "/audit/v1/traces/search", + query={"journey_id": "uid-journey-abc123"}, + ) + def test_trace_get_returns_tree_envelope(self): self.client.get.return_value.json.return_value = { "trace_id": "a" * 32,