diff --git a/frontend/public/services/gleap.png b/frontend/public/services/gleap.png new file mode 100644 index 0000000000000..99eb242c9dc91 Binary files /dev/null and b/frontend/public/services/gleap.png differ 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...",)])