Unsubscribed Members from newsletters when their email is suppressed
refs https://github.com/TryGhost/Team/issues/2367 This ensures that a Member is not considered subscribed to any emails, so that counts for newsletter recipients are correct. Eventually we will filter members on their email suppression status but this is not implemented yet.
This commit is contained in:
parent
7567997dbf
commit
9736d942e1
@ -1,4 +1,4 @@
|
||||
const {AbstractEmailSuppressionList, EmailSuppressionData} = require('@tryghost/email-suppression-list');
|
||||
const {AbstractEmailSuppressionList, EmailSuppressionData, EmailSuppressedEvent} = require('@tryghost/email-suppression-list');
|
||||
const {SpamComplaintEvent, EmailBouncedEvent} = require('@tryghost/email-events');
|
||||
const DomainEvents = require('@tryghost/domain-events');
|
||||
const logging = require('@tryghost/logging');
|
||||
@ -103,6 +103,11 @@ class MailgunEmailSuppressionList extends AbstractEmailSuppressionList {
|
||||
reason: 'bounce',
|
||||
created_at: event.timestamp
|
||||
});
|
||||
DomainEvents.dispatch(EmailSuppressedEvent.create({
|
||||
emailAddress: event.email,
|
||||
emailId: event.emailId,
|
||||
reason: reason
|
||||
}, event.timestamp));
|
||||
} catch (err) {
|
||||
if (err.code !== 'ER_DUP_ENTRY') {
|
||||
logging.error(err);
|
||||
|
@ -741,8 +741,9 @@ describe('EmailEventStorage', function () {
|
||||
);
|
||||
|
||||
// Check not unsubscribed
|
||||
const {body: {events: [notSpamEvent]}} = await agent.get(eventsURI);
|
||||
assert.notEqual(notSpamEvent.type, 'email_complaint_event', 'This test requires a member that does not have a spam event');
|
||||
const {body: {events: eventsBefore}} = await agent.get(eventsURI);
|
||||
const existingSpamEvent = eventsBefore.find(event => event.type === 'email_complaint_event');
|
||||
assert.equal(existingSpamEvent, null, 'This test requires a member that does not have a spam event');
|
||||
|
||||
events = [{
|
||||
event: 'complained',
|
||||
@ -772,7 +773,8 @@ describe('EmailEventStorage', function () {
|
||||
await sleep(200);
|
||||
|
||||
// Check if event exists
|
||||
const {body: {events: [spamComplaintEvent]}} = await agent.get(eventsURI);
|
||||
const {body: {events: eventsAfter}} = await agent.get(eventsURI);
|
||||
const spamComplaintEvent = eventsAfter.find(event => event.type === 'email_complaint_event');
|
||||
assert.equal(spamComplaintEvent.type, 'email_complaint_event');
|
||||
});
|
||||
|
||||
|
@ -84,7 +84,41 @@ class AbstractEmailSuppressionList {
|
||||
}
|
||||
}
|
||||
|
||||
class EmailSuppressedEvent {
|
||||
/**
|
||||
* @readonly
|
||||
* @type {{emailId: string, emailAddress: string, reason: string}}
|
||||
*/
|
||||
data;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @type {Date}
|
||||
*/
|
||||
timestamp;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
constructor({emailAddress, emailId, reason, timestamp}) {
|
||||
this.data = {
|
||||
emailAddress,
|
||||
emailId,
|
||||
reason
|
||||
};
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
static create(data, timestamp) {
|
||||
return new EmailSuppressedEvent({
|
||||
...data,
|
||||
timestamp: timestamp || new Date
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
AbstractEmailSuppressionList,
|
||||
EmailSuppressionData
|
||||
EmailSuppressionData,
|
||||
EmailSuppressedEvent
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
const assert = require('assert');
|
||||
const {EmailSuppressionData} = require('../../lib/email-suppression-list');
|
||||
const {EmailSuppressionData, EmailSuppressedEvent} = require('../../lib/email-suppression-list');
|
||||
|
||||
describe('EmailSuppressionData', function () {
|
||||
it('Has null info when not suppressed', function () {
|
||||
@ -12,7 +12,7 @@ describe('EmailSuppressionData', function () {
|
||||
assert(data.suppressed === false);
|
||||
assert(data.info === null);
|
||||
});
|
||||
it('', function () {
|
||||
it('Has info when suppressed', function () {
|
||||
const now = new Date();
|
||||
const data = new EmailSuppressionData(true, {
|
||||
reason: 'spam',
|
||||
@ -24,3 +24,15 @@ describe('EmailSuppressionData', function () {
|
||||
assert(data.info.timestamp === now);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EmailSuppressedEvent', function () {
|
||||
it('Exposes a create factory method', function () {
|
||||
const event = EmailSuppressedEvent.create({
|
||||
emailAddress: 'test@test.com',
|
||||
emailId: '1234567890abcdef',
|
||||
reason: 'spam'
|
||||
});
|
||||
assert(event instanceof EmailSuppressedEvent);
|
||||
assert(event.timestamp);
|
||||
});
|
||||
});
|
||||
|
@ -16,6 +16,9 @@ const RouterController = require('./controllers/router');
|
||||
const MemberController = require('./controllers/member');
|
||||
const WellKnownController = require('./controllers/well-known');
|
||||
|
||||
const {EmailSuppressedEvent} = require('@tryghost/email-suppression-list');
|
||||
const DomainEvents = require('@tryghost/domain-events');
|
||||
|
||||
module.exports = function MembersAPI({
|
||||
tokenConfig: {
|
||||
issuer,
|
||||
@ -347,6 +350,14 @@ module.exports = function MembersAPI({
|
||||
|
||||
bus.emit('ready');
|
||||
|
||||
DomainEvents.subscribe(EmailSuppressedEvent, async function (event) {
|
||||
const member = await memberRepository.get({email: event.data.emailAddress});
|
||||
if (!member) {
|
||||
return;
|
||||
}
|
||||
await memberRepository.update({newsletters: []}, {id: member.id});
|
||||
});
|
||||
|
||||
return {
|
||||
middleware,
|
||||
getMemberDataFromMagicLinkToken,
|
||||
|
Loading…
Reference in New Issue
Block a user