From a09635d10ad8668260de80652bf00e65dd479890 Mon Sep 17 00:00:00 2001 From: Marcus Hof <13001502+MarconLP@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:49:53 +0200 Subject: [PATCH] feat(cdp): add gleap.io hog function (#24884) --- frontend/public/services/gleap.png | Bin 0 -> 6044 bytes posthog/cdp/templates/__init__.py | 2 + posthog/cdp/templates/gleap/template_gleap.py | 91 ++++++++++++++++++ .../templates/gleap/test_template_gleap.py | 82 ++++++++++++++++ 4 files changed, 175 insertions(+) create mode 100644 frontend/public/services/gleap.png create mode 100644 posthog/cdp/templates/gleap/template_gleap.py create mode 100644 posthog/cdp/templates/gleap/test_template_gleap.py diff --git a/frontend/public/services/gleap.png b/frontend/public/services/gleap.png new file mode 100644 index 0000000000000000000000000000000000000000..99eb242c9dc91ad98fe6a2ab4985b390a9865232 GIT binary patch literal 6044 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 K|EGd-zW)dQ5B4Ge literal 0 HcmV?d00001 diff --git a/posthog/cdp/templates/__init__.py b/posthog/cdp/templates/__init__.py index 4edf9ca937ca8..3df8e99677965 100644 --- a/posthog/cdp/templates/__init__.py +++ b/posthog/cdp/templates/__init__.py @@ -17,6 +17,7 @@ from .avo.template_avo import template as avo from .loops.template_loops import template as loops from .rudderstack.template_rudderstack import template as rudderstack +from .gleap.template_gleap import template as gleap HOG_FUNCTION_TEMPLATES = [ @@ -38,6 +39,7 @@ loops, rudderstack, avo, + gleap, ] diff --git a/posthog/cdp/templates/gleap/template_gleap.py b/posthog/cdp/templates/gleap/template_gleap.py new file mode 100644 index 0000000000000..a177ce42ce90c --- /dev/null +++ b/posthog/cdp/templates/gleap/template_gleap.py @@ -0,0 +1,91 @@ +from posthog.cdp.templates.hog_function_template import HogFunctionTemplate + +template: HogFunctionTemplate = HogFunctionTemplate( + status="beta", + id="template-gleap", + name="Add contacts to Gleap", + description="Updates a contact in Gleap", + icon_url="/static/services/gleap.png", + hog=""" +let action := inputs.action +let name := event.name + +if (empty(inputs.userId)) { + print('No User ID set. Skipping...') + return +} + +let attributes := inputs.include_all_properties ? person.properties : {} + +attributes['userId'] := inputs.userId + +for (let key, value in inputs.attributes) { + if (not empty(value)) { + attributes[key] := value + } +} + +let res := fetch(f'https://api.gleap.io/admin/identify', { + 'method': 'POST', + 'headers': { + 'User-Agent': 'PostHog Gleap.io App', + 'Api-Token': inputs.apiKey, + 'Content-Type': 'application/json' + }, + 'body': attributes +}) + +if (res.status >= 400) { + print('Error from gleap.io api:', res.status, res.body) +} + +""".strip(), + inputs_schema=[ + { + "key": "apiKey", + "type": "string", + "label": "Gleap.io API Key", + "secret": True, + "required": True, + }, + { + "key": "userId", + "type": "string", + "label": "User ID", + "description": "You can choose to fill this from an `email` property or an `id` property. If the value is empty nothing will be sent. See here for more information: https://docs.gleap.io/server/rest-api", + "default": "{person.uuid}", + "secret": False, + "required": True, + }, + { + "key": "include_all_properties", + "type": "boolean", + "label": "Include all properties as attributes", + "description": "If set, all person properties will be included as attributes. Individual attributes can be overridden below.", + "default": False, + "secret": False, + "required": True, + }, + { + "key": "attributes", + "type": "dictionary", + "label": "Attribute mapping", + "description": "Map of Gleap.io attributes and their values. You can use the filters section to filter out unwanted events.", + "default": { + "email": "{person.properties.email}", + "name": "{person.properties.name}", + "phone": "{person.properties.phone}", + }, + "secret": False, + "required": False, + }, + ], + filters={ + "events": [ + {"id": "$identify", "name": "$identify", "type": "events", "order": 0}, + {"id": "$set", "name": "$set", "type": "events", "order": 1}, + ], + "actions": [], + "filter_test_accounts": True, + }, +) diff --git a/posthog/cdp/templates/gleap/test_template_gleap.py b/posthog/cdp/templates/gleap/test_template_gleap.py new file mode 100644 index 0000000000000..85769fad13fc1 --- /dev/null +++ b/posthog/cdp/templates/gleap/test_template_gleap.py @@ -0,0 +1,82 @@ +from inline_snapshot import snapshot +from posthog.cdp.templates.helpers import BaseHogFunctionTemplateTest +from posthog.cdp.templates.gleap.template_gleap import ( + template as template_gleap, +) + + +def create_inputs(**kwargs): + inputs = { + "apiKey": "uB6Jymn60NN5EEIWgiUzZx13geVlEx26", + "include_all_properties": False, + "userId": "edad9282-25d0-4cf1-af0e-415535ee1161", + "attributes": {"name": "example", "email": "example@posthog.com"}, + } + inputs.update(kwargs) + + return inputs + + +class TestTemplateGleap(BaseHogFunctionTemplateTest): + template = template_gleap + + def test_function_works(self): + self.run_function( + inputs=create_inputs(), + globals={ + "event": {"name": "$identify"}, + }, + ) + + assert self.get_mock_fetch_calls()[0] == snapshot( + ( + "https://api.gleap.io/admin/identify", + { + "method": "POST", + "headers": { + "User-Agent": "PostHog Gleap.io App", + "Api-Token": "uB6Jymn60NN5EEIWgiUzZx13geVlEx26", + "Content-Type": "application/json", + }, + "body": { + "userId": "edad9282-25d0-4cf1-af0e-415535ee1161", + "name": "example", + "email": "example@posthog.com", + }, + }, + ) + ) + + def test_body_includes_all_properties_if_set(self): + self.run_function( + inputs=create_inputs(include_all_properties=False), + globals={ + "person": {"properties": {"account_status": "paid"}}, + }, + ) + + assert self.get_mock_fetch_calls()[0][1]["body"] == snapshot( + {"userId": "edad9282-25d0-4cf1-af0e-415535ee1161", "name": "example", "email": "example@posthog.com"} + ) + + self.run_function( + inputs=create_inputs(include_all_properties=True), + globals={ + "person": {"properties": {"account_status": "paid"}}, + }, + ) + + assert self.get_mock_fetch_calls()[0][1]["body"] == snapshot( + { + "userId": "edad9282-25d0-4cf1-af0e-415535ee1161", + "account_status": "paid", + "name": "example", + "email": "example@posthog.com", + } + ) + + def test_function_requires_identifier(self): + self.run_function(inputs=create_inputs(userId="")) + + assert not self.get_mock_fetch_calls() + assert self.get_mock_print_calls() == snapshot([("No User ID set. Skipping...",)])