Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Klaviyo Connector #2501

Merged
merged 12 commits into from
Apr 17, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The types of changes are:

### Added
- Access and erasure support for Aircall [#2589](https://github.com/ethyca/fides/pull/2589)
- Access and erasure support for Klaviyo [#2501](https://github.com/ethyca/fides/pull/2501)

### Changed
- The `cursor` pagination strategy now also searches for data outside of the `data_path` when determining the cursor value [#3068](https://github.com/ethyca/fides/pull/3068)
Expand Down
61 changes: 61 additions & 0 deletions data/saas/config/klaviyo_config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
saas_config:
fides_key: <instance_fides_key>
name: Klaviyo
type: klaviyo
description: A sample schema representing the Klaviyo connector for Fides
version: 0.1.0

connector_params:
- name: domain
default_value: a.klaviyo.com
- name: api_key
- name: revision
default_value: '2023-02-03'

client_config:
protocol: https
host: <domain>
authentication:
strategy: api_key
configuration:
headers:
- name: Authorization
value: Klaviyo-API-Key <api_key>
- name: revision
value: <revision>

test_request:
method: GET
path: /api/profiles

endpoints:
- name: profiles
requests:
read:
method: GET
path: /api/profiles
query_params:
- name: filter
value: 'equals(email,"<email>")'
data_path: data
param_values:
- name: email
identity: email
delete:
method: POST
path: /api/data-privacy-deletion-jobs
body: |
{
"data": {
"type": "data-privacy-deletion-job",
"attributes": {
"profile_id": "<profiles_id>"
}
}
}
param_values:
- name: profiles_id
references:
- dataset: <instance_fides_key>
field: profiles.id
direction: from
144 changes: 144 additions & 0 deletions data/saas/dataset/klaviyo_dataset.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
dataset:
- fides_key: <instance_fides_key>
name: Klaviyo Dataset
description: A sample dataset representing the Klaviyo connector for Fides
collections:
- name: profiles
fields:
- name: type
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: id
data_categories: [user.unique_id]
fidesops_meta:
primary_key: True
data_type: string
- name: attributes
fidesops_meta:
data_type: object
fields:
- name: email
data_categories: [user.contact.email]
fidesops_meta:
data_type: string
- name: phone_number
data_categories: [user.contact.phone_number]
fidesops_meta:
data_type: string
- name: external_id
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: anonymous_id
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: first_name
data_categories: [user.name]
fidesops_meta:
data_type: string
- name: last_name
data_categories: [user.name]
fidesops_meta:
data_type: string
- name: organization
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: title
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: image
- name: created
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: updated
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: last_event_date
- name: location
fidesops_meta:
data_type: object
fields:
- name: address1
data_categories: [user.contact.address.street]
fidesops_meta:
data_type: string
- name: address2
data_categories: [user.contact.address.street]
fidesops_meta:
data_type: string
- name: city
data_categories: [user.contact.address.city]
fidesops_meta:
data_type: string
- name: country
data_categories: [user.contact.address.country]
fidesops_meta:
data_type: string
- name: latitude
data_categories: [user.location]
fidesops_meta:
data_type: string
- name: longitude
data_categories: [user.location]
fidesops_meta:
data_type: string
- name: region
data_categories: [user.contact.address.state]
fidesops_meta:
data_type: string
- name: zip
data_categories: [user.contact.address.postal_code]
fidesops_meta:
data_type: string
- name: timezone
- name: properties
- name: links
fidesops_meta:
data_type: object
fields:
- name: self
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: relationships
fidesops_meta:
data_type: object
fields:
- name: lists
fidesops_meta:
data_type: object
fields:
- name: links
fidesops_meta:
data_type: object
fields:
- name: self
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: related
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: segments
fidesops_meta:
data_type: object
fields:
- name: links
fidesops_meta:
data_type: object
fields:
- name: self
data_categories: [system.operations]
fidesops_meta:
data_type: string
- name: related
data_categories: [system.operations]
fidesops_meta:
data_type: string
134 changes: 134 additions & 0 deletions tests/fixtures/saas/klaviyo_fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
from typing import Any, Dict, Generator

import pydash
import pytest
import requests
from sqlalchemy.orm import Session

from fides.api.ctl.sql_models import Dataset as CtlDataset
from fides.api.ops.models.connectionconfig import (
AccessLevel,
ConnectionConfig,
ConnectionType,
)
from fides.api.ops.models.datasetconfig import DatasetConfig
from fides.api.ops.util.saas_util import (
load_config_with_replacement,
load_dataset_with_replacement,
)
from fides.lib.cryptography import cryptographic_util
from tests.ops.test_helpers.saas_test_utils import poll_for_existence
from tests.ops.test_helpers.vault_client import get_secrets

secrets = get_secrets("klaviyo")


@pytest.fixture(scope="session")
def klaviyo_secrets(saas_config):
return {
"domain": pydash.get(saas_config, "klaviyo.domain") or secrets["domain"],
"api_key": pydash.get(saas_config, "klaviyo.api_key") or secrets["api_key"],
"revision": pydash.get(saas_config, "klaviyo.revision") or secrets["revision"]
}


@pytest.fixture(scope="session")
def klaviyo_identity_email(saas_config):
return (
pydash.get(saas_config, "klaviyo.identity_email") or secrets["identity_email"]
)


@pytest.fixture(scope="function")
def klaviyo_erasure_identity_email() -> str:
return f"{cryptographic_util.generate_secure_random_string(13)}@email.com"


@pytest.fixture
def klaviyo_config() -> Dict[str, Any]:
return load_config_with_replacement(
"data/saas/config/klaviyo_config.yml",
"<instance_fides_key>",
"klaviyo_instance",
)


@pytest.fixture
def klaviyo_dataset() -> Dict[str, Any]:
return load_dataset_with_replacement(
"data/saas/dataset/klaviyo_dataset.yml",
"<instance_fides_key>",
"klaviyo_instance",
)[0]


@pytest.fixture(scope="function")
def klaviyo_connection_config(
db: Session, klaviyo_config, klaviyo_secrets
) -> Generator:
fides_key = klaviyo_config["fides_key"]
connection_config = ConnectionConfig.create(
db=db,
data={
"key": fides_key,
"name": fides_key,
"connection_type": ConnectionType.saas,
"access": AccessLevel.write,
"secrets": klaviyo_secrets,
"saas_config": klaviyo_config,
},
)
yield connection_config
connection_config.delete(db)


@pytest.fixture
def klaviyo_dataset_config(
db: Session,
klaviyo_connection_config: ConnectionConfig,
klaviyo_dataset: Dict[str, Any],
) -> Generator:
fides_key = klaviyo_dataset["fides_key"]
klaviyo_connection_config.name = fides_key
klaviyo_connection_config.key = fides_key
klaviyo_connection_config.save(db=db)

ctl_dataset = CtlDataset.create_from_dataset_dict(db, klaviyo_dataset)

dataset = DatasetConfig.create(
db=db,
data={
"connection_config_id": klaviyo_connection_config.id,
"fides_key": fides_key,
"ctl_dataset_id": ctl_dataset.id,
},
)
yield dataset
dataset.delete(db=db)
ctl_dataset.delete(db=db)

@pytest.fixture(scope="function")
def klaviyo_create_erasure_data(
klaviyo_connection_config: ConnectionConfig, klaviyo_erasure_identity_email: str
) -> None:

klaviyo_secrets = klaviyo_connection_config.secrets
base_url = f"https://{klaviyo_secrets['domain']}"
headers = {
"Authorization": f"Klaviyo-API-Key {klaviyo_secrets['api_key']}",
"revision": klaviyo_secrets['revision']
}
# user
body = {
"data": {
"type": "profile",
"attributes": {
"email": klaviyo_erasure_identity_email
}
}
}

users_response = requests.post(url=f"{base_url}/api/profiles/", headers=headers, json=body)
user = users_response.json()

yield user
Loading