From 338e41269aae4df71c6a030d18cd7b6e94e5e49c Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Wed, 11 Sep 2024 17:15:40 +0200 Subject: [PATCH] feat(cdp): braze template (#24886) --- frontend/public/services/braze.png | Bin 0 -> 10289 bytes posthog/cdp/templates/__init__.py | 2 + posthog/cdp/templates/braze/template_braze.py | 83 ++++++++++++++++++ .../templates/braze/test_template_braze.py | 48 ++++++++++ 4 files changed, 133 insertions(+) create mode 100644 frontend/public/services/braze.png create mode 100644 posthog/cdp/templates/braze/template_braze.py create mode 100644 posthog/cdp/templates/braze/test_template_braze.py diff --git a/frontend/public/services/braze.png b/frontend/public/services/braze.png new file mode 100644 index 0000000000000000000000000000000000000000..f354ab9c013d1de83903529a09713102bd82a68c GIT binary patch literal 10289 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 [{ + 'attributes': inputs.attributes, + 'events': [inputs.event] +}] + +let res := fetch(f'{inputs.brazeEndpoint}/users/track', { + 'method': 'POST', + 'headers': { + 'Authorization': f'Bearer {inputs.apiKey}', + 'Content-Type': 'application/json' + }, + 'body': getPayload() +}) + +if (res.status >= 200 and res.status < 300) { + print('Event sent successfully!') +} else { + throw Error(f'Error sending event: {res.status} {res.body}') +} +""".strip(), + inputs_schema=[ + { + "key": "brazeEndpoint", + "type": "choice", + "label": "Braze REST Endpoint", + "description": "The endpoint identifier where your Braze instance is located, see the docs here: https://www.braze.com/docs/api/basics", + "choices": [ + {"label": "US-01", "value": "https://rest.iad-01.braze.com"}, + {"label": "US-02", "value": "https://rest.iad-02.braze.com"}, + {"label": "US-03", "value": "https://rest.iad-03.braze.com"}, + {"label": "US-04", "value": "https://rest.iad-04.braze.com"}, + {"label": "US-05", "value": "https://rest.iad-05.braze.com"}, + {"label": "US-06", "value": "https://rest.iad-06.braze.com"}, + {"label": "US-08", "value": "https://rest.iad-08.braze.com"}, + {"label": "EU-01", "value": "https://rest.fra-01.braze.eu"}, + {"label": "EU-02", "value": "https://rest.fra-02.braze.eu"}, + ], + "default": "", + "secret": False, + "required": True, + }, + { + "key": "apiKey", + "type": "string", + "label": "Your Braze API Key", + "description": "See the docs here: https://www.braze.com/docs/api/api_key/", + "default": "", + "secret": True, + "required": True, + }, + { + "key": "attributes", + "type": "json", + "label": "Attributes to set", + "default": {"email": "{person.properties.email}"}, + "secret": False, + "required": True, + }, + { + "key": "event", + "type": "json", + "label": "Event payload", + "default": { + "properties": "{event.properties}", + "external_id": "{event.distinct_id}", + "name": "{event.name}", + "time": "{event.timestamp}", + }, + "secret": False, + "required": True, + }, + ], +) diff --git a/posthog/cdp/templates/braze/test_template_braze.py b/posthog/cdp/templates/braze/test_template_braze.py new file mode 100644 index 00000000000..1aa52d78269 --- /dev/null +++ b/posthog/cdp/templates/braze/test_template_braze.py @@ -0,0 +1,48 @@ +from freezegun import freeze_time +from posthog.cdp.templates.helpers import BaseHogFunctionTemplateTest +from posthog.cdp.templates.braze.template_braze import template as template_braze + + +class TestTemplateBraze(BaseHogFunctionTemplateTest): + template = template_braze + + @freeze_time("2024-04-16T12:34:51Z") + def test_function_works(self): + res = self.run_function( + inputs={ + "brazeEndpoint": "https://rest.fra-01.braze.eu", + "apiKey": "my_secret_key", + "attributes": {"email": "{person.properties.email}"}, + "event": { + "name": "{event.name}", + "time": "{event.timestamp}", + "properties": "{event.properties}", + "external_id": "{event.distinct_id}", + }, + } + ) + + assert res.result is None + assert self.get_mock_fetch_calls()[0] == ( + "https://rest.fra-01.braze.eu/users/track", + { + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer my_secret_key", + }, + "body": [ + { + "attributes": {"email": "{person.properties.email}"}, + "events": [ + { + "external_id": "{event.distinct_id}", + "name": "{event.name}", + "properties": "{event.properties}", + "time": "{event.timestamp}", + }, + ], + } + ], + "method": "POST", + }, + )