@@ -8,6 +8,8 @@ import * as marked from 'marked';
88import * as yaml from 'js-yaml' ;
99import fetch from 'node-fetch' ;
1010
11+ import * as SG from './sendgrid' ;
12+
1113const readFile = promisify ( fs . readFile ) ;
1214const writeFile = promisify ( fs . writeFile ) ;
1315const 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-
8750type 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
10064async function loadTemplate ( path ?: string , options ?: CompileOptions ) {
@@ -192,6 +156,9 @@ async function render(opts: Options) {
192156 } ;
193157}
194158
159+ const dateStr =
160+ ( d : Date | string ) => ( ( typeof d === 'string' ? d : d . toISOString ( ) ) . split ( 'T' , 1 ) [ 0 ] ) ;
161+
195162function getSendDate ( c : TemplateContext ) {
196163 let date = c . post . date ;
197164 if ( date . getTime ( ) <= Date . now ( ) ) {
@@ -205,21 +172,42 @@ function getSendDate(c: TemplateContext) {
205172 return date ;
206173}
207174
175+ function singleSendId ( context : TemplateContext , index ?: SG . SingleSendIndex ) {
176+ if ( ! index )
177+ return undefined ;
178+
179+ const date = dateStr ( context . post . date ) ;
180+
181+ for ( const ss of Object . values ( index . byId ) ) {
182+ if ( dateStr ( ss . send_at ) === date )
183+ return ss . id ;
184+
185+ if ( ss . name . includes ( context . post . title ) )
186+ return ss . id ;
187+ }
188+ }
189+
208190async function run ( options : Options ) {
209191 const { text, context } = await render ( options ) ;
210- // console.log(context);
211192
212193 if ( options . output ) {
213194 await writeFile ( options . output , text ) ;
214195 } else if ( options . apiKey ) {
215196 const sendAt = getSendDate ( context ) ;
216- const response = await singleSend ( {
197+ const id = singleSendId ( context , options . index ) ;
198+
199+ if ( id )
200+ console . log ( `Updating existing Single Send ${ id } ` ) ;
201+
202+ const response = await SG . singleSend ( {
217203 html : text ,
218204 listId : options . listId ,
219205 suppressionGroup : options . suppressionGroupId ,
220206 token : options . apiKey ,
221207 sendAt,
222208 subject : ( options . subject ?? '%s' ) . replace ( '%s' , context . post . title ) ,
209+ categories : [ 'newsletter' ] ,
210+ id,
223211 } ) ;
224212
225213 const url = response . headers . get ( 'location' ) ;
@@ -246,7 +234,7 @@ type RunOptions = Omit<Options, 'filePath'> & {
246234function dateFilter ( after : number ) {
247235 return ( path : string ) => {
248236 const ctx = contextFromPath ( path ) ;
249- return ctx . date . getTime ( ) > after ;
237+ return ctx . date . getTime ( ) >= after ;
250238 } ;
251239}
252240
@@ -271,10 +259,13 @@ async function runAll(options: RunOptions) {
271259 return ;
272260 }
273261
262+ const index = await SG . indexSingleSends ( { token : options . apiKey } ) ;
263+
274264 for ( const post of posts ) {
275265 const result = await run ( {
276266 ...options ,
277- filePath : post
267+ filePath : post ,
268+ index,
278269 } ) ;
279270
280271 if ( result ?. url && options . slackUrl ) {
@@ -299,7 +290,7 @@ async function runAction() {
299290 INPUT_SUBJECT_FORMAT : subject = '%s' ,
300291 INPUT_POSTS_DIR : postsDir ,
301292 INPUT_SLACK_URL : slackUrl ,
302- TODAY_OVERRIDE : today ,
293+ INPUT_AFTER_DATE : today ,
303294 } = process . env ;
304295
305296 if ( ! ( path || postsDir ) ) {
@@ -325,7 +316,6 @@ async function runAction() {
325316}
326317
327318async function testRun ( ) {
328- // const apiKey = 'REAS-yuff0naum!krar';
329319 process . env [ 'INPUT_SENDGRID_LIST_ID' ] = "559adb5e-7164-4ac8-bbb5-1398d4ff0df9" ;
330320 // process.env['INPUT_SENDGRID_API_KEY'] = apiKey;
331321 // process.env['INPUT_TEXT_PATH'] = __dirname + '/../../../../_posts/2021-11-16-communications-lead.md';
@@ -334,8 +324,6 @@ async function testRun() {
334324 process . env [ 'INPUT_CONTEXT' ] = `{}` ;
335325 process . env [ 'INPUT_SUPPRESSION_GROUP_ID' ] = '17889' ;
336326 process . env [ 'INPUT_SITE_YAML' ] = __dirname + '/../../../../_config.yml' ;
337- process . env [ 'INPUT_SLACK_URL' ] = 'https://hooks.slack.com/services/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' ;
338- process . env [ 'TODAY_OVERRIDE' ] = '2022-01-10' ;
339327
340328 await runAction ( ) ;
341329}
0 commit comments