Skip to content

Commit

Permalink
feat(sprig): added user deletion support (#2886)
Browse files Browse the repository at this point in the history
* feat(sprig): added user deletion support

* chore: destination doc link added for reference

* chore: code review changes

* chore: code review changes
  • Loading branch information
mihir-4116 authored Jan 4, 2024
1 parent 8bf56cc commit e0c225d
Show file tree
Hide file tree
Showing 3 changed files with 375 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/v0/destinations/sprig/deleteUsers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const { NetworkError, ConfigurationError } = require('@rudderstack/integrations-lib');
const { httpPOST } = require('../../../adapters/network');
const {
processAxiosResponse,
getDynamicErrorType,
} = require('../../../adapters/utils/networkUtils');
const { isHttpStatusSuccess } = require('../../util');
const { executeCommonValidations } = require('../../util/regulation-api');
const tags = require('../../util/tags');
const { getUserIdBatches } = require('../../util/deleteUserUtils');
const { JSON_MIME_TYPE } = require('../../util/constant');

/**
* This function will help to delete the users one by one from the userAttributes array.
* @param {*} userAttributes Array of objects with userId, email and phone
* @param {*} config Destination.Config provided in dashboard
* @returns
*/
const userDeletionHandler = async (userAttributes, config) => {
const { apiKey } = config;

if (!apiKey) {
throw new ConfigurationError('Api Key is required for user deletion');
}

const endpoint = 'https://api.sprig.com/v2/purge/visitors';
const headers = {
Accept: JSON_MIME_TYPE,
'Content-Type': JSON_MIME_TYPE,
Authorization: `API-Key ${apiKey}`,
};
/**
* userIdBatches = [[u1,u2,u3,...batchSize],[u1,u2,u3,...batchSize]...]
* Ref doc : https://docs.sprig.com/reference/post-v2-purge-visitors-1
*/
const userIdBatches = getUserIdBatches(userAttributes, 100);
// Note: we will only get 400 status code when no user deletion is present for given userIds so we will not throw error in that case
// eslint-disable-next-line no-restricted-syntax
for (const curBatch of userIdBatches) {
// eslint-disable-next-line no-await-in-loop
const deletionResponse = await httpPOST(
endpoint,
{
userIds: curBatch,
},
{
headers,
},
{
destType: 'sprig',
feature: 'deleteUsers',
endpointPath: 'api.sprig.com/v2/purge/visitors',
},
);
const handledDelResponse = processAxiosResponse(deletionResponse);
if (!isHttpStatusSuccess(handledDelResponse.status) && handledDelResponse.status !== 400) {
throw new NetworkError(
'User deletion request failed',
handledDelResponse.status,
{
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(handledDelResponse.status),
},
handledDelResponse,
);
}
}

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 };
217 changes: 217 additions & 0 deletions test/integrations/destinations/sprig/deleteUsers/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
export const data = [
{
name: 'sprig',
description: 'Missing api key',
feature: 'userDeletion',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
destType: 'SPRIG',
userAttributes: [
{
userId: '1',
},
{
userId: '2',
},
],
config: {
apiKey: undefined,
},
},
],
},
},
output: {
response: {
status: 400,
body: [
{
statusCode: 400,
error: 'Api Key is required for user deletion',
},
],
},
},
},
{
name: 'sprig',
description: 'Invalid api key',
feature: 'userDeletion',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
destType: 'SPRIG',
userAttributes: [
{
userId: '1',
},
{
userId: '2',
},
],
config: {
apiKey: 'invalidApiKey',
},
},
],
},
},
output: {
response: {
status: 403,
body: [
{
statusCode: 403,
error: 'User deletion request failed',
},
],
},
},
},
{
name: 'sprig',
description: 'Too many requests',
feature: 'userDeletion',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
destType: 'SPRIG',
userAttributes: [
{
userId: '1',
},
{
userId: '2',
},
{
userId: '3',
},
{
userId: '4',
},
{
userId: '5',
},
{
userId: '6',
},
{
userId: '7',
},
{
userId: '8',
},
{
userId: '9',
},
{
userId: '10',
},
],
config: {
apiKey: 'testApiKey',
},
},
],
},
},
output: {
response: {
status: 429,
body: [
{
statusCode: 429,
error: 'User deletion request failed',
},
],
},
},
},
{
name: 'sprig',
description: 'Given userId is not present for user deletion',
feature: 'userDeletion',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
destType: 'SPRIG',
userAttributes: [
{
userId: '9',
},
],
config: {
apiKey: 'testApiKey',
},
},
],
},
},
output: {
response: {
status: 200,
body: [
{
statusCode: 200,
status: 'successful',
},
,
],
},
},
},
{
name: 'sprig',
description: 'Successful user deletion',
feature: 'userDeletion',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
destType: 'SPRIG',
userAttributes: [
{
userId: '1',
},
{
userId: '2',
},
{
userId: '3',
},
],
config: {
apiKey: 'testApiKey',
},
},
],
},
},
output: {
response: {
status: 200,
body: [
{
statusCode: 200,
status: 'successful',
},
],
},
},
},
];
79 changes: 79 additions & 0 deletions test/integrations/destinations/sprig/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const deleteNwData = [
{
httpReq: {
method: 'post',
url: 'https://api.sprig.com/v2/purge/visitors',
data: {
userIds: ['1', '2'],
},
headers: {
Accept: 'application/json',
Authorization: 'API-Key invalidApiKey',
'Content-Type': 'application/json',
},
},
httpRes: {
data: 'Forbidden',
status: 403,
},
},
{
httpReq: {
method: 'post',
url: 'https://api.sprig.com/v2/purge/visitors',
data: {
userIds: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],
},
headers: {
Accept: 'application/json',
Authorization: 'API-Key testApiKey',
'Content-Type': 'application/json',
},
},
httpRes: {
data: 'Your application has made too many requests in too short a time.',
status: 429,
},
},
{
httpReq: {
method: 'post',
url: 'https://api.sprig.com/v2/purge/visitors',
data: {
userIds: ['9'],
},
headers: {
Accept: 'application/json',
Authorization: 'API-Key testApiKey',
'Content-Type': 'application/json',
},
},
httpRes: {
data: {
error: 'User deletion request failed',
},
status: 400,
},
},
{
httpReq: {
method: 'post',
url: 'https://api.sprig.com/v2/purge/visitors',
data: {
userIds: ['1', '2', '3'],
},
headers: {
Accept: 'application/json',
Authorization: 'API-Key testApiKey',
'Content-Type': 'application/json',
},
},
httpRes: {
data: {
requestId: 'request_1',
},
status: 200,
},
},
];
export const networkCallsData = [...deleteNwData];

0 comments on commit e0c225d

Please sign in to comment.