Skip to content
This repository was archived by the owner on Nov 15, 2024. It is now read-only.

Commit cf6b199

Browse files
committed
Added set_marketing_consent
1 parent 2c0e129 commit cf6b199

7 files changed

+112
-14
lines changed

README.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,19 @@ Returns the selected marketing consent level for a user. An error with the code
246246

247247
- `level`: The consent level selected. Either `general` or `none`.
248248

249+
### `set_marketing_consent`
250+
251+
Returns the selected marketing consent level for a user. An error with the code `awaiting_consent` will be returned if the user hasn't set a consent level yet.
252+
253+
#### Request
254+
255+
```json
256+
{
257+
"user_id": "user_000000C2kdCzNlbL1BqR5FeMatItU",
258+
"level": "general"
259+
}
260+
```
261+
249262
## Webhooks
250263

251264
Webhooks URL's comprise of two parts; the webhook indicator, followed by the provider value. Each provider has an example below.
@@ -325,7 +338,19 @@ interface Identifiers {
325338
}
326339
```
327340

328-
### `provider_mappings`
341+
### `marketing-consent`
342+
343+
```ts
344+
interface MarketingConsent {
345+
id: string;
346+
userId: string;
347+
level: 'none' | 'general';
348+
createdAt: string;
349+
updatedAt: string | null;
350+
}
351+
```
352+
353+
### `provider-mappings`
329354

330355
```ts
331356
interface ExternalMappings {
@@ -338,7 +363,7 @@ interface ExternalMappings {
338363
}
339364
```
340365

341-
### `refresh_tokens`
366+
### `refresh-tokens`
342367

343368
```ts
344369
interface RefreshTokens {

src/app/set-marketing-consent.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import mailchimpMarketing from '@mailchimp/mailchimp_marketing';
2+
import crypto from 'crypto';
3+
4+
import { ConsentLevel } from '../db/marketing-consent';
5+
import { Context, SetMarketingConsentRequest } from '../types';
6+
7+
export default async function setMarketingConsent(ctx: Context, request: SetMarketingConsentRequest): Promise<void> {
8+
console.log(request);
9+
10+
const user = await ctx.app.dbClient.users.findUser(request.userId);
11+
const identifiers = await ctx.app.dbClient.identifiers.listUserIdentifiers(user.id);
12+
const emails = identifiers.filter(i => i.identifierType === 'email' && !i.removedAt);
13+
14+
// For each email, set consent
15+
await Promise.all(emails.map(async e => {
16+
const digest = crypto.createHash('md5')
17+
.update(e.identifierValue)
18+
.digest('hex');
19+
20+
await setMailchimpMarketingLevel(e.identifierValue, digest, request.level);
21+
}));
22+
23+
await ctx.app.dbClient.marketingConsent.upsertMarketingConsent(user.id, request.level);
24+
}
25+
26+
async function setMailchimpMarketingLevel(email: string, hash: string, level: ConsentLevel) {
27+
await mailchimpMarketing.lists.updateListMember('e580e6811f', hash, {
28+
email_address: email,
29+
status: level === 'none' ? 'unsubscribed' : 'subscribed',
30+
});
31+
}

src/db/marketing-consent.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export default class MarketingConsents extends Collection<MarketingConsent> {
3636
_id: id,
3737
userId,
3838
createdAt: now,
39-
removedAt: null,
4039
},
4140
}, { upsert: true });
4241
}

src/interface/rpc/index.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { APIGatewayProxyEventV2 } from 'aws-lambda';
2-
import * as camelCaseKeys from 'camelcase-keys';
2+
import camelCaseKeys from 'camelcase-keys';
33
import { validate } from 'jsonschema';
44
import { Logger } from 'tslog';
55

@@ -15,19 +15,20 @@ import getUser, { getUserSchema } from './get-user';
1515
import listNewsItems, { listNewsItemsSchema } from './list-news-items';
1616
import handleAuth from './middleware/auth';
1717
import sendMagicLink, { sendMagicLinkSchema } from './send-magic-link';
18+
import setMarketingConsent, { setMarketingConsentSchema } from './set-marketing-consent';
1819

1920
const urlRegex = /^\/(\d)\/([\d-]+)\/(.+)$/;
2021
const qualifierRegex = /^\/\d\/[\d-]+\//;
2122

2223
const v20201214: VersionSet = {
23-
send_magic_link: {
24-
impl: sendMagicLink,
25-
schema: sendMagicLinkSchema,
26-
},
2724
authenticate_user: {
2825
impl: authenticateUser,
2926
schema: authenticateUserSchema,
3027
},
28+
enrol_alpha_user: {
29+
impl: enrolAlphaUser,
30+
schema: enrolAlphaUserSchema,
31+
},
3132
get_marketing_consent: {
3233
impl: getMarketingConsent,
3334
schema: getMarketingConsentSchema,
@@ -36,14 +37,18 @@ const v20201214: VersionSet = {
3637
impl: getSubscriptionStatus20201214,
3738
schema: getSubscriptionStatusSchema20201214,
3839
},
39-
enrol_alpha_user: {
40-
impl: enrolAlphaUser,
41-
schema: enrolAlphaUserSchema,
42-
},
4340
list_news_items: {
4441
impl: listNewsItems,
4542
schema: listNewsItemsSchema,
4643
},
44+
send_magic_link: {
45+
impl: sendMagicLink,
46+
schema: sendMagicLinkSchema,
47+
},
48+
set_marketing_consent: {
49+
impl: setMarketingConsent,
50+
schema: setMarketingConsentSchema,
51+
},
4752
};
4853

4954
const v20211006: VersionSet = {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"type": "object",
3+
"additionalProperties": false,
4+
5+
"required": [
6+
"user_id",
7+
"level"
8+
],
9+
10+
"properties": {
11+
"user_id": {
12+
"type": "string",
13+
"minLength": 1
14+
},
15+
16+
"level": {
17+
"type": "string",
18+
"enum": ["none", "general"]
19+
}
20+
}
21+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import setMarketingConsentImpl from '../../app/set-marketing-consent';
2+
import { Context, SetMarketingConsentRequest } from '../../types';
3+
import Squawk from '../../utils/squawk';
4+
import setMarketingConsentSchema from './set-marketing-consent.json';
5+
6+
export default async function setMarketingConsent(ctx: Context, request: SetMarketingConsentRequest) {
7+
if (!ctx.auth)
8+
throw new Squawk('access_denied');
9+
10+
if (ctx.auth.type !== 'internal' && ctx.auth.userId !== request.userId)
11+
throw new Squawk('access_denied');
12+
13+
return await setMarketingConsentImpl(ctx, request);
14+
}
15+
16+
export { setMarketingConsentSchema };

src/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { SESClient } from '@aws-sdk/client-ses';
2-
import { ConsentLevel } from './db/marketing-consent';
3-
import { CancelType } from './db/subscriptions';
42
import { Stripe } from 'stripe';
53
import { Logger } from 'tslog';
64

75
import DbClient from './db';
6+
import { ConsentLevel } from './db/marketing-consent';
7+
import { CancelType } from './db/subscriptions';
88

99
export interface Config {
1010
env: string;
@@ -13,6 +13,7 @@ export interface Config {
1313
stpSecretKey: string;
1414
stpWebhookSecret: string;
1515
stpSubscriptionPriceId: string;
16+
mailchimpApiKey: string;
1617
requiredCoupon?: string;
1718
mongoUri: string;
1819
internalKey: string;

0 commit comments

Comments
 (0)