diff --git a/frontend/public/services/loops.png b/frontend/public/services/loops.png new file mode 100644 index 0000000000000..822763a10e108 Binary files /dev/null and b/frontend/public/services/loops.png differ diff --git a/posthog/cdp/templates/__init__.py b/posthog/cdp/templates/__init__.py index 32725b5a57367..f1f0243c08cd5 100644 --- a/posthog/cdp/templates/__init__.py +++ b/posthog/cdp/templates/__init__.py @@ -14,6 +14,7 @@ ) from .zapier.template_zapier import template as zapier from .mailgun.template_mailgun import template_mailgun_send_email as mailgun +from .loops.template_loops import template as loops from .rudderstack.template_rudderstack import template as rudderstack @@ -33,6 +34,7 @@ mailjet_update_contact_list, clearbit, mailgun, + loops, rudderstack, ] diff --git a/posthog/cdp/templates/loops/template_loops.py b/posthog/cdp/templates/loops/template_loops.py new file mode 100644 index 0000000000000..01230f7727328 --- /dev/null +++ b/posthog/cdp/templates/loops/template_loops.py @@ -0,0 +1,49 @@ +from posthog.cdp.templates.hog_function_template import HogFunctionTemplate + + +template: HogFunctionTemplate = HogFunctionTemplate( + status="beta", + id="template-loops", + name="Send events to Loops", + description="Passes PostHog events to Loops.so", + icon_url="/static/services/loops.png", + hog=""" +let apiKey := inputs.apiKey + +let payload := { + 'userId': event.distinct_id, + 'eventName': event.name == '$set' ? '$identify' : event.name, + 'email': person.properties.email +} +for (let key, value in person.properties) { + payload[key] := value +} +fetch('https://app.loops.so/api/v1/events/send', { + 'method': 'POST', + 'headers': { + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {apiKey}', + }, + 'body': payload +}) +""".strip(), + inputs_schema=[ + { + "key": "apiKey", + "type": "string", + "label": "Loops API Key", + "description": "Loops API Key", + "default": "", + "secret": True, + "required": True, + } + ], + 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/loops/test_template_loops.py b/posthog/cdp/templates/loops/test_template_loops.py new file mode 100644 index 0000000000000..c6d48b5228b14 --- /dev/null +++ b/posthog/cdp/templates/loops/test_template_loops.py @@ -0,0 +1,61 @@ +from inline_snapshot import snapshot +from posthog.cdp.templates.helpers import BaseHogFunctionTemplateTest +from posthog.cdp.templates.loops.template_loops import template as template_loops + + +class TestTemplateLoops(BaseHogFunctionTemplateTest): + template = template_loops + + def _inputs(self, **kwargs): + inputs = {"apiKey": "1cac089e00a708680bdb1ed9f082d5bf"} + inputs.update(kwargs) + return inputs + + def test_function_works(self): + self.run_function( + inputs=self._inputs(), + globals={ + "event": {"distinct_id": "66e614bd-d9f2-491e-9e2c-eeab3090f72f", "name": "$pageview"}, + "person": { + "properties": {"email": "max@posthog.com", "name": "Max", "company": "PostHog"}, + }, + }, + ) + + assert self.get_mock_fetch_calls()[0] == snapshot( + ( + "https://app.loops.so/api/v1/events/send", + { + "method": "POST", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer 1cac089e00a708680bdb1ed9f082d5bf", + }, + "body": { + "userId": "66e614bd-d9f2-491e-9e2c-eeab3090f72f", + "eventName": "$pageview", + "email": "max@posthog.com", + "name": "Max", + "company": "PostHog", + }, + }, + ) + ) + + def test_automatic_action_mapping(self): + for event_name, expected_action in [ + ("$identify", "$identify"), + ("$set", "$identify"), + ("$pageview", "$pageview"), + ("$create_alias", "$create_alias"), + ("$autocapture", "$autocapture"), + ("custom", "custom"), + ]: + self.run_function( + inputs=self._inputs(), + globals={ + "event": {"name": event_name, "properties": {"url": "https://example.com", "$browser": "Chrome"}}, + }, + ) + + assert self.get_mock_fetch_calls()[0][1]["body"]["eventName"] == expected_action diff --git a/posthog/hogql/transforms/test/__snapshots__/test_in_cohort.ambr b/posthog/hogql/transforms/test/__snapshots__/test_in_cohort.ambr index 66203f817267f..369f18ab9d118 100644 --- a/posthog/hogql/transforms/test/__snapshots__/test_in_cohort.ambr +++ b/posthog/hogql/transforms/test/__snapshots__/test_in_cohort.ambr @@ -31,7 +31,7 @@ FROM events LEFT JOIN ( SELECT person_static_cohort.person_id AS cohort_person_id, 1 AS matched, person_static_cohort.cohort_id AS cohort_id FROM person_static_cohort - WHERE and(equals(person_static_cohort.team_id, 420), in(person_static_cohort.cohort_id, [13]))) AS __in_cohort ON equals(__in_cohort.cohort_person_id, events.person_id) + WHERE and(equals(person_static_cohort.team_id, 420), in(person_static_cohort.cohort_id, [2]))) AS __in_cohort ON equals(__in_cohort.cohort_person_id, events.person_id) WHERE and(equals(events.team_id, 420), 1, ifNull(equals(__in_cohort.matched, 1), 0)) LIMIT 100 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1, format_csv_allow_double_quotes=0, max_ast_elements=4000000, max_expanded_ast_elements=4000000, max_bytes_before_external_group_by=0 @@ -42,7 +42,7 @@ FROM events LEFT JOIN ( SELECT person_id AS cohort_person_id, 1 AS matched, cohort_id FROM static_cohort_people - WHERE in(cohort_id, [13])) AS __in_cohort ON equals(__in_cohort.cohort_person_id, person_id) + WHERE in(cohort_id, [2])) AS __in_cohort ON equals(__in_cohort.cohort_person_id, person_id) WHERE and(1, equals(__in_cohort.matched, 1)) LIMIT 100 ''' @@ -55,7 +55,7 @@ FROM events LEFT JOIN ( SELECT person_static_cohort.person_id AS cohort_person_id, 1 AS matched, person_static_cohort.cohort_id AS cohort_id FROM person_static_cohort - WHERE and(equals(person_static_cohort.team_id, 420), in(person_static_cohort.cohort_id, [14]))) AS __in_cohort ON equals(__in_cohort.cohort_person_id, events.person_id) + WHERE and(equals(person_static_cohort.team_id, 420), in(person_static_cohort.cohort_id, [3]))) AS __in_cohort ON equals(__in_cohort.cohort_person_id, events.person_id) WHERE and(equals(events.team_id, 420), 1, ifNull(equals(__in_cohort.matched, 1), 0)) LIMIT 100 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1, format_csv_allow_double_quotes=0, max_ast_elements=4000000, max_expanded_ast_elements=4000000, max_bytes_before_external_group_by=0 @@ -66,7 +66,7 @@ FROM events LEFT JOIN ( SELECT person_id AS cohort_person_id, 1 AS matched, cohort_id FROM static_cohort_people - WHERE in(cohort_id, [14])) AS __in_cohort ON equals(__in_cohort.cohort_person_id, person_id) + WHERE in(cohort_id, [3])) AS __in_cohort ON equals(__in_cohort.cohort_person_id, person_id) WHERE and(1, equals(__in_cohort.matched, 1)) LIMIT 100 '''