Skip to content

Commit

Permalink
[DEV-1980] Add user to active campaign (#1220)
Browse files Browse the repository at this point in the history
* add api signature for contacts

* add list management

* update package-lock

* add eslintrc.json

* update package.json and eslint

* migrate eslint

* fix issues with linting

* add changeset

* scaffold, and api calls

* add contact fix

* delete non add

* Create contact

* env example

* remove files

* Update packages/active-campaign-client/src/handlers/addContact.ts

Co-authored-by: Marco Ponchia <[email protected]>

* Update packages/active-campaign-client/src/activeCampaignClient.ts

Co-authored-by: Marco Ponchia <[email protected]>

* Update packages/active-campaign-client/src/__tests__/handlers/addContact.test.ts

Co-authored-by: Marco Ponchia <[email protected]>

* readme update

* changeset

* Update packages/active-campaign-client/src/__tests__/handlers/addContact.test.ts

Co-authored-by: Marco Ponchia <[email protected]>

* Update packages/active-campaign-client/src/handlers/addContact.ts

Co-authored-by: Marco Ponchia <[email protected]>

* Update .changeset/flat-walls-cough.md

Co-authored-by: marcobottaro <[email protected]>

* Update packages/active-campaign-client/src/activeCampaignClient.ts

Co-authored-by: marcobottaro <[email protected]>

* Update packages/active-campaign-client/.env.example

Co-authored-by: marcobottaro <[email protected]>

* Update packages/active-campaign-client/src/activeCampaign.ts

Co-authored-by: marcobottaro <[email protected]>

* Update packages/active-campaign-client/src/activeCampaign.ts

Co-authored-by: marcobottaro <[email protected]>

* Update packages/active-campaign-client/src/activeCampaign.ts

Co-authored-by: marcobottaro <[email protected]>

* Update packages/active-campaign-client/.env.example

Co-authored-by: marcobottaro <[email protected]>

* Pull request changes

* Pull request changes

* Pull request changes

---------

Co-authored-by: Marcello Bertoli <[email protected]>
Co-authored-by: t <[email protected]>
Co-authored-by: Marco Ponchia <[email protected]>
Co-authored-by: marcobottaro <[email protected]>
  • Loading branch information
5 people authored Nov 19, 2024
1 parent fe61351 commit 07703f2
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/flat-walls-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"active-campaign-client": minor
---

Add package setup and the lambda function to add user to Active Campaign
3 changes: 3 additions & 0 deletions packages/active-campaign-client/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
AC_BASE_URL=your_account_url
AC_API_KEY=your_api_key
SENDER_URL=localhost:3000
3 changes: 2 additions & 1 deletion packages/active-campaign-client/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"functional/no-expression-statements": "off",
"functional/no-this-expressions": "off",
"functional/no-classes": "off",
"functional/immutable-data": "off"
"functional/immutable-data": "off",
"functional/no-try-statements": "off"
}
}
6 changes: 6 additions & 0 deletions packages/active-campaign-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,9 @@ All requests require authentication using an API key. The key is passed in the h
'Content-Type': 'application/json'
}
```

# Tests

Since the client is a wrapper around the Active Campaign API, it is not possible to test the client without making actual requests to the API.
The tests are therefore integration tests that require a valid Active Campaign account and API key to run.
They are skipped by default but can be run by deleting the `.skip` from the test suite.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { handler } from '../../handlers/addContact';
import { SQSEvent } from 'aws-lambda';

// remove .skip to run the test, be aware it does a real API call so it will create a contact in the active campaign account
describe('addContact handler', () => {
it('should create a contact successfully', async () => {
const event: SQSEvent = {
Records: [
{
messageId: '1',
receiptHandle: '1',
body: JSON.stringify({
username: `test@example${new Date().getTime()}e.com`,
firstName: 'Giovanni',
lastName: 'Doe',
company: 'Test Co',
role: 'Developer',
mailinglistAccepted: true,
}),
attributes: {
ApproximateReceiveCount: '1',
SentTimestamp: '1',
SenderId: '1',
ApproximateFirstReceiveTimestamp: '1',
},
messageAttributes: {},
md5OfBody: '1',
eventSource: 'aws:sqs',
eventSourceARN: 'arn:aws:sqs:region:account-id:queue-name',
awsRegion: 'region',
},
],
};

const response = await handler(event);
expect(response.statusCode).toBe(200);
});
});
34 changes: 34 additions & 0 deletions packages/active-campaign-client/src/activeCampaignClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import axios from 'axios';
import * as dotenv from 'dotenv';
import { ContactPayload } from './types/contactPayload';

dotenv.config({ path: '.env' });

export class ActiveCampaignClient {
private readonly baseUrl: string;
private readonly apiKey: string;

constructor(baseUrl: string, apiKey: string) {
this.baseUrl = baseUrl;
this.apiKey = apiKey;
}

private getHeaders() {
return {
'Api-Token': this.apiKey,
'Content-Type': 'application/json',
};
}

async createContact(data: ContactPayload) {
const response = await axios.post(`${this.baseUrl}/api/3/contacts`, data, {
headers: this.getHeaders(),
});
return response.data;
}
}

export const acClient = new ActiveCampaignClient(
process.env.AC_BASE_URL!,

Check warning on line 32 in packages/active-campaign-client/src/activeCampaignClient.ts

View workflow job for this annotation

GitHub Actions / Update CHANGELOG

Forbidden non-null assertion
process.env.AC_API_KEY!

Check warning on line 33 in packages/active-campaign-client/src/activeCampaignClient.ts

View workflow job for this annotation

GitHub Actions / Update CHANGELOG

Forbidden non-null assertion
);
Empty file.
50 changes: 50 additions & 0 deletions packages/active-campaign-client/src/handlers/addContact.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { APIGatewayProxyResult, SQSEvent } from 'aws-lambda';
import { acClient } from '../activeCampaignClient';
import { SignUpUserData } from 'nextjs-website/src/lib/types/sign-up';
import { ContactPayload } from '../types/contactPayload';

export async function handler(event: {
readonly Records: SQSEvent['Records'];
}): Promise<APIGatewayProxyResult> {
try {
const firstMessage = event.Records[0] ?? { body: '{}' };
// Parse request body
const userData: SignUpUserData = JSON.parse(firstMessage.body);

// Transform to AC payload
const acPayload: ContactPayload = {
contact: {
email: userData.username,
firstName: userData.firstName,
lastName: userData.lastName,
fieldValues: [
{
field: '2',
value: userData.company,
},
{
field: '1',
value: userData.role,
},
{
field: '3',
value: userData.mailinglistAccepted ? 'TRUE' : 'FALSE',
},
],
},
};

const response = await acClient.createContact(acPayload);

return {
statusCode: 200,
body: JSON.stringify(response),
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
body: JSON.stringify({ message: 'Internal server error' }),
};
}
}
12 changes: 12 additions & 0 deletions packages/active-campaign-client/src/types/contactPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type ContactPayload = {
readonly contact: {
readonly email: string;
readonly firstName: string;
readonly lastName: string;
readonly phone?: string;
readonly fieldValues: readonly {
readonly field: string;
readonly value: string;
}[];
};
};
10 changes: 10 additions & 0 deletions packages/active-campaign-client/src/types/listPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type ListPayload = {
readonly list: {
readonly name: string;
readonly stringid: string;
readonly sender_url: string;
readonly sender_reminder: string;
readonly subscription_notify?: string;
readonly unsubscription_notify?: string;
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type ListStatusPayload = {
readonly contactList: {
readonly list: string;
readonly contact: string;
readonly status: string;
};
};

0 comments on commit 07703f2

Please sign in to comment.