Skip to content

Commit

Permalink
feat(cdp): template migrations (#24940)
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusandra authored Sep 12, 2024
1 parent 51b77c5 commit 134833a
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 38 deletions.
6 changes: 4 additions & 2 deletions posthog/cdp/templates/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from .webhook.template_webhook import template as webhook
from .slack.template_slack import template as slack
from .hubspot.template_hubspot import template as hubspot
from .hubspot.template_hubspot import template as hubspot, TemplateHubspotMigrator
from .braze.template_braze import template as braze
from .customerio.template_customerio import template as customerio, TemplateCustomerioMigrator
from .intercom.template_intercom import template as intercom, TemplateIntercomMigrator
from .sendgrid.template_sendgrid import template as sendgrid, TemplateSendGridMigrator
from .clearbit.template_clearbit import template as clearbit
from .posthog.template_posthog import template as posthog
from .posthog.template_posthog import template as posthog, TemplatePostHogMigrator
from .aws_kinesis.template_aws_kinesis import template as aws_kinesis
from .salesforce.template_salesforce import template_create as salesforce_create, template_update as salesforce_update
from .mailjet.template_mailjet import (
Expand Down Expand Up @@ -62,6 +62,8 @@
TemplateSendGridMigrator.plugin_url: TemplateSendGridMigrator,
TemplateGooglePubSubMigrator.plugin_url: TemplateGooglePubSubMigrator,
TemplateGoogleCloudStorageMigrator.plugin_url: TemplateGoogleCloudStorageMigrator,
TemplatePostHogMigrator.plugin_url: TemplatePostHogMigrator,
TemplateHubspotMigrator.plugin_url: TemplateHubspotMigrator,
}

__all__ = ["HOG_FUNCTION_TEMPLATES", "HOG_FUNCTION_TEMPLATES_BY_ID"]
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from copy import deepcopy

from posthog.cdp.templates.hog_function_template import HogFunctionTemplate, HogFunctionTemplateMigrator
from posthog.hogql.escape_sql import escape_hogql_string
from posthog.models.integration import GoogleCloudIntegration

template: HogFunctionTemplate = HogFunctionTemplate(
Expand Down Expand Up @@ -70,7 +71,7 @@ class TemplateGoogleCloudStorageMigrator(HogFunctionTemplateMigrator):
def migrate(cls, obj):
hf = deepcopy(dataclasses.asdict(template))

exportEventsToIgnore = obj.config.get("exportEventsToIgnore", "")
exportEventsToIgnore = [x.strip() for x in obj.config.get("exportEventsToIgnore", "").split(",") if x]
bucketName = obj.config.get("bucketName", "")

from posthog.models.plugin import PluginAttachment
Expand All @@ -86,19 +87,17 @@ def migrate(cls, obj):

hf["filters"] = {}
if exportEventsToIgnore:
events = exportEventsToIgnore.split(",")
if len(events) > 0:
event_names = ", ".join(["'{}'".format(event.strip()) for event in events])
query = f"event not in ({event_names})"
hf["filters"]["events"] = [
{
"id": None,
"name": "All events",
"type": "events",
"order": 0,
"properties": [{"key": query, "type": "hogql"}],
}
]
event_names = ", ".join([escape_hogql_string(event) for event in exportEventsToIgnore])
query = f"event not in ({event_names})"
hf["filters"]["events"] = [
{
"id": None,
"name": "All events",
"type": "events",
"order": 0,
"properties": [{"key": query, "type": "hogql"}],
}
]

hf["inputs"] = {
"bucketName": {"value": bucketName},
Expand Down
27 changes: 13 additions & 14 deletions posthog/cdp/templates/google_pubsub/template_google_pubsub.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from copy import deepcopy

from posthog.cdp.templates.hog_function_template import HogFunctionTemplate, HogFunctionTemplateMigrator
from posthog.hogql.escape_sql import escape_hogql_string
from posthog.models.integration import GoogleCloudIntegration

template: HogFunctionTemplate = HogFunctionTemplate(
Expand Down Expand Up @@ -76,7 +77,7 @@ class TemplateGooglePubSubMigrator(HogFunctionTemplateMigrator):
def migrate(cls, obj):
hf = deepcopy(dataclasses.asdict(template))

exportEventsToIgnore = obj.config.get("exportEventsToIgnore", "")
exportEventsToIgnore = [x.strip() for x in obj.config.get("exportEventsToIgnore", "").split(",") if x]
topicId = obj.config.get("topicId", "")

from posthog.models.plugin import PluginAttachment
Expand All @@ -92,19 +93,17 @@ def migrate(cls, obj):

hf["filters"] = {}
if exportEventsToIgnore:
events = exportEventsToIgnore.split(",")
if len(events) > 0:
event_names = ", ".join(["'{}'".format(event.strip()) for event in events])
query = f"event not in ({event_names})"
hf["filters"]["events"] = [
{
"id": None,
"name": "All events",
"type": "events",
"order": 0,
"properties": [{"key": query, "type": "hogql"}],
}
]
event_names = ", ".join([escape_hogql_string(event) for event in exportEventsToIgnore])
query = f"event not in ({event_names})"
hf["filters"]["events"] = [
{
"id": None,
"name": "All events",
"type": "events",
"order": 0,
"properties": [{"key": query, "type": "hogql"}],
}
]

hf["inputs"] = {
"topicId": {"value": topicId},
Expand Down
78 changes: 74 additions & 4 deletions posthog/cdp/templates/hubspot/template_hubspot.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from posthog.cdp.templates.hog_function_template import HogFunctionTemplate
import dataclasses
from copy import deepcopy

from posthog.cdp.templates.hog_function_template import HogFunctionTemplate, HogFunctionTemplateMigrator


template: HogFunctionTemplate = HogFunctionTemplate(
Expand Down Expand Up @@ -76,12 +79,11 @@
"label": "Property mapping",
"description": "Map any event properties to Hubspot properties.",
"default": {
"name": "{person.properties.name}",
"firstname": "{person.properties.firstname}",
"lastname": "{person.properties.lastname}",
"company": "{person.properties.company}",
"phone": "{person.properties.phone}",
"website": "{person.properties.website}",
"domain": "{person.properties.website}",
"company_website": "{person.properties.website}",
},
"secret": False,
"required": True,
Expand All @@ -93,3 +95,71 @@
"filter_test_accounts": True,
},
)


class TemplateHubspotMigrator(HogFunctionTemplateMigrator):
plugin_url = "https://github.com/PostHog/hubspot-plugin"

@classmethod
def migrate(cls, obj):
hf = deepcopy(dataclasses.asdict(template))

# Must reauthenticate with HubSpot
hubspotAccessToken = obj.config.get("hubspotAccessToken", "")
triggeringEvents = [x.strip() for x in obj.config.get("triggeringEvents", "").split(",") if x]
additionalPropertyMappings = [
x.strip() for x in obj.config.get("additionalPropertyMappings", "").split(",") if x
]
ignoredEmails = [x.strip() for x in obj.config.get("ignoredEmails", "").split(",") if x]

hf["inputs_schema"][0] = {
"key": "access_token",
"type": "string",
"label": "Hubspot authorization token",
"secret": True,
"required": True,
}
hf["hog"] = hf["hog"].replace("inputs.oauth.access_token", "inputs.access_token")

hf["inputs"] = {
"access_token": {"value": hubspotAccessToken},
"email": {"value": "{person.properties.email}"},
"properties": {
"value": {
"firstname": "{person.properties.firstname ?? person.properties.firstName ?? person.properties.first_name}",
"lastname": "{person.properties.lastname ?? person.properties.lastName ?? person.properties.last_name}",
"company": "{person.properties.company ?? person.properties.companyName ?? person.properties.company_name}",
"phone": "{person.properties.phone ?? person.properties.phoneNumber ?? person.properties.phone_number}",
"website": "{person.properties.website ?? person.properties.companyWebsite ?? person.properties.company_website}",
}
},
}
for mapping in additionalPropertyMappings:
personPropertyName, hubSpotPropertyName = mapping.split(":")
hf["inputs"]["properties"]["value"][hubSpotPropertyName] = f"{{person.properties.{personPropertyName}}}"

hf["filters"] = {}

if ignoredEmails:
hf["filters"]["properties"] = [
{
"key": "email",
"value": domain,
"operator": "not_icontains",
"type": "person",
}
for domain in ignoredEmails
]

if triggeringEvents:
hf["filters"]["events"] = [
{
"id": event,
"name": event,
"type": "events",
"properties": [],
}
for event in triggeringEvents
]

return hf
50 changes: 49 additions & 1 deletion posthog/cdp/templates/hubspot/test_template_hubspot.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from inline_snapshot import snapshot

from posthog.cdp.templates.helpers import BaseHogFunctionTemplateTest
from posthog.cdp.templates.hubspot.template_hubspot import template as template_hubspot
from posthog.cdp.templates.hubspot.template_hubspot import template as template_hubspot, TemplateHubspotMigrator
from posthog.models import PluginConfig
from posthog.test.base import BaseTest


class TestTemplateHubspot(BaseHogFunctionTemplateTest):
Expand Down Expand Up @@ -82,3 +86,47 @@ def mock_fetch(*args):
"body": {"properties": {"company": "PostHog", "email": "[email protected]"}},
},
)


class TestTemplateMigration(BaseTest):
def get_plugin_config(self, config: dict):
_config = {
"hubspotAccessToken": "toky",
"triggeringEvents": "$identify,$set",
"additionalPropertyMappings": "a:b",
"ignoredEmails": "gmail.com",
}
_config.update(config)
return PluginConfig(enabled=True, order=0, config=_config)

def test_default_config(self):
obj = self.get_plugin_config({})
template = TemplateHubspotMigrator.migrate(obj)
assert template["inputs"] == snapshot(
{
"access_token": {"value": "toky"},
"email": {"value": "{person.properties.email}"},
"properties": {
"value": {
"firstname": "{person.properties.firstname ?? person.properties.firstName ?? person.properties.first_name}",
"lastname": "{person.properties.lastname ?? person.properties.lastName ?? person.properties.last_name}",
"company": "{person.properties.company ?? person.properties.companyName ?? person.properties.company_name}",
"phone": "{person.properties.phone ?? person.properties.phoneNumber ?? person.properties.phone_number}",
"website": "{person.properties.website ?? person.properties.companyWebsite ?? person.properties.company_website}",
"b": "{person.properties.a}",
}
},
}
)
assert template["filters"] == {
"properties": [{"key": "email", "value": "gmail.com", "operator": "not_icontains", "type": "person"}],
"events": [
{"id": "$identify", "name": "$identify", "type": "events", "properties": []},
{"id": "$set", "name": "$set", "type": "events", "properties": []},
],
}
assert template["inputs_schema"][0]["key"] == "access_token"
assert template["inputs_schema"][0]["type"] == "string"
assert template["inputs_schema"][0]["secret"]
assert "inputs.oauth.access_token" not in template["hog"]
assert "inputs.access_token" in template["hog"]
43 changes: 41 additions & 2 deletions posthog/cdp/templates/posthog/template_posthog.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from posthog.cdp.templates.hog_function_template import HogFunctionTemplate
import dataclasses
from copy import deepcopy

from posthog.cdp.templates.hog_function_template import HogFunctionTemplate, HogFunctionTemplateMigrator
from posthog.hogql.escape_sql import escape_hogql_string

template: HogFunctionTemplate = HogFunctionTemplate(
status="beta",
Expand Down Expand Up @@ -38,7 +41,7 @@
"type": "string",
"label": "PostHog host",
"description": "For cloud accounts this is either https://us.i.posthog.com or https://eu.i.posthog.com",
"default": "https://us.posthog.com",
"default": "https://us.i.posthog.com",
"secret": False,
"required": True,
},
Expand Down Expand Up @@ -69,3 +72,39 @@
},
],
)


class TemplatePostHogMigrator(HogFunctionTemplateMigrator):
plugin_url = "https://github.com/PostHog/posthog-plugin-replicator"

@classmethod
def migrate(cls, obj):
hf = deepcopy(dataclasses.asdict(template))

host = obj.config.get("host", "")
project_api_key = obj.config.get("project_api_key", "")
# replication = obj.config.get("replication", "") # not used
events_to_ignore = [x.strip() for x in obj.config.get("events_to_ignore", "").split(",") if x]
disable_geoip = obj.config.get("disable_geoip", "No") == "Yes"

hf["inputs"] = {
"host": {"value": host},
"token": {"value": project_api_key},
"include_all_properties": {"value": True},
"properties": {"value": {"$geoip_disable": True} if disable_geoip else {}},
}

hf["filters"] = {}
if events_to_ignore:
event_names = ", ".join([escape_hogql_string(event) for event in events_to_ignore])
hf["filters"]["events"] = [
{
"id": None,
"name": "All events",
"type": "events",
"order": 0,
"properties": [{"type": "hogql", "key": f"event not in ({event_names})"}],
}
]

return hf
Loading

0 comments on commit 134833a

Please sign in to comment.