Skip to content

Commit 9f181d0

Browse files
authored
Update Rokt-Audiences Destination to support emailsha256 values (#2851)
* build: updates * fix: run yarn types * fix: build errors
1 parent fa3766f commit 9f181d0

File tree

5 files changed

+105
-17
lines changed

5 files changed

+105
-17
lines changed

packages/destination-actions/src/destinations/rokt-audiences/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ const destination: DestinationDefinition<Settings> = {
1212
description: `
1313
This destination allows user to engage audiences using Rokt's Public APIs.
1414
User can connect Rokt Audiences (Actions) as a destination to their Engage Audience in Segment,
15-
which will create/update custom audiences in the Rokt data platform.
15+
which will create/update custom audiences in the Rokt data platform. Audiences can be defined with either
16+
email values or hashed (sha256) email values.
1617
`,
1718
authentication: {
1819
scheme: 'custom',

packages/destination-actions/src/destinations/rokt-audiences/upsertCustomAudiences/__tests__/index.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,26 @@ const goodEvent = createTestEvent({
2525
}
2626
})
2727

28+
const goodEventHashedEmail = createTestEvent({
29+
context: {
30+
personas: {
31+
computation_class: 'audience',
32+
computation_key: 'aval_test_two_track_only'
33+
},
34+
traits: {
35+
email_sha256: 'd2a904f42a7f3632a0b9df96d33071b7ea31517d38fe3a8b1333f1ccec475f8c'
36+
}
37+
},
38+
traits: {
39+
email_sha256: 'd2a904f42a7f3632a0b9df96d33071b7ea31517d38fe3a8b1333f1ccec475f8c',
40+
aval_test_audience_for_chewy: true
41+
},
42+
properties: {
43+
audience_key: 'aval_test_two_track_only',
44+
aval_test_two_track_only: true
45+
}
46+
})
47+
2848
const badEvent = createTestEvent({
2949
context: {
3050
personas: {
@@ -56,6 +76,17 @@ describe('RoktAudiences.upsertCustomAudiences', () => {
5676
).resolves.not.toThrowError()
5777
})
5878

79+
it('should not throw an error if the audience creation succeed - hashed emails', async () => {
80+
nock(CONSTANTS.ROKT_API_BASE_URL).post(CONSTANTS.ROKT_API_CUSTOM_AUDIENCE_ENDPOINT).reply(201)
81+
82+
await expect(
83+
testDestination.testAction('upsertCustomAudiences', {
84+
event: goodEventHashedEmail,
85+
useDefaultMappings: true
86+
})
87+
).resolves.not.toThrowError()
88+
})
89+
5990
it('should throw an error if the audience creation failed, bad body', async () => {
6091
nock(CONSTANTS.ROKT_API_BASE_URL).post(CONSTANTS.ROKT_API_CUSTOM_AUDIENCE_ENDPOINT).reply(400)
6192

packages/destination-actions/src/destinations/rokt-audiences/upsertCustomAudiences/custom-audience-operations.ts

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ type CustomAudienceOperation = {
1616
action: string
1717
list: string
1818
emails: string[]
19+
sha256s: string[]
1920
}
2021

2122
/**
22-
* getCustomAudienceOperations parses event payloads from segment to convert to request object for Rokt api
23+
* getCustomAudienceOperations parses event payloads from segment to convert to request object for Rokt api.
24+
* Each audience receives its own pair of include and exclude lists.
2325
* @payload payload of events
2426
*/
25-
2627
const getCustomAudienceOperations = (payload: Payload[], settings: Settings): CustomAudienceOperation[] => {
28+
let is_hashed = false
29+
2730
// map to handle different audiences in the batch
2831
// this will contain audience_name=>[action=>emails]
2932
const audience_map = new Map<string, Map<string, string[]>>([])
@@ -49,11 +52,25 @@ const getCustomAudienceOperations = (payload: Payload[], settings: Settings): Cu
4952
}
5053

5154
if (p.traits_or_props[p.custom_audience_name] === true) {
52-
// audience entered 'true', include email to list
53-
action_map.get(CONSTANTS.INCLUDE)?.push(p.email)
55+
// audience entered 'true', include email or hashed email from list
56+
if (p.email_sha256 !== undefined) {
57+
action_map.get(CONSTANTS.INCLUDE)?.push(p.email_sha256)
58+
is_hashed = true
59+
} else {
60+
if (p.email !== undefined) {
61+
action_map.get(CONSTANTS.INCLUDE)?.push(p.email)
62+
}
63+
}
5464
} else if (p.traits_or_props[p.custom_audience_name] === false) {
55-
// audience entered 'false', exclude email from list
56-
action_map.get(CONSTANTS.EXCLUDE)?.push(p.email)
65+
// audience entered 'false', exclude email or hashed email from list
66+
if (p.email_sha256 !== undefined) {
67+
action_map.get(CONSTANTS.EXCLUDE)?.push(p.email_sha256)
68+
is_hashed = true
69+
} else {
70+
if (p.email !== undefined) {
71+
action_map.get(CONSTANTS.EXCLUDE)?.push(p.email)
72+
}
73+
}
5774
}
5875
}
5976

@@ -64,12 +81,25 @@ const getCustomAudienceOperations = (payload: Payload[], settings: Settings): Cu
6481
// key will be audience list
6582
// value will map of action=>email_list
6683
action_map_values.forEach((emails: string[], action: string) => {
67-
const custom_audience_op: CustomAudienceOperation = {
68-
accountId: settings.accountid,
69-
list: list,
70-
action: action,
71-
emails: emails
84+
let custom_audience_op: CustomAudienceOperation
85+
if (is_hashed) {
86+
custom_audience_op = {
87+
accountId: settings.accountid,
88+
list: list,
89+
action: action,
90+
emails: [],
91+
sha256s: emails
92+
}
93+
} else {
94+
custom_audience_op = {
95+
accountId: settings.accountid,
96+
list: list,
97+
action: action,
98+
emails: emails,
99+
sha256s: []
100+
}
72101
}
102+
73103
custom_audience_ops.push(custom_audience_op)
74104
})
75105
})
@@ -87,7 +117,7 @@ async function processPayload(request: RequestClient, settings: Settings, events
87117
const promises = []
88118

89119
for (const op of custom_audience_ops) {
90-
if (op.emails.length > 0) {
120+
if (op.emails.length > 0 || op.sha256s.length > 0) {
91121
// if emails are present for action, send to Rokt. Push to list of promises
92122
// There will be max 2 promises for 2 http requests ( include & exclude actions )
93123
promises.push(

packages/destination-actions/src/destinations/rokt-audiences/upsertCustomAudiences/generated-types.ts

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/destination-actions/src/destinations/rokt-audiences/upsertCustomAudiences/index.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ const action: ActionDefinition<Settings, Payload> = {
2929
},
3030
email: {
3131
label: 'Email',
32-
description: "User's email address for including/excluding from custom audience",
32+
description:
33+
"User's email address to be included/excluded from the custom audience. One of either email_sha256 or email must be specified.",
3334
type: 'string',
3435
format: 'email',
35-
required: true,
36+
required: {
37+
// If emailSHA256 is not provided then email is required
38+
conditions: [{ fieldKey: 'email_sha256', operator: 'is', value: undefined }]
39+
},
3640
default: {
3741
'@if': {
3842
exists: { '@path': '$.context.traits.email' },
@@ -41,6 +45,24 @@ const action: ActionDefinition<Settings, Payload> = {
4145
}
4246
}
4347
},
48+
email_sha256: {
49+
label: 'Email SHA256',
50+
description:
51+
"User's SHA256-hashed email address to be included/excluded from the custom audience. One of either email_sha256 or email must be specified.",
52+
type: 'string',
53+
format: 'text',
54+
required: {
55+
// If email is not provided then emailSHA256 is required
56+
conditions: [{ fieldKey: 'email', operator: 'is', value: undefined }]
57+
},
58+
default: {
59+
'@if': {
60+
exists: { '@path': '$.context.traits.email_sha256' },
61+
then: { '@path': '$.context.traits.email_sha256' },
62+
else: { '@path': '$.traits.email_sha256' }
63+
}
64+
}
65+
},
4466
traits_or_props: {
4567
label: 'traits or properties object',
4668
description: 'Object which will be computed differently for track and identify events',

0 commit comments

Comments
 (0)