Skip to content

Commit

Permalink
Adding extra match fields according to https://learn.microsoft.com/en…
Browse files Browse the repository at this point in the history
  • Loading branch information
seg-leonelsanches authored Feb 11, 2025
1 parent 9fb50e0 commit 91702fb
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { RequestClient, ModifiedResponse } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from '../updateAudience/generated-types'
import { BASE_URL, LINKEDIN_SOURCE_PLATFORM } from '../constants'
import type { ProfileAPIResponse, AdAccountUserResponse } from '../types'
import type { ProfileAPIResponse, AdAccountUserResponse, LinkedInAudiencePayload } from '../types'

export class LinkedInAudiences {
request: RequestClient
Expand Down Expand Up @@ -57,7 +57,7 @@ export class LinkedInAudiences {
})
}

async batchUpdate(dmpSegmentId: string, elements: Record<string, unknown>[]): Promise<ModifiedResponse> {
async batchUpdate(dmpSegmentId: string, elements: LinkedInAudiencePayload[]): Promise<ModifiedResponse> {
return this.request(`${BASE_URL}/dmpSegments/${dmpSegmentId}/users`, {
method: 'POST',
headers: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { DestinationDefinition } from '@segment/actions-core'
import { InvalidAuthenticationError } from '@segment/actions-core'
import https from 'https'

import type { DestinationDefinition, ModifiedResponse } from '@segment/actions-core'
import { InvalidAuthenticationError, IntegrationError, ErrorCodes } from '@segment/actions-core'

import type { Settings } from './generated-types'
import updateAudience from './updateAudience'
import { LINKEDIN_API_VERSION } from './constants'
import https from 'https'
import { LinkedInAudiences } from './api'
import type {
RefreshTokenResponse,
Expand All @@ -12,8 +14,6 @@ import type {
LinkedInRefreshTokenError,
LinkedInTestAuthenticationError
} from './types'
import type { ModifiedResponse } from '@segment/actions-core'
import { IntegrationError, ErrorCodes } from '@segment/actions-core'

const destination: DestinationDefinition<Settings> = {
// We need to match `name` with the creationName in the db. The name used in the UI is "LinkedIn Audiences".
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ export interface AdAccountUserResponse {
role: string
}

export interface LinkedInAudiencePayload {
action: 'ADD' | 'REMOVE'
userIds: Record<string, string>[]
firstName?: string
lastName?: string
title?: string
company?: string
country?: string
}

export class LinkedInRefreshTokenError extends HTTPError {
response: Response & {
data: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,59 @@ describe('LinkedinAudiences.updateAudience', () => {
'"{\\"elements\\":[{\\"action\\":\\"ADD\\",\\"userIds\\":[{\\"idType\\":\\"SHA256_EMAIL\\",\\"idValue\\":\\"584c4423c421df49955759498a71495aba49b8780eb9387dff333b6f0982c777\\"},{\\"idType\\":\\"GOOGLE_AID\\",\\"idValue\\":\\"123\\"}]}]}"'
)
})

it('Full payload', async () => {
const eventWithTraits = createTestEvent({
event: 'Audience Entered',
type: 'track',
properties: {
audience_key: 'personas_test_audience'
},
traits: {
email: '[email protected]',
firstName: 'John',
lastName: 'Doe',
title: 'CEO',
company: 'Acme',
country: 'US'
},
context: {
device: {
advertisingId: '123'
}
}
})

nock(`${BASE_URL}/dmpSegments`)
.get(/.*/)
.query(() => true)
.reply(200, { elements: [{ id: 'dmp_segment_id' }] })

nock(`${BASE_URL}/dmpSegments/dmp_segment_id/users`)
.post(/.*/, (body) => body.elements[0].action === 'ADD')
.reply(200)

const responses = await testDestination.testAction('updateAudience', {
event: eventWithTraits,
settings: {
ad_account_id: '123',
send_email: true,
send_google_advertising_id: true
},
useDefaultMappings: true,
auth,
mapping: {
personas_audience_key: 'personas_test_audience',
dmp_user_action: 'ADD'
}
})

expect(responses).toBeTruthy()
expect(responses).toHaveLength(2)
expect(responses[1].options.body).toMatchInlineSnapshot(
'"{\\"elements\\":[{\\"action\\":\\"ADD\\",\\"userIds\\":[{\\"idType\\":\\"SHA256_EMAIL\\",\\"idValue\\":\\"584c4423c421df49955759498a71495aba49b8780eb9387dff333b6f0982c777\\"},{\\"idType\\":\\"GOOGLE_AID\\",\\"idValue\\":\\"123\\"}],\\"firstName\\":\\"John\\",\\"lastName\\":\\"Doe\\",\\"title\\":\\"CEO\\",\\"company\\":\\"Acme\\",\\"country\\":\\"US\\"}]}"'
)
})
})

describe('Error cases', () => {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { RequestClient, RetryableError, IntegrationError, sha256SmartHash } from
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
import { LinkedInAudiences } from '../api'
import { LinkedInAudiencePayload } from '../types'

const action: ActionDefinition<Settings, Payload> = {
title: 'Sync To LinkedIn DMP Segment',
Expand Down Expand Up @@ -36,6 +37,47 @@ const action: ActionDefinition<Settings, Payload> = {
}
}
},
first_name: {
label: 'User First Name',
description: "The user's first name to send to LinkedIn.",
type: 'string',
default: {
'@path': '$.traits.firstName'
}
},
last_name: {
label: 'User Last Name',
description: "The user's last name to send to LinkedIn.",
type: 'string',
default: {
'@path': '$.traits.lastName'
}
},
title: {
label: 'User Title',
description: "The user's title to send to LinkedIn.",
type: 'string',
default: {
'@path': '$.traits.title'
}
},
company: {
label: 'User Company',
description: "The user's company to send to LinkedIn.",
type: 'string',
default: {
'@path': '$.traits.company'
}
},
country: {
label: 'User Country',
description:
"The user's country to send to LinkedIn. This field accepts an ISO standardized two letter country code e.g. US.",
type: 'string',
default: {
'@path': '$.traits.country'
}
},
google_advertising_id: {
label: 'User Google Advertising ID',
description: "The user's Google Advertising ID to send to LinkedIn.",
Expand Down Expand Up @@ -180,24 +222,46 @@ async function createDmpSegment(
return headers['x-linkedin-id']
}

function extractUsers(settings: Settings, payloads: Payload[]) {
const elements: Record<string, unknown>[] = []
function extractUsers(settings: Settings, payloads: Payload[]): LinkedInAudiencePayload[] {
const elements: LinkedInAudiencePayload[] = []

payloads.forEach((payload: Payload) => {
if (!payload.email && !payload.google_advertising_id) {
return
}

elements.push({
const linkedinAudiencePayload: LinkedInAudiencePayload = {
action: getAction(payload),
userIds: getUserIds(settings, payload)
})
}

if (payload.first_name) {
linkedinAudiencePayload.firstName = payload.first_name
}

if (payload.last_name) {
linkedinAudiencePayload.lastName = payload.last_name
}

if (payload.title) {
linkedinAudiencePayload.title = payload.title
}

if (payload.company) {
linkedinAudiencePayload.company = payload.company
}

if (payload.country) {
linkedinAudiencePayload.country = payload.country
}

elements.push(linkedinAudiencePayload)
})

return elements
}

function getAction(payload: Payload) {
function getAction(payload: Payload): 'ADD' | 'REMOVE' {
const { dmp_user_action = 'AUTO' } = payload

if (dmp_user_action === 'ADD') {
Expand All @@ -217,26 +281,28 @@ function getAction(payload: Payload) {
return 'REMOVE'
}
}

return 'ADD'
}

function getUserIds(settings: Settings, payload: Payload): Record<string, string>[] {
const users = []
const userIds = []

if (payload.email && settings.send_email === true) {
users.push({
userIds.push({
idType: 'SHA256_EMAIL',
idValue: sha256SmartHash(payload.email)
})
}

if (payload.google_advertising_id && settings.send_google_advertising_id === true) {
users.push({
userIds.push({
idType: 'GOOGLE_AID',
idValue: payload.google_advertising_id
})
}

return users
return userIds
}

export default action

0 comments on commit 91702fb

Please sign in to comment.