From 542057fec072cb5f2c303cef4b2e270c96e2c325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADn=20Alcaraz?= Date: Mon, 6 Nov 2023 17:55:31 -0800 Subject: [PATCH] wip --- packages/cli/src/lib/server.ts | 1 + .../addToAudience/generated-types.ts | 2 +- .../display-video-360/addToAudience/index.ts | 2 ++ .../display-video-360/listManagement.ts | 31 ++++++++++++++--- .../display-video-360/properties.ts | 15 +++++--- .../destinations/display-video-360/shared.ts | 34 +++++++++++++++---- .../destinations/display-video-360/types.ts | 22 +++++------- 7 files changed, 76 insertions(+), 31 deletions(-) diff --git a/packages/cli/src/lib/server.ts b/packages/cli/src/lib/server.ts index 7cc195ae96..83660d3e74 100644 --- a/packages/cli/src/lib/server.ts +++ b/packages/cli/src/lib/server.ts @@ -297,6 +297,7 @@ function setupRoutes(def: DestinationDefinition | null): void { if (Array.isArray(eventParams.data)) { // If no mapping or default mapping is provided, default to using the first payload across all events. eventParams.mapping = mapping || eventParams.data[0] || {} + eventParams.audienceSettings = req.body.payload[0]?.context?.personas?.audience_settings || {} await action.executeBatch(eventParams) } else { await action.execute(eventParams) diff --git a/packages/destination-actions/src/destinations/display-video-360/addToAudience/generated-types.ts b/packages/destination-actions/src/destinations/display-video-360/addToAudience/generated-types.ts index f542701d0d..9152279011 100644 --- a/packages/destination-actions/src/destinations/display-video-360/addToAudience/generated-types.ts +++ b/packages/destination-actions/src/destinations/display-video-360/addToAudience/generated-types.ts @@ -2,7 +2,7 @@ export interface Payload { /** - * The identifier for the user to add to the audience. + * The identifier for the user to add to the audience. Can only be one of the following. Basic User Lists only support Publisher Provided ID. Customer Match Lists support all four identifiers. */ user_identifier: string /** diff --git a/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts b/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts index df2b2ce9cb..7edbd1e5eb 100644 --- a/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts +++ b/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts @@ -16,6 +16,7 @@ const action: ActionDefinition = { external_audience_id: { ...external_audience_id } }, perform: async (request, { payload, audienceSettings, statsContext }) => { + console.log('Adding to the audience in regular') statsContext?.statsClient?.incr('addToAudience', 1, statsContext?.tags) if (!audienceSettings) { @@ -25,6 +26,7 @@ const action: ActionDefinition = { return handleUpdate(request, audienceSettings, [payload], 'add') }, performBatch: async (request, { payload, audienceSettings, statsContext }) => { + console.log('Adding to the audience in batch ') statsContext?.statsClient?.incr('addToAudience.batch', 1, statsContext?.tags) if (!audienceSettings) { diff --git a/packages/destination-actions/src/destinations/display-video-360/listManagement.ts b/packages/destination-actions/src/destinations/display-video-360/listManagement.ts index 916d915b9c..2cfb07f933 100644 --- a/packages/destination-actions/src/destinations/display-video-360/listManagement.ts +++ b/packages/destination-actions/src/destinations/display-video-360/listManagement.ts @@ -35,8 +35,30 @@ export const prepareOfflineDataJobCreationParams = (listType: string, listId: st } } +const getIdentifierKey = (key: string): string => { + let k = 'publisherProvidedId' + + switch (key) { + case 'email': + k = 'hashedEmail' + break + case 'phone': + k = 'hashedPhoneNumber' + break + case 'mobile': + k = 'mobileId' + break + } + + return k +} + // TODO: Implement operations for customerMatch list -export const buildAddListOperation = (payload: UpdateHandlerPayload, listType: string): ListAddOperation => { +export const buildAddListOperation = ( + payload: UpdateHandlerPayload, + listType: string, + key: string +): ListAddOperation => { let op: ListAddOperation = { create: { userIdentifiers: {} @@ -46,10 +68,11 @@ export const buildAddListOperation = (payload: UpdateHandlerPayload, listType: s switch (listType) { case 'basicUserList': op = op as BasicListAddTypeOperation - op.create.userIdentifiers['publisher_provided_id'] = payload?.user_identifier + op.create.userIdentifiers['publisherProvidedId'] = payload?.user_identifier break case 'customerMatchList': - // TODO: Implement this + // @ts-ignore TODO: Remove after testing + op.create.userIdentifiers[getIdentifierKey(key)] = payload?.user_identifier break default: throw new IntegrationError('Invalid list type', 'INVALID_REQUEST_DATA', 400) @@ -68,7 +91,7 @@ export const buildRemoveListOperation = (payload: UpdateHandlerPayload, listType switch (listType) { case 'basicUserList': op = op as BasicListRemoveTypeOperation - op.remove.userIdentifiers['publisher_provided_id'] = payload.user_identifier + op.remove.userIdentifiers['publisherProvidedId'] = payload.user_identifier break case 'customerMatchList': // TODO: Implement this diff --git a/packages/destination-actions/src/destinations/display-video-360/properties.ts b/packages/destination-actions/src/destinations/display-video-360/properties.ts index 331f343315..3e96add5cb 100644 --- a/packages/destination-actions/src/destinations/display-video-360/properties.ts +++ b/packages/destination-actions/src/destinations/display-video-360/properties.ts @@ -2,14 +2,19 @@ import { InputField } from '@segment/actions-core/destination-kit/types' export const user_identifier: InputField = { label: 'User Identifier', - description: 'The identifier for the user to add to the audience.', + description: + 'The identifier for the user to add to the audience. Can only be one of the following. Basic User Lists only support Publisher Provided ID. Customer Match Lists support all four identifiers.', type: 'string', required: true, - default: 'publisherProvidedId', choices: [ - { label: 'Publisher Provided ID', value: 'publisherProvidedId' }, - { label: 'Email', value: 'email' } - ] + { label: 'Publisher Provided ID', value: '$.anonymousId' }, + { label: 'Hashed Email', value: '$.email' }, + { label: 'Hashed Phone Number', value: '$.phoneNumber' }, + { label: 'Mobile ID', value: '$.context.device' } // TODO: Fix + ], + default: { + '@path': '$.anonymousId' + } } export const enable_batching: InputField = { diff --git a/packages/destination-actions/src/destinations/display-video-360/shared.ts b/packages/destination-actions/src/destinations/display-video-360/shared.ts index e6d30770a0..ce86509415 100644 --- a/packages/destination-actions/src/destinations/display-video-360/shared.ts +++ b/packages/destination-actions/src/destinations/display-video-360/shared.ts @@ -9,12 +9,16 @@ import { UpdateHandlerPayload, ListAddOperation, ListRemoveOperation, ListOperat const MULTI_STATUS_ERROR_CODES_ENABLED = true const createOfflineDataJob = async (request: RequestClient, audienceSettings: AudienceSettings, listId: string) => { - const advertiserDataJobUrl = OFFLINE_DATA_JOB_URL.replace('advertiserID', audienceSettings?.advertiserId) + const advertiserDataJobUrl = `${OFFLINE_DATA_JOB_URL.replace('advertiserID', audienceSettings?.advertiserId)}:create` const dataJobParams = prepareOfflineDataJobCreationParams(audienceSettings?.listType, listId) - const r = await request(`${advertiserDataJobUrl}:create`, { + const r = await request(advertiserDataJobUrl, { method: 'POST', - json: { - dataJobParams + json: dataJobParams, + headers: { + 'Content-Type': 'application/json', + // @ts-ignore -- TODO: Remove + Authorization: `Bearer ${audienceSettings?.authToken}`, + 'Login-Customer-Id': `products/DISPLAY_VIDEO_ADVERTISER/customers/${audienceSettings?.advertiserId}` } }) @@ -23,6 +27,8 @@ const createOfflineDataJob = async (request: RequestClient, audienceSettings: Au } const response = await r.json() + + // TODO: Consider caching this job ID for a period of time const jobId = response.resourceName.split('/').pop() if (!jobId) { @@ -37,7 +43,8 @@ const populateOfflineDataJob = async ( payload: UpdateHandlerPayload[], operation: ListOperation, jobId: string, - listType: string + listType: string, + audienceSettings: AudienceSettings ) => { const operations: ListAddOperation[] & ListRemoveOperation[] = [] payload.forEach((p) => { @@ -55,6 +62,12 @@ const populateOfflineDataJob = async ( json: { operations: operations, enablePartialFailure: MULTI_STATUS_ERROR_CODES_ENABLED + }, + headers: { + 'Content-Type': 'application/json', + // @ts-ignore -- TODO: Remove + Authorization: `Bearer ${audienceSettings?.authToken}`, + 'Login-Customer-Id': `products/DISPLAY_VIDEO_ADVERTISER/customers/${audienceSettings?.advertiserId}` } }) @@ -64,6 +77,7 @@ const populateOfflineDataJob = async ( } const performOfflineDataJob = async (request: RequestClient, jobId: string) => { + console.log('Running Datajob', jobId) const r = await request(`${OFFLINE_DATA_JOB_URL}/${jobId}:run`) if (r.status !== 200) { throw new Error(`Failed to run offline data job: ${r.text}`) @@ -82,11 +96,17 @@ export const handleUpdate = async ( jobId = await createOfflineDataJob(request, audienceSettings, payload[0]?.external_audience_id) } catch (error) { // Any error here would discard the entire batch, therefore, we shall retry everything. - throw new IntegrationError('Unable to create data job', 'RETRYABLE_ERROR', 500) + + if (error.response.status === 400) { + throw new IntegrationError(error.response.data.error.message, 'INTEGRATION_ERROR', 400) + } + + const errorMessage = JSON.parse(error.response.content).error.message + throw new IntegrationError(errorMessage, 'RETRYABLE_ERROR', 500) } try { - await populateOfflineDataJob(request, payload, operation, jobId, audienceSettings.listType) + await populateOfflineDataJob(request, payload, operation, jobId, audienceSettings.listType, audienceSettings) } catch (error) { // Any error here would discard the entire batch, therefore, we shall retry everything. throw new IntegrationError('Unable to populate data job', 'RETRYABLE_ERROR', 500) diff --git a/packages/destination-actions/src/destinations/display-video-360/types.ts b/packages/destination-actions/src/destinations/display-video-360/types.ts index 82820f8798..b067db5d31 100644 --- a/packages/destination-actions/src/destinations/display-video-360/types.ts +++ b/packages/destination-actions/src/destinations/display-video-360/types.ts @@ -11,7 +11,7 @@ export type BasicListTypeMap = export type BasicListAddTypeOperation = { create: { userIdentifiers: { - publisher_provided_id: string + publisherProvidedId: string } } } @@ -19,7 +19,7 @@ export type BasicListAddTypeOperation = { export type BasicListRemoveTypeOperation = { remove: { userIdentifiers: { - publisher_provided_id: string + publisherProvidedId: string } } } @@ -28,12 +28,9 @@ export type CustomerMatchAddListOperation = { create: { userIdentifiers: { hashedEmail?: string - addressInfo?: { - hashedFirstName: string - hashedLastName: string - countryCode: string - postalCode: string - } + hashedPhoneNumber?: string + mobileId?: string + publisherProvidedId?: string } } } @@ -42,12 +39,9 @@ export type CustomerMatchRemoveListOperation = { remove: { userIdentifiers: { hashedEmail?: string - addressInfo?: { - hashedFirstName: string - hashedLastName: string - countryCode: string - postalCode: string - } + hashedPhoneNumber?: string + mobileId?: string + publisherProvidedId?: string } } }