From 04dfc707c7103fbe8f0c86156090201abc136486 Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Fri, 13 Oct 2023 16:37:09 +0100 Subject: [PATCH 1/2] VersionAnnotation now records user agent string For better audit purposes, we now record the user agent string in use when a new version is created. --- CHANGELOG.md | 1 + src/caselawclient/Client.py | 4 ++++ src/caselawclient/client_helpers/__init__.py | 16 ++++++++++++++++ tests/client/test_save_copy_delete_judgment.py | 11 ++++++++++- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1438b073..bd363324 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog 1.0.0]. - BREAKING: `VersionAnnotation` now requires a statement of if the action is automated or not - `VersionAnnotation` can now accept an optional dict of structured `payload` data +- `VersionAnnotation` can now record a user agent string ## [Release 16.0.0] diff --git a/src/caselawclient/Client.py b/src/caselawclient/Client.py index 52c690f8..c6b740fc 100644 --- a/src/caselawclient/Client.py +++ b/src/caselawclient/Client.py @@ -197,6 +197,7 @@ def __init__( self.session = requests.Session() self.session.auth = HTTPBasicAuth(username, password) self.session.headers.update({"User-Agent": user_agent}) + self.user_agent = user_agent def get_document_by_uri(self, uri: DocumentURIString) -> Document: document_type_class = self.get_document_type_from_uri(uri) @@ -468,6 +469,7 @@ def save_locked_judgment_xml( uri = self._format_uri_for_marklogic(judgment_uri) annotation.set_calling_function("save_locked_judgment_xml") + annotation.set_calling_agent(self.user_agent) vars: query_dicts.UpdateLockedJudgmentDict = { "uri": uri, @@ -497,6 +499,7 @@ def insert_document_xml( uri = self._format_uri_for_marklogic(document_uri) annotation.set_calling_function("insert_document_xml") + annotation.set_calling_agent(self.user_agent) vars: query_dicts.InsertDocumentDict = { "uri": uri, @@ -528,6 +531,7 @@ def update_document_xml( uri = self._format_uri_for_marklogic(document_uri) annotation.set_calling_function("update_document_xml") + annotation.set_calling_agent(self.user_agent) vars: query_dicts.UpdateDocumentDict = { "uri": uri, diff --git a/src/caselawclient/client_helpers/__init__.py b/src/caselawclient/client_helpers/__init__.py index b1b1bbba..2523550f 100644 --- a/src/caselawclient/client_helpers/__init__.py +++ b/src/caselawclient/client_helpers/__init__.py @@ -8,6 +8,7 @@ class AnnotationDataDict(TypedDict): type: str calling_function: str + calling_agent: str message: NotRequired[str] payload: NotRequired[dict[str, Any]] automated: bool @@ -57,21 +58,36 @@ def set_calling_function(self, calling_function: str) -> None: """ self.calling_function = calling_function + def set_calling_agent(self, calling_agent: str) -> None: + """ + Set the name of the calling agent for tracing purposes + + :param calling_agent: The name of the agent which is performing the database write + """ + self.calling_agent = calling_agent + @property def structured_annotation_dict(self) -> AnnotationDataDict: """ :return: A structured dict representing this `VersionAnnotation` :raises AttributeError: The name of the calling function has not been set; use `set_calling_function()` + :raises AttributeError: The name of the calling agent has not been set; use `set_calling_agent()` """ if not self.calling_function: raise AttributeError( "The name of the calling function has not been set; use set_calling_function()" ) + if not self.calling_agent: + raise AttributeError( + "The name of the calling agent has not been set; use set_calling_agent()" + ) + annotation_data: AnnotationDataDict = { "type": self.version_type.value, "calling_function": self.calling_function, + "calling_agent": self.calling_agent, "automated": self.automated, } diff --git a/tests/client/test_save_copy_delete_judgment.py b/tests/client/test_save_copy_delete_judgment.py index 883878b7..fab7498e 100644 --- a/tests/client/test_save_copy_delete_judgment.py +++ b/tests/client/test_save_copy_delete_judgment.py @@ -14,7 +14,13 @@ class TestSaveCopyDeleteJudgment(unittest.TestCase): def setUp(self): - self.client = MarklogicApiClient("", "", "", False) + self.client = MarklogicApiClient( + host="", + username="", + password="", + use_https=False, + user_agent="marklogic-api-client-test", + ) def test_update_document_xml(self): with patch.object(self.client, "eval") as mock_eval: @@ -28,6 +34,7 @@ def test_update_document_xml(self): { "type": "edit", "calling_function": "update_document_xml", + "calling_agent": "marklogic-api-client-test", "automated": False, "message": "test_update_document_xml", "payload": {"test_payload": True}, @@ -68,6 +75,7 @@ def test_save_locked_judgment_xml(self): { "type": "enrichment", "calling_function": "save_locked_judgment_xml", + "calling_agent": "marklogic-api-client-test", "automated": True, "message": "test_save_locked_judgment_xml", "payload": {"test_payload": True}, @@ -127,6 +135,7 @@ def test_insert_document_xml(self): { "type": "submission", "calling_function": "insert_document_xml", + "calling_agent": "marklogic-api-client-test", "automated": False, "message": "test_insert_document_xml", "payload": {"test_payload": True}, From 929de7d77274922df148ac27dda308b0fedef85c Mon Sep 17 00:00:00 2001 From: Nick Jackson Date: Fri, 13 Oct 2023 16:50:13 +0100 Subject: [PATCH 2/2] Add missing tests --- src/caselawclient/client_helpers/__init__.py | 3 + .../client_helpers/test_version_annotation.py | 57 ++++++++++++++++--- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/caselawclient/client_helpers/__init__.py b/src/caselawclient/client_helpers/__init__.py index 2523550f..d81d6e02 100644 --- a/src/caselawclient/client_helpers/__init__.py +++ b/src/caselawclient/client_helpers/__init__.py @@ -50,6 +50,9 @@ def __init__( self.message = message self.payload = payload + self.calling_function: Optional[str] = None + self.calling_agent: Optional[str] = None + def set_calling_function(self, calling_function: str) -> None: """ Set the name of the calling function for tracing purposes diff --git a/tests/client_helpers/test_version_annotation.py b/tests/client_helpers/test_version_annotation.py index 0ba1e1fb..de37204e 100644 --- a/tests/client_helpers/test_version_annotation.py +++ b/tests/client_helpers/test_version_annotation.py @@ -3,11 +3,54 @@ from caselawclient.client_helpers import VersionAnnotation, VersionType -class TestSaveCopyDeleteJudgment: +class TestVersionAnnotation: + def test_structured_annotation_dict_returns_expected_values(self): + annotation = VersionAnnotation( + VersionType.SUBMISSION, + message="test_structured_annotation_dict_returns_expected_values", + payload={"test_payload": True}, + automated=False, + ) + annotation.set_calling_agent("marklogic-api-client-test") + annotation.set_calling_function("update_xml") + + assert annotation.structured_annotation_dict == { + "automated": False, + "calling_agent": "marklogic-api-client-test", + "calling_function": "update_xml", + "message": "test_structured_annotation_dict_returns_expected_values", + "payload": {"test_payload": True}, + "type": "submission", + } + def test_structured_annotation_dict_raises_on_no_calling_function_name(self): - with pytest.raises(AttributeError): - VersionAnnotation( - VersionType.SUBMISSION, - message="test_structured_annotation_dict_raises_on_no_calling_function_name", - automated=False, - ).structured_annotation_dict + annotation = VersionAnnotation( + VersionType.SUBMISSION, + message="test_structured_annotation_dict_raises_on_no_calling_function_name", + automated=False, + ) + annotation.set_calling_agent("marklogic-api-client-test") + + with pytest.raises(AttributeError) as e: + annotation.structured_annotation_dict + + assert ( + str(e.value) + == "The name of the calling function has not been set; use set_calling_function()" + ) + + def test_structured_annotation_dict_raises_on_no_calling_agent(self): + annotation = VersionAnnotation( + VersionType.SUBMISSION, + message="test_structured_annotation_dict_raises_on_no_calling_agent", + automated=False, + ) + annotation.set_calling_function("update_xml") + + with pytest.raises(AttributeError) as e: + annotation.structured_annotation_dict + + assert ( + str(e.value) + == "The name of the calling agent has not been set; use set_calling_agent()" + )