Skip to content

Commit 83c3b78

Browse files
committed
Moved SendGrid functions into another file
1 parent 3a7b906 commit 83c3b78

File tree

2 files changed

+114
-41
lines changed

2 files changed

+114
-41
lines changed

.github/actions/render-newsletter/src/index.ts

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import * as marked from 'marked';
88
import * as yaml from 'js-yaml';
99
import fetch from 'node-fetch';
1010

11+
import * as SG from './sendgrid';
12+
1113
const readFile = promisify(fs.readFile);
1214
const writeFile = promisify(fs.writeFile);
1315
const readdir = promisify(fs.readdir);
@@ -45,45 +47,6 @@ async function postToSlack(slackUrl: string, url: string) {
4547
});
4648
}
4749

48-
const API_BASE = 'https://api.sendgrid.com/v3';
49-
type SingleSendParams = {
50-
html: string,
51-
listId: string,
52-
suppressionGroup: number,
53-
token: string,
54-
sendAt?: Date,
55-
subject: string,
56-
};
57-
async function singleSend(params: SingleSendParams) {
58-
return await fetch(`${API_BASE}/marketing/singlesends`, {
59-
method: 'POST',
60-
headers: {
61-
'Authorization': `Bearer ${params.token}`,
62-
'Content-type': 'application/json',
63-
},
64-
body: JSON.stringify({
65-
name: `Newsletter: ${params.subject}`,
66-
send_at: params.sendAt?.toISOString(),
67-
send_to: {
68-
list_ids: [params.listId]
69-
},
70-
email_config: {
71-
subject: params.subject,
72-
html_content: params.html,
73-
suppression_group_id: params.suppressionGroup
74-
}
75-
})
76-
});
77-
}
78-
79-
type GetSingleSendsParams = {
80-
81-
};
82-
83-
async function getSingleSends(params: GetSingleSendsParams) {
84-
85-
}
86-
8750
type Options = {
8851
apiKey?: string,
8952
filePath: string,
@@ -95,6 +58,7 @@ type Options = {
9558
siteYaml?: string,
9659
subject?: string,
9760
slackUrl?: string,
61+
index?: SG.SingleSendIndex,
9862
};
9963

10064
async function loadTemplate(path?: string, options?: CompileOptions) {
@@ -192,6 +156,12 @@ async function render(opts: Options) {
192156
};
193157
}
194158

159+
const dateStr = (d: Date) => ((d.toISOString()).split('T', 1)[0]);
160+
161+
const floorDate = (d: Date) => (new Date(d.getFullYear(),
162+
d.getMonth(),
163+
d.getDate()));
164+
195165
function getSendDate(c: TemplateContext) {
196166
let date = c.post.date;
197167
if (date.getTime() <= Date.now()) {
@@ -213,13 +183,16 @@ async function run(options: Options) {
213183
await writeFile(options.output, text);
214184
} else if (options.apiKey) {
215185
const sendAt = getSendDate(context);
216-
const response = await singleSend({
186+
const id = options.index?.byDate[dateStr(context.post.date)][0];
187+
const response = await SG.singleSend({
217188
html: text,
218189
listId: options.listId,
219190
suppressionGroup: options.suppressionGroupId,
220191
token: options.apiKey,
221192
sendAt,
222193
subject: (options.subject ?? '%s').replace('%s', context.post.title),
194+
categories: ['newsletter'],
195+
id,
223196
});
224197

225198
const url = response.headers.get('location');
@@ -271,10 +244,14 @@ async function runAll(options: RunOptions) {
271244
return;
272245
}
273246

247+
const index = await SG.indexSingleSends({ token: options.apiKey });
248+
274249
for (const post of posts) {
250+
275251
const result = await run({
276252
...options,
277-
filePath: post
253+
filePath: post,
254+
index,
278255
});
279256

280257
if (result?.url && options.slackUrl) {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import fetch from 'node-fetch';
2+
3+
export type ScheduledSend = {
4+
id: string,
5+
name: string,
6+
status: string,
7+
categories: string[],
8+
send_at: string,
9+
created_at: string,
10+
updated_at: string,
11+
is_abtest: boolean,
12+
};
13+
14+
const API_BASE = 'https://api.sendgrid.com/v3';
15+
type SingleSendParams = {
16+
html: string,
17+
listId: string,
18+
suppressionGroup: number,
19+
token: string,
20+
sendAt?: Date,
21+
subject: string,
22+
categories?: string[],
23+
id?: string,
24+
};
25+
export async function singleSend(params: SingleSendParams) {
26+
const url = `${API_BASE}/marketing/singlesends` +
27+
(params.id ? `/${params.id}` : '');
28+
return await fetch(url, {
29+
method: params.id ? 'PATCH' : 'POST',
30+
headers: {
31+
'Authorization': `Bearer ${params.token}`,
32+
'Content-type': 'application/json',
33+
},
34+
body: JSON.stringify({
35+
name: `Newsletter: ${params.subject}`,
36+
send_at: params.sendAt?.toISOString(),
37+
send_to: {
38+
list_ids: [params.listId]
39+
},
40+
categories: params.categories,
41+
email_config: {
42+
subject: params.subject,
43+
html_content: params.html,
44+
suppression_group_id: params.suppressionGroup
45+
}
46+
})
47+
});
48+
}
49+
50+
type GetSingleSendsParams = {
51+
token: string,
52+
};
53+
54+
export async function *getSingleSends(params: GetSingleSendsParams) {
55+
let url = `${API_BASE}/marketing/singlesends/search`;
56+
while (url) {
57+
const response = await fetch(url, {
58+
method: 'POST',
59+
headers: {
60+
'Authorization': `Bearer ${params.token}`,
61+
'Content-type': 'application/json',
62+
},
63+
body: JSON.stringify({
64+
status: ['scheduled', 'draft'],
65+
// categories: ['newsletter']
66+
})
67+
});
68+
69+
const { result, _metadata: meta } = await response.json();
70+
yield *(result as ScheduledSend[]);
71+
url = meta.next;
72+
}
73+
}
74+
75+
export type SingleSendIndex = {
76+
byId: Record<string, ScheduledSend>,
77+
byName: Record<string, string>,
78+
byDate: Record<string, string[]>,
79+
}
80+
export async function indexSingleSends(params: GetSingleSendsParams) {
81+
const idx: SingleSendIndex = { byId: {}, byName: {}, byDate: {}, };
82+
83+
for await (const ss of getSingleSends(params)) {
84+
const { id } = ss;
85+
86+
idx.byId[id] = ss;
87+
idx.byName[ss.name] = id;
88+
89+
const date = ss.send_at.split('T', 1)[0];
90+
if (!idx.byDate[date])
91+
idx.byDate[date] = [];
92+
idx.byDate[date].push(id);
93+
}
94+
95+
return idx;
96+
}

0 commit comments

Comments
 (0)