From 22fe3ec88b00824171c1e7b7a5faceee0632637a Mon Sep 17 00:00:00 2001 From: "Fabien \"egg\" O'Carroll" Date: Fri, 18 Nov 2022 14:00:26 +0700 Subject: [PATCH] Added @tryghost/email-suppression-list package refs https://github.com/TryGhost/Team/issues/2267 This package contains definitions for the public interface of the email suppression list as well as an abstract implementation. --- ghost/email-suppression-list/.eslintrc.js | 6 ++ ghost/email-suppression-list/README.md | 21 +++++ ghost/email-suppression-list/index.js | 1 + .../lib/email-suppression-list.js | 90 +++++++++++++++++++ ghost/email-suppression-list/package.json | 26 ++++++ .../email-suppression-list/test/.eslintrc.js | 6 ++ 6 files changed, 150 insertions(+) create mode 100644 ghost/email-suppression-list/.eslintrc.js create mode 100644 ghost/email-suppression-list/README.md create mode 100644 ghost/email-suppression-list/index.js create mode 100644 ghost/email-suppression-list/lib/email-suppression-list.js create mode 100644 ghost/email-suppression-list/package.json create mode 100644 ghost/email-suppression-list/test/.eslintrc.js diff --git a/ghost/email-suppression-list/.eslintrc.js b/ghost/email-suppression-list/.eslintrc.js new file mode 100644 index 0000000000..c9c1bcb522 --- /dev/null +++ b/ghost/email-suppression-list/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: ['ghost'], + extends: [ + 'plugin:ghost/node' + ] +}; diff --git a/ghost/email-suppression-list/README.md b/ghost/email-suppression-list/README.md new file mode 100644 index 0000000000..2f91c715ae --- /dev/null +++ b/ghost/email-suppression-list/README.md @@ -0,0 +1,21 @@ +# Email Suppression List + + +## Usage + + +## Develop + +This is a monorepo package. + +Follow the instructions for the top-level repo. +1. `git clone` this repo & `cd` into it as usual +2. Run `yarn` to install top-level dependencies. + + + +## Test + +- `yarn lint` run just eslint +- `yarn test` run lint and tests + diff --git a/ghost/email-suppression-list/index.js b/ghost/email-suppression-list/index.js new file mode 100644 index 0000000000..ade62d814d --- /dev/null +++ b/ghost/email-suppression-list/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/email-suppression-list'); diff --git a/ghost/email-suppression-list/lib/email-suppression-list.js b/ghost/email-suppression-list/lib/email-suppression-list.js new file mode 100644 index 0000000000..89c80b61a4 --- /dev/null +++ b/ghost/email-suppression-list/lib/email-suppression-list.js @@ -0,0 +1,90 @@ +const assert = require('assert'); + +/** + * @typedef {object} EmailSuppressionInfo + * @prop {'spam' | 'failed'} reason + * @prop {Date} timestamp + */ + +/** + * @typedef {object} EmailSuppressedData + * @prop {true} suppressed + * @prop {EmailSuppressionInfo} info + */ + +/** + * @typedef {object} EmailNotSuppressedData + * @prop {false} suppressed + * @prop {null} info + */ + +/** + * @typedef {EmailSuppressedData | EmailNotSuppressedData} IEmailSuppressionData + */ + +/** + * @typedef {object} IEmailSuppressionList + * @prop {(email: string) => Promise} getSuppressionData + * @prop {(emails: string[]) => Promise} getBulkSuppressionData + * @prop {(email: string) => Promise} removeEmail + */ + +/** + * @implements {IEmailSuppressionData} + */ +class EmailSuppressionData { + /** @type {boolean} */ + suppressed; + /** @type {EmailSuppressionInfo | null} */ + info; + + constructor(suppressed, info) { + if (!suppressed) { + this.suppressed = false; + this.info = null; + } else { + this.suppressed = true; + assert(info.reason === 'spam' || info.reason === 'fail'); + assert(info.timestamp instanceof Date); + this.info = { + reason: info.reason, + timestamp: info.timestamp + }; + } + } +} + +/** + * @abstract + * @implements {IEmailSuppressionList} + */ +class AbstractEmailSuppressionList { + /** + * @param {string} email + * @returns {Promise} + */ + async removeEmail(email) { + return Promise.reject(); + } + + /** + * @param {string} email + * @returns {Promise} + */ + async getSuppressionData(email) { + return Promise.reject(); + } + + /** + * @param {string[]} emails + * @returns {Promise} + */ + async getBulkSuppressionData(emails) { + return Promise.all(emails.map(email => this.getSuppressionData(email))); + } +} + +module.exports = { + AbstractEmailSuppressionList, + EmailSuppressionData +}; diff --git a/ghost/email-suppression-list/package.json b/ghost/email-suppression-list/package.json new file mode 100644 index 0000000000..12925bf400 --- /dev/null +++ b/ghost/email-suppression-list/package.json @@ -0,0 +1,26 @@ +{ + "name": "@tryghost/email-suppression-list", + "version": "0.0.0", + "repository": "https://github.com/TryGhost/Ghost/tree/main/packages/email-suppression-list", + "author": "Ghost Foundation", + "private": true, + "main": "index.js", + "scripts": { + "dev": "echo \"Implement me!\"", + "test": "NODE_ENV=testing c8 --all --check-coverage --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "lint:code": "eslint *.js lib/ --ext .js --cache", + "lint": "yarn lint:code && yarn lint:test", + "lint:test": "eslint -c test/.eslintrc.js test/ --ext .js --cache" + }, + "files": [ + "index.js", + "lib" + ], + "devDependencies": { + "c8": "7.12.0", + "mocha": "10.1.0", + "should": "13.2.3", + "sinon": "14.0.2" + }, + "dependencies": {} +} diff --git a/ghost/email-suppression-list/test/.eslintrc.js b/ghost/email-suppression-list/test/.eslintrc.js new file mode 100644 index 0000000000..829b601eb0 --- /dev/null +++ b/ghost/email-suppression-list/test/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: ['ghost'], + extends: [ + 'plugin:ghost/test' + ] +};