diff --git a/src/v0/destinations/iterable/deleteUsers.js b/src/v0/destinations/iterable/deleteUsers.js new file mode 100644 index 0000000000..834cccd4cb --- /dev/null +++ b/src/v0/destinations/iterable/deleteUsers.js @@ -0,0 +1,80 @@ +const { httpDELETE } = require('../../../adapters/network'); +const { processAxiosResponse } = require('../../../adapters/utils/networkUtils'); +const { isHttpStatusSuccess } = require('../../util'); +const { getDynamicErrorType } = require('../../../adapters/utils/networkUtils'); +const { NetworkError, ConfigurationError } = require('../../util/errorTypes'); +const { executeCommonValidations } = require('../../util/regulation-api'); +const tags = require('../../util/tags'); +const { JSON_MIME_TYPE } = require('../../util/constant'); + +// Ref-> https://developers.intercom.com/intercom-api-reference/v1.3/reference/permanently-delete-a-user +const userDeletionHandler = async (userAttributes, config) => { + if (!config) { + throw new ConfigurationError('Config for deletion not present'); + } + const { apiKey } = config; + if (!apiKey) { + throw new ConfigurationError('api key for deletion not present'); + } + const validUserIds = []; + userAttributes.forEach((userAttribute) => { + // Dropping the user if userId is not present + if (userAttribute.userId) { + validUserIds.push(userAttribute.userId); + } + }); + const failedUserDeletions = []; + await Promise.all( + validUserIds.map(async (uId) => { + const url = `https://api.iterable.com/api/users/byUserId/${uId}`; + const requestOptions = { + headers: { + 'Content-Type': JSON_MIME_TYPE, + api_key: apiKey, + }, + }; + const resp = await httpDELETE(url, requestOptions, { + destType: 'iterable', + feature: 'deleteUsers', + }); + const handledDelResponse = processAxiosResponse(resp); + if (!isHttpStatusSuccess(handledDelResponse.status) && handledDelResponse.status !== 404) { + if (handledDelResponse.status !== 400) { + // Generic errors such as invalid api key + throw new NetworkError( + `User deletion request failed : ${handledDelResponse.response.msg}`, + handledDelResponse.status, + { + [tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(handledDelResponse.status), + }, + handledDelResponse, + ); + } else { + // Specific errors such as user is not found + failedUserDeletions.push({ userId: uId, Reason: handledDelResponse.response.msg }); + } + } + }), + ); + + if (failedUserDeletions.length > 0) { + throw new NetworkError( + `User deletion request failed for userIds : ${JSON.stringify(failedUserDeletions)}`, + 400, + { + [tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(400), + }, + failedUserDeletions, + ); + } + + return { statusCode: 200, status: 'successful' }; +}; +const processDeleteUsers = async (event) => { + const { userAttributes, config } = event; + executeCommonValidations(userAttributes); + const resp = await userDeletionHandler(userAttributes, config); + return resp; +}; + +module.exports = { processDeleteUsers }; diff --git a/test/deleteUsers/data/iterable/handler_input.json b/test/deleteUsers/data/iterable/handler_input.json new file mode 100644 index 0000000000..8ebc859089 --- /dev/null +++ b/test/deleteUsers/data/iterable/handler_input.json @@ -0,0 +1,93 @@ +[ + { + "request": { + "body": [ + { + "destType": "ITERABLE", + "userAttributes": [ + { + "userId": "rudder1" + } + ] + } + ] + } + }, + { + "request": { + "body": [ + { + "destType": "ITERABLE", + "userAttributes": [ + { + "userId": "rudder2" + } + ], + "config": { + "apiToken": "dummyApiKey" + } + } + ] + } + }, + { + "request": { + "body": [ + { + "destType": "ITERABLE", + "userAttributes": [ + { + "userId": "rudder1" + }, + { + "userId": "rudder2" + } + ], + "config": { + "apiKey": "dummyApiKey" + } + } + ] + } + }, + { + "request": { + "body": [ + { + "destType": "ITERABLE", + "userAttributes": [ + { + "userId": "rudder3" + }, + { + "userId": "rudder4" + } + ], + "config": { + "apiKey": "invalidKey" + } + } + ] + } + }, + { + "request": { + "body": [ + { + "destType": "ITERABLE", + "userAttributes": [ + { + "userId": "rudder5" + }, + { + "userId": "rudder6" + } + ], + "config": { + "apiKey": "dummyApiKey" + } + } + ] + } + } +] diff --git a/test/deleteUsers/data/iterable/handler_output.json b/test/deleteUsers/data/iterable/handler_output.json new file mode 100644 index 0000000000..b053d04df4 --- /dev/null +++ b/test/deleteUsers/data/iterable/handler_output.json @@ -0,0 +1,32 @@ +[ + [ + { + "statusCode": 400, + "error": "Config for deletion not present" + } + ], + [ + { + "statusCode": 400, + "error": "api key for deletion not present" + } + ], + [ + { + "statusCode": 400, + "error": "User deletion request failed for userIds : [{\"userId\":\"rudder2\",\"Reason\":\"User does not exist. Email: UserId: rudder2\"}]" + } + ], + [ + { + "error": "User deletion request failed : Invalid API key", + "statusCode": 401 + } + ], + [ + { + "statusCode": 200, + "status": "successful" + } + ] +] diff --git a/test/deleteUsers/data/iterable/nw_client_data.json b/test/deleteUsers/data/iterable/nw_client_data.json new file mode 100644 index 0000000000..159c301b11 --- /dev/null +++ b/test/deleteUsers/data/iterable/nw_client_data.json @@ -0,0 +1,138 @@ +[ + [ + { + "type": "delete", + "reqParams": [ + "https://api.iterable.com/api/users/byUserId/rudder1", + {}, + { + "Accept": "application/json", + "api_key": "dummyApiKey" + } + ], + "response": { + "response": { + "data": { + "msg": "All users associated with rudder1 were successfully deleted", + "code": "Success", + "params": null + }, + "status": 200 + } + } + }, + { + "type": "delete", + "reqParams": [ + "https://api.iterable.com/api/users/byUserId/rudder2", + {}, + { + "Accept": "application/json", + "api_key": "dummyApiKey" + } + ], + "response": { + "response": { + "data": { + "msg": "User does not exist. Email: UserId: rudder2", + "code": "BadParams", + "params": null + }, + "status": 400 + } + } + } + ], + [ + { + "type": "delete", + "reqParams": [ + "https://api.iterable.com/api/users/byUserId/rudder3", + {}, + { + "Accept": "application/json", + "api_key": "invalidKey" + } + ], + "response": { + "response": { + "data": { + "msg": "Invalid API key", + "code": "Success", + "params": { + "endpoint": "/api/users/byUserId/rudder3" + } + }, + "status": 401 + } + } + }, + { + "type": "delete", + "reqParams": [ + "https://api.iterable.com/api/users/byUserId/rudder4", + {}, + { + "Accept": "application/json", + "api_key": "invalidKey" + } + ], + "response": { + "response": { + "data": { + "msg": "Invalid API key", + "code": "Success", + "params": { + "endpoint": "/api/users/byUserId/rudder3" + } + }, + "status": 401 + } + } + } + ], + [ + { + "type": "delete", + "reqParams": [ + "https://api.iterable.com/api/users/byUserId/rudder5", + {}, + { + "Accept": "application/json", + "api_key": "dummyApiKey" + } + ], + "response": { + "response": { + "data": { + "msg": "All users associated with rudder5 were successfully deleted", + "code": "Success", + "params": null + }, + "status": 200 + } + } + }, + { + "type": "delete", + "reqParams": [ + "https://api.iterable.com/api/users/byUserId/rudder6", + {}, + { + "Accept": "application/json", + "api_key": "dummyApiKey" + } + ], + "response": { + "response": { + "data": { + "msg": "All users associated with rudder6 were successfully deleted", + "code": "Success", + "params": null + }, + "status": 200 + } + } + } + ] +]