diff --git a/ansible/inventory.yaml b/ansible/inventory.yaml index a14fcdadca7..f9ed7d98ebe 100644 --- a/ansible/inventory.yaml +++ b/ansible/inventory.yaml @@ -15,3 +15,4 @@ all: backend3.freesewing.org: monorepo: /fs/monorepo + diff --git a/config/newsletter-testers.mjs b/config/newsletter-testers.mjs index 523410dab12..ddb771e2e37 100644 --- a/config/newsletter-testers.mjs +++ b/config/newsletter-testers.mjs @@ -1,10 +1,14 @@ -export const testers = [ - { - email: 'joost@joost.at', - ehash: 'asefsdfsdfsdlfsllehash', - }, - { - email: 'joost@decock.org', - ehash: 'zlasdadfsdlfsjjuehash', - }, -] +export const testers = { + en: [ + { + email: 'joost@joost.at', + ehash: 'asefsdfsdfsdlfsllehash', + }, + ], + nl: [ + { + email: 'joost@decock.org', + ehash: 'zlasdadfsdlfsjjuehash', + }, + ], +} diff --git a/config/templates/newsletter.html b/config/templates/newsletter.html index 7de792f5083..161aa0919e8 100644 --- a/config/templates/newsletter.html +++ b/config/templates/newsletter.html @@ -19,7 +19,7 @@ - FreeSewing Newsletter + {{ title }} @@ -323,7 +323,7 @@ " > Support FreeSewing: Become a Patron{{ support }} @@ -356,8 +356,7 @@ >

- You can unsubscribe at any time. Or just reply and - tell us you want out. + {{ unsub1 }}. {{ unsub2 }} diff --git a/package.json b/package.json index ab1361e07e5..b23e892d98b 100644 --- a/package.json +++ b/package.json @@ -103,6 +103,7 @@ "c8": "^8.0.0", "eslint-config-next": "^14.0.1", "glob": "^10.3.10", + "rehype-format": "^5.0.0", "yarn": "^1.22.19" }, "packageManager": "yarn@1.22.19" diff --git a/scripts/newsletter-lib.mjs b/scripts/newsletter-lib.mjs index 742f481344f..0619cf8962c 100644 --- a/scripts/newsletter-lib.mjs +++ b/scripts/newsletter-lib.mjs @@ -12,10 +12,50 @@ import { testers } from '../config/newsletter-testers.mjs' import { fileURLToPath } from 'url' import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2' +console.log({ edition: process.env.NL_EDITION }) // Current working directory const cwd = path.dirname(fileURLToPath(import.meta.url)) -const backend = 'https://backend.freesewing.org/' +const backend = 'https://backend3.freesewing.org/' + +const i18n = { + en: { + title: 'FreeSewing newsletter', + support: 'Support FreeSewing: Become a patron', + unsub1: 'You can unsubscribe at any time', + unsub2: 'Or reply and tell us you want out', + }, + nl: { + title: 'FreeSewing nieuwsbrief', + support: 'Steun FreeSewing: Wordt mecenas', + unsub1: 'Je kan je op elk moment uitschrijven', + unsub2: 'Of stuur een reply en laat ons weten dat het niet meer hoeft', + }, + fr: { + title: "Bulletin d'info FreeSewing", + support: 'Soutenir FreeSewing : Devenir mécène', + unsub1: 'Vous pouvez vous désabonner à tout moment', + unsub2: 'Ou répondez et dites-nous que vous voulez vous désabonner', + }, + de: { + title: 'FreeSewing-Newsletter', + support: 'Unterstützen Sie FreeSewing: Werden Sie Gönner', + unsub1: 'Sie können sich jederzeit wieder abmelden', + unsub2: 'Oder antworten Sie uns und sagen Sie uns, dass Sie nicht mehr wollen', + }, + de: { + title: 'FBoletín FreeSewing', + support: 'Apoya FreeSewing: Hazte mecenas', + unsub1: 'Puedes darte de baja en cualquier momento', + unsub2: 'O contesta y dinos que quieres darte de baja', + }, + de: { + title: 'Інформаційний бюлетень FreeSewing', + support: 'Підтримайте FreeSewing: Стати меценатом', + unsub1: 'Ви можете відписатися в будь-який час', + unsub2: 'Або надішліть нам відповідь і скажіть, що хочете відмовитися', + }, +} const asHtml = async (text) => { const content = await unified() @@ -29,20 +69,13 @@ const asHtml = async (text) => { return content.value } -const getToken = async () => { - let res = await axios.post(`${backend}login`, { - username: process.env.FS_USER, - password: process.env.FS_PASSWORD, - }) - if (res.data) return res.data.token - else if (res.err) return console.log(res.err) -} - const getSubscribers = async (test = true) => { if (test) return testers - let token = await getToken() let res = await axios.get(`${backend}admin/subscribers`, { - headers: { Authorization: 'Bearer ' + token }, + auth: { + username: process.env.NL_API_KEY, + password: process.env.NL_API_SECRET, + }, }) if (res.data) return res.data else return false @@ -51,75 +84,82 @@ const getSubscribers = async (test = true) => { const send = async (test = true) => { const us = 'FreeSewing ' const template = fs.readFileSync(`${cwd}/../config/templates/newsletter.html`, 'utf8') - let edition - try { - edition = await axios.get( - `https://posts.freesewing.org/newsletters?slug_eq=${process.env.NL_EDITION}`, - 'utf8' - ) - } catch (err) { - console.log(err) - process.exit() - } - const text = edition.data[0].body - const subscribers = await getSubscribers(test) - const content = await asHtml(text) - const inject = { content } // Oh AWS your APIs are such a clusterfuck const client = new SESv2Client({ region: 'us-east-1' }) let i = 1 - subscribers.sort() - let subs = subscribers.length - for (let sub of subscribers) { - // If your SMTP relay start rate-limiting midway through - // you can use this if loop to start just after the last - // successful delivery - if (i > 0) { - let unsub = `${backend}newsletter/unsubscribe/${sub.ehash}` - inject.unsubscribe = unsub - let body = mustache.render(template, inject) - console.log(`${i}/${subs} Sending to ${sub.email}`) + let l = 1 + for (const lang in subscribers) { + let edition + try { + edition = await axios.get( + `https://raw.githubusercontent.com/freesewing/freesewing/develop/markdown/org/newsletter/${process.env.NL_EDITION}/${lang}.md`, + 'utf8' + ) + } catch (err) { + console.log(err) + process.exit() + } + console.log(edition.data) + const text = edition.data[0].body + const content = await asHtml(text) - // Via API - const command = new SendEmailCommand({ - ConfigurationSetName: 'Newsletter', - Content: { - Simple: { - Body: { - Text: { - Charset: 'utf-8', - Data: text, + console.log(content) + + process.exit() + + subscribers[lang].sort() + let subs = subscribers[lang].length + for (let sub of subscribers[lang]) { + if (i > 0) { + let unsub = `${backend}newsletter/unsubscribe/${sub.ehash}` + inject.unsubscribe = unsub + let body = mustache.render(template, { + ...i18n[lang], + content, + }) + console.log(`[${lang}] ${i}/${subs} Sending to ${sub.email}`) + + // Via API + const command = new SendEmailCommand({ + ConfigurationSetName: 'Newsletter', + Content: { + Simple: { + Body: { + Text: { + Charset: 'utf-8', + Data: text, + }, + Html: { + Charset: 'utf-8', + Data: body, + }, }, - Html: { + Subject: { Charset: 'utf-8', - Data: body, + Data: 'FreeSewing newsletter: Autumn 2023', }, }, - Subject: { - Charset: 'utf-8', - Data: 'FreeSewing newsletter: Autumn 2023', - }, }, - }, - Destination: { - ToAddresses: [sub.email], - }, - //FeedbackForwardingEmailAddress: us, - FromEmailAddress: us, - //FromEmailAddressIdentityArn: "arn:aws:ses:us-east-1:550348293871:identity/freesewing.org", - //ReplyToAddresses: us, - }) - try { - await client.send(command) - } catch (err) { - console.log(err) - return false + Destination: { + ToAddresses: [sub.email], + }, + //FeedbackForwardingEmailAddress: us, + FromEmailAddress: us, + //FromEmailAddressIdentityArn: "arn:aws:ses:us-east-1:550348293871:identity/freesewing.org", + //ReplyToAddresses: us, + }) + //try { + // await client.send(command) + //} catch (err) { + // console.log(err) + // return false + //} } + i++ } - i++ } }