From d1c3d37a381b419bc8b3fa958a6ced224b6d5495 Mon Sep 17 00:00:00 2001 From: John Brandborg Date: Thu, 7 Nov 2024 12:51:45 +0100 Subject: [PATCH] Feature: Planhat Create Activity bulk mode --- docs/changelog.rst | 6 +++ src/cruds/__init__.py | 2 +- .../interfaces/planhat/configuration.yaml | 8 ++++ src/cruds/interfaces/planhat/logic.py | 32 ++++++++++------ tests/interfaces/test_planhat.py | 37 +++++++++++++++++++ 5 files changed, 73 insertions(+), 12 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 0c857ca..fd30161 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,12 @@ Changelog ========= +Release 1.3.9 (November 7, 2024) +-------------------------------- + +Features: + - Planhat Create Activity bulk mode to upload multiple entries in one request. + Release 1.3.8 (November 5, 2024) -------------------------------- diff --git a/src/cruds/__init__.py b/src/cruds/__init__.py index c2a0fee..b351fee 100644 --- a/src/cruds/__init__.py +++ b/src/cruds/__init__.py @@ -28,6 +28,6 @@ from .core import Client __author__: str = "John Brandborg" -__version__: str = "1.3.8" +__version__: str = "1.3.9" __all__: list = ["Client", "auth"] diff --git a/src/cruds/interfaces/planhat/configuration.yaml b/src/cruds/interfaces/planhat/configuration.yaml index e34012f..45e5102 100644 --- a/src/cruds/interfaces/planhat/configuration.yaml +++ b/src/cruds/interfaces/planhat/configuration.yaml @@ -230,6 +230,14 @@ api: uri: onjectives - name: user_activity + docstring: | + Keeping track of your endusers activity is an important part of the Customer Success + effort. The most obvious events are probably logins and page-views. Logins tend to be + fairly inaccurate since it depends a lot on user behavior, some people login and logout + a lot, others keep their sessions open. Page views is likely a better metric. Even though + page views have relatively weak correlation with the value created, it does give you a + general sense of activity level, and it’s great to understand when a given user/customer + was last active. methods: - create_activity - segment diff --git a/src/cruds/interfaces/planhat/logic.py b/src/cruds/interfaces/planhat/logic.py index 9fca44e..f89abce 100644 --- a/src/cruds/interfaces/planhat/logic.py +++ b/src/cruds/interfaces/planhat/logic.py @@ -83,7 +83,8 @@ def bulk_upsert_response_check(self) -> None: logger.info(f"{error['type']} check passed.") -def _sum_bulk_upsert_responses(self, total: dict, response: dict) -> None: +@staticmethod +def _sum_bulk_upsert_responses(total: dict, response: dict) -> None: """ Takes two Dictionaries and sums or extends the values in the response into the total using common keys. Only the first level is processed. @@ -103,7 +104,7 @@ def model_init(self, owner, uri) -> None: self._uri = uri -def create(self, data: dict) -> dict: +def create(self, data: Any) -> dict: """ To create an entry it's required define a name and a valid companyId. @@ -116,7 +117,7 @@ def create(self, data: dict) -> dict: def bulk_upsert( self, - data: Dict[Any, Any], + data: list, chunk_size=5000, ) -> Dict[str, Union[int, List[str]]]: """ @@ -152,7 +153,7 @@ def delete(self, identification: str) -> dict: return self._owner.client.delete(f"{self._uri}/{identification}") -def update(self, identification: str, data: dict) -> dict: +def update(self, identification: str, data: Any) -> dict: """ Updates an entry by PlanID, ExternalID or SourceID by prepending the id with either extid- or srcid-. @@ -293,31 +294,40 @@ def _get_all_data(self, uri, params, max_requests) -> Generator: ## User Activity - Analytics Endpoint -def bulk_insert_metrics(self, data: dict) -> dict: +def bulk_insert_metrics(self, data: Any) -> dict: """ - To push dimension data into Planhat it is required to specify the Tenant Token (tenantUUID) in - the request URL. This token is a simple uui identifier for your tenant and it can be found in - the Developer module under the Tokens section. + To push dimension data into Planhat it is required to specify the Tenant Token + (tenantUUID) in the request URL. This token is a simple uui identifier for your + tenant and it can be found in the Developer module under the Tokens section. """ return self._owner.client_analytics.create( f"{self._uri}/{self._owner.tenant_token}", data ) -def create_activity(self, data: dict) -> Union[Dict[Any, Any], bytes]: +def create_activity(self, data: Any, bulk=False) -> Union[Dict[Any, Any], bytes]: """ Creates user activity. Required data keys are email or externalId. Ensure you create the PlanHat instance with analytics set to True. To use this method you don't need an API auth token. Just supply the tenant_token instead. + + Parameters: + data (dict): Data to be serialed and deliveryed + bulk (bool): Use the bulk request rather than realtime + + Returns: + data (dict|bytes): Deserialed or byte data """ + bulk_path: str = "/bulk" if bulk is True else "" + return self._owner.client_analytics.create( - f"{self._uri}/{self._owner.tenant_token}", data + f"{self._uri}{bulk_path}/{self._owner.tenant_token}", data ) -def segment(self, data: dict) -> Union[Dict[Any, Any], bytes]: +def segment(self, data) -> Union[Dict[Any, Any], bytes]: """ Segment can be used to send User Events (user tracking data) to Planhat. Required data keys are type, and trait. trait is an object. diff --git a/tests/interfaces/test_planhat.py b/tests/interfaces/test_planhat.py index c235430..2075dcf 100644 --- a/tests/interfaces/test_planhat.py +++ b/tests/interfaces/test_planhat.py @@ -238,6 +238,18 @@ def test_Model_create(planhat_model): ) +def test__sum_bulk_upsert_response(planhat_model): + """ + Test that the new responses are summarized into the result + """ + result = {} + planhat_model._sum_bulk_upsert_responses(result, {"A": 3, "B": [1]}) + assert result == {"A": 3, "B": [1]} + + planhat_model._sum_bulk_upsert_responses(result, {"A": 8, "B": [3]}) + assert result == {"A": 11, "B": [1, 3]} + + def test_Model_bulk_upsert_results(planhat_model): """ Test the bulk upsert iterates over data and returns results @@ -620,6 +632,31 @@ def test_Model_create_activity(planhat_model): ) +def test_Model_create_activity_bulk(planhat_model): + """ + Test the create activity request to planhat + """ + + create_sample = json.loads("""\ + { + "email": "ivars@planhat.com", + "action": "Logged in", + "externalId": "ojpsoi57pzn", + "companyExternalId": "Planhat-81ock9l81wl", + "weight": 1, + "info": { + "index": 30, + "theme": "Blue" + } + } + """) + planhat_model.create_activity(data=create_sample, bulk=True) + + planhat_model._owner.client_analytics.create.assert_called_with( + f"planhat_model_uri/bulk/{TEST_TENANT_TOKEN}", create_sample + ) + + def test_Model_segment(planhat_model): """ Test the segment request to planhat