Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DEV-2017] Resync user on active campaign #1269

Merged
merged 14 commits into from
Dec 18, 2024
Merged
5 changes: 5 additions & 0 deletions .changeset/cuddly-cats-retire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"active-campaign-client": minor
---

Add resync user handler
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { deleteContact } from '../helpers/deleteContact';
import { getUserFromCognitoUsername } from '../helpers/getUserFromCognito';
import { getSubscribedWebinars } from '../helpers/getSubscribedWebinars';
import { addContact } from '../helpers/addContact';
import { APIGatewayProxyResult, SQSEvent } from 'aws-lambda';
import { addContactToList } from '../helpers/manageListSubscription';
import { queueEventParser } from '../helpers/queueEventParser';

export async function resyncUserHandler(event: {
readonly Records: SQSEvent['Records'];
}): Promise<APIGatewayProxyResult> {
try {
const queueEvent = queueEventParser(event);
const cognitoUsername = queueEvent.detail.additionalEventData.sub;
const deletionResult = await deleteContact(cognitoUsername);
if (
deletionResult.statusCode !== 200 &&
deletionResult.statusCode !== 404
) {
// eslint-disable-next-line functional/no-throw-statements
throw new Error('Error adding contact');
}

const user = await getUserFromCognitoUsername(cognitoUsername);

if (!user) {
console.log(
`User: ${cognitoUsername} not present on Cognito, sync done.`
);
return {
statusCode: 200,
body: JSON.stringify({
message: 'User not present on Cognito, sync done.',
}),
};
}

const userWebinarsSubscriptions = await getSubscribedWebinars(
cognitoUsername
);

const webinarIds = JSON.parse(userWebinarsSubscriptions.body)
.map(
(webinar: { readonly webinarId: { readonly S: string } }) =>
webinar?.webinarId?.S
)
.filter(Boolean);

const res = await addContact(user);
if (res.statusCode !== 200) {
// eslint-disable-next-line functional/no-throw-statements
throw new Error('Error adding contact');
}

await webinarIds.reduce(
async (
prevPromise: Promise<APIGatewayProxyResult>,
webinarId: string
) => {
await prevPromise;
try {
const result = await addContactToList(cognitoUsername, webinarId);
console.log('Add contact to list result:', result, webinarId); // TODO: Remove after testing
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should remove the TODOs

await new Promise((resolve) => setTimeout(resolve, 1000)); // wait 1 sec to avoid rate limiting
} catch (e) {
console.error('Error adding contact to list', e); // TODO: Remove after testing
}
},
Promise.resolve()
);

return {
statusCode: 200,
body: JSON.stringify({ message: 'User resynced' }),
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ message: error }),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { DynamoDBClient, QueryCommand } from '@aws-sdk/client-dynamodb';
import { APIGatewayProxyResult } from 'aws-lambda';

export async function getSubscribedWebinars(
username: string
): Promise<APIGatewayProxyResult> {
try {
const dynamoClient = new DynamoDBClient({ region: process.env.AWS_REGION });
const command = new QueryCommand({
TableName: process.env.DYNAMO_WEBINARS_TABLE_NAME,
KeyConditionExpression: 'username = :username',
ExpressionAttributeValues: {
':username': { S: username },
},
});

const response = await dynamoClient.send(command);
console.log('getWebinarSubscriptions', response);
return {
statusCode: 200,
body: JSON.stringify(response.Items),
};
} catch (error) {
console.error('Error querying items by username:', error);
return {
statusCode: 500,
body: JSON.stringify({ message: 'Internal server error' }),
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@ import { QueueEvent } from '../types/queueEvent';
import { listUsersCommandOutputToUser } from './listUsersCommandOutputToUser';

export async function getUserFromCognito(queueEvent: QueueEvent) {
const username = queueEvent.detail.additionalEventData.sub;
const user = await getUserFromCognitoUsername(username);
if (!user) {
// eslint-disable-next-line functional/no-throw-statements
throw new Error('User not found');
}
return user;
}

export async function getUserFromCognitoUsername(username: string) {
const command = new ListUsersCommand({
UserPoolId: process.env.COGNITO_USER_POOL_ID,
Filter: `username = "${queueEvent.detail.additionalEventData.sub}"`,
Filter: `username = "${username}"`,
});
const listUsersCommandOutput = await cognitoClient.send(command);
const user = listUsersCommandOutputToUser(listUsersCommandOutput);
if (!user) {
// eslint-disable-next-line functional/no-throw-statements
throw new Error('User not found');
}
console.log('User:', JSON.stringify(user, null, 2)); // TODO: Remove after testing
return user;
}
7 changes: 7 additions & 0 deletions packages/active-campaign-client/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { SQSEvent } from 'aws-lambda';
import { sqsQueueHandler } from './handlers/sqsQueueHandler';
import { resyncUserHandler } from './handlers/resyncUserHandler';

export async function sqsQueue(event: {
readonly Records: SQSEvent['Records'];
}) {
return await sqsQueueHandler(event);
}

export async function resyncQueue(event: {
readonly Records: SQSEvent['Records'];
}) {
return await resyncUserHandler(event);
}
Loading