Skip to content

Commit

Permalink
[Klaviyo] |Add MultistatusResponse to RemoveProfile and RemoveProfile…
Browse files Browse the repository at this point in the history
…fromList (#2607)

* multistatus response to removeprofile and removeprofilefromlist

* Remove Batch Testcase

* Remove Comments

* updated unit test cases

* Pushed generated-types

* resolved conflicts , merged with main

---------

Co-authored-by: Gaurav Kochar <[email protected]>
  • Loading branch information
Innovative-GauravKochar and Gaurav Kochar authored Dec 12, 2024
1 parent 59fe0e6 commit 53ed4c4
Show file tree
Hide file tree
Showing 8 changed files with 733 additions and 777 deletions.

Large diffs are not rendered by default.

101 changes: 97 additions & 4 deletions packages/destination-actions/src/destinations/klaviyo/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import {
DynamicFieldResponse,
IntegrationError,
PayloadValidationError,
MultiStatusResponse,
JSONLikeObject,
HTTPError,
MultiStatusResponse,
ErrorCodes
} from '@segment/actions-core'
import { JSONLikeObject } from '@segment/actions-core'
import { API_URL, REVISION_DATE } from './config'
import { Settings } from './generated-types'
import {
Expand All @@ -29,9 +29,10 @@ import {
KlaviyoAPIErrorResponse
} from './types'
import { Payload } from './upsertProfile/generated-types'
import { Payload as RemoveProfilePayload } from './removeProfile/generated-types'
import { PhoneNumberUtil, PhoneNumberFormat } from 'google-libphonenumber'
import { Payload as TrackEventPayload } from './trackEvent/generated-types'
import dayjs from '../../lib/dayjs'
import { PhoneNumberUtil, PhoneNumberFormat } from 'google-libphonenumber'
import { Payload as AddProfileToListPayload } from './addProfileToList/generated-types'
import { eventBulkCreateRegex } from './properties'
import { ActionDestinationErrorResponseType } from '@segment/actions-core/destination-kittypes'
Expand Down Expand Up @@ -506,6 +507,98 @@ async function updateMultiStatusWithKlaviyoErrors(
})
}

export async function removeBulkProfilesFromList(request: RequestClient, payloads: RemoveProfilePayload[]) {
const multiStatusResponse = new MultiStatusResponse()

const { filteredPayloads, validPayloadIndicesBitmap } = validateAndPrepareRemoveBulkProfilePayloads(
payloads,
multiStatusResponse
)
// if there are no payloads with valid phone number/email/external_id, return multiStatusResponse
if (!filteredPayloads.length) {
return multiStatusResponse
}

const emails = extractField(filteredPayloads, 'email')
const externalIds = extractField(filteredPayloads, 'external_id')
const phoneNumbers = extractField(filteredPayloads, 'phone_number')

const listId = filteredPayloads[0]?.list_id as string

try {
const profileIds = await getProfiles(request, emails, externalIds, phoneNumbers)
let response = null
if (profileIds.length) {
response = await removeProfileFromList(request, profileIds, listId)
}
updateMultiStatusWithSuccessData(filteredPayloads, validPayloadIndicesBitmap, multiStatusResponse, response)
} catch (error) {
if (error instanceof HTTPError) {
await updateMultiStatusWithKlaviyoErrors(
payloads as object as JSONLikeObject[],
error,
multiStatusResponse,
validPayloadIndicesBitmap
)
} else {
throw error // Bubble up the error
}
}
return multiStatusResponse
}

function extractField(payloads: JSONLikeObject[], field: string): string[] {
return payloads.map((profile) => profile[field]).filter(Boolean) as string[]
}

function validateAndPrepareRemoveBulkProfilePayloads(
payloads: RemoveProfilePayload[],
multiStatusResponse: MultiStatusResponse
) {
const filteredPayloads: JSONLikeObject[] = []
const validPayloadIndicesBitmap: number[] = []

payloads.forEach((payload, originalBatchIndex) => {
const { validPayload, error } = validateAndConstructRemoveProfilePayloads(payload)
if (error) {
multiStatusResponse.setErrorResponseAtIndex(originalBatchIndex, error)
} else {
filteredPayloads.push(validPayload as JSONLikeObject)
validPayloadIndicesBitmap.push(originalBatchIndex)
}
})
return { filteredPayloads, validPayloadIndicesBitmap }
}
function validateAndConstructRemoveProfilePayloads(payload: RemoveProfilePayload): {
validPayload?: JSONLikeObject
error?: ActionDestinationErrorResponseType
} {
const { phone_number, email, external_id } = payload
const response: { validPayload?: JSONLikeObject; error?: ActionDestinationErrorResponseType } = {}
if (!email && !phone_number && !external_id) {
response.error = {
status: 400,
errortype: 'PAYLOAD_VALIDATION_FAILED',
errormessage: 'One of External ID, Phone Number or Email is required.'
}
return response
}

if (phone_number) {
const validPhoneNumber = validateAndConvertPhoneNumber(phone_number, payload.country_code as string)
if (!validPhoneNumber) {
response.error = {
status: 400,
errortype: 'PAYLOAD_VALIDATION_FAILED',
errormessage: 'Phone number could not be converted to E.164 format.'
}
return response
}
payload.phone_number = validPhoneNumber
}
return { validPayload: payload as object as JSONLikeObject }
}

function validateAndConstructProfilePayload(payload: AddProfileToListPayload): {
validPayload?: JSONLikeObject
error?: ActionDestinationErrorResponseType
Expand Down Expand Up @@ -790,7 +883,7 @@ export function updateMultiStatusWithSuccessData(
multiStatusResponse.setSuccessResponseAtIndex(validPayloadIndicesBitmap[index], {
status: 200,
sent: payload,
body: JSON.stringify(response?.data)
body: JSON.stringify(response?.data) || 'success'
})
})
}
Loading

0 comments on commit 53ed4c4

Please sign in to comment.