Skip to content

Commit

Permalink
Hooked mega service to listen to email.added event
Browse files Browse the repository at this point in the history
- This was needed because we switched to synchronous request handling (to allow including email data with post.publish event)
  • Loading branch information
naz committed Nov 7, 2019
1 parent 4e1caa8 commit eca129c
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 41 deletions.
19 changes: 19 additions & 0 deletions core/server/api/canary/posts.js
@@ -1,6 +1,7 @@
const models = require('../../models');
const common = require('../../lib/common');
const urlUtils = require('../../lib/url-utils');
const {mega} = require('../../services/mega');
const allowedIncludes = ['tags', 'authors', 'authors.roles', 'email'];
const unsafeAttrs = ['status', 'authors', 'visibility'];

Expand Down Expand Up @@ -141,6 +142,24 @@ module.exports = {
},
query(frame) {
return models.Post.edit(frame.data.posts[0], frame.options)
.then(async (model) => {
if (!model.get('send_email_when_published')) {
return model;
}

if (!model.get('email') && (model.get('status') === 'published') && model.wasChanged()) {

const email = await mega.addEmail(model.toJSON());

if (frame.options.include && frame.options.includes('email')) {
model.set('email', email);
}

return model;
} else {
return model;
}
})
.then((model) => {
if (
model.get('status') === 'published' && model.wasChanged() ||
Expand Down
2 changes: 1 addition & 1 deletion core/server/data/schema/schema.js
Expand Up @@ -386,7 +386,7 @@ module.exports = {
maxlength: 50,
nullable: false,
defaultTo: 'sending',
validations: {isIn: [['sending', 'sent', 'failed']]}
validations: {isIn: [['pending', 'sending', 'sent', 'failed']]}
},
error: {type: 'string', maxlength: 2000, nullable: true},
stats: {type: 'text', maxlength: 65535, nullable: true},
Expand Down
83 changes: 43 additions & 40 deletions core/server/services/mega/mega.js
Expand Up @@ -8,7 +8,9 @@ const models = require('../../models');
const postEmailSerializer = require('./post-email-serializer');
const urlUtils = require('../../lib/url-utils');

const sendEmail = async (post, members) => {
const internalContext = {context: {internal: true}};

const getEmailData = (post, members) => {
const emailTmpl = postEmailSerializer.serialize(post);

const membersToSendTo = members.filter((member) => {
Expand All @@ -23,8 +25,13 @@ const sendEmail = async (post, members) => {
}, emailData);
}, {});

return bulkEmailService.send(emailTmpl, emails, emailData)
.then(() => ({emailTmpl, emails}));
return {emailTmpl, emails, emailData};
};

const sendEmail = async (post, members) => {
const {emailTmpl, emails, emailData} = getEmailData(post, members);

return bulkEmailService.send(emailTmpl, emails, emailData);
};

const sendTestEmail = async (post, emails) => {
Expand All @@ -33,6 +40,27 @@ const sendTestEmail = async (post, emails) => {
return bulkEmailService.send(emailTmpl, emails);
};

const addEmail = async (post) => {
const {members} = await membersService.api.members.list(Object.assign({filter: 'subscribed:true'}, {limit: 'all'}));
const {emailTmpl, emails} = getEmailData(post, members);

const existing = await models.Email.findOne({post_id: post.id}, internalContext);

if (!existing) {
return models.Email.add({
post_id: post.id,
status: 'pending',
email_count: emails.length,
subject: emailTmpl.subject,
html: emailTmpl.html,
plaintext: emailTmpl.plaintext,
submitted_at: moment().toDate()
}, internalContext);
} else {
return existing;
}
};

// NOTE: serialization is needed to make sure we are using current API and do post transformations
// such as image URL transformation from relative to absolute
const serialize = async (model) => {
Expand Down Expand Up @@ -111,24 +139,18 @@ async function handleUnsubscribeRequest(req) {
}
}

async function listener(model, options) {
async function listener(emailModel, options) {
// CASE: do not send email if we import a database
// TODO: refactor post.published events to never fire on importing
if (options && options.importing) {
return;
}

if (!model.get('send_email_when_published')) {
return;
}
const postModel = await models.Post.findOne({id: emailModel.get('post_id')}, internalContext);

const post = await serialize(model);
const post = await serialize(postModel);

const deliveredEvents = await models.Action.findAll({
filter: `event:delivered+resource_id:${model.id}`
});

if (deliveredEvents && deliveredEvents.toJSON().length > 0) {
if (emailModel.get('status') !== 'pending') {
return;
}

Expand All @@ -139,43 +161,24 @@ async function listener(model, options) {
}

sendEmail(post, members)
.then(async ({emailTmpl, emails}) => {
return models.Email.add({
post_id: post.id,
status: 'sent',
email_count: emails.length,
subject: emailTmpl.subject,
html: emailTmpl.html,
plaintext: emailTmpl.plaintext,
submitted_at: moment().toDate()
}, {context: {internal: true}});
})
.then(async () => {
let actor = {id: null, type: null};
if (options.context && options.context.user) {
actor = {
id: options.context.user,
type: 'user'
};
}
const action = {
event: 'delivered',
resource_id: model.id,
resource_type: 'post',
actor_id: actor.id,
actor_type: actor.type
};
return models.Action.add(action, {context: {internal: true}});
return models.Email.edit({
status: 'sent'
}, {
id: emailModel.id,
context: {internal: true}
});
});
}

function listen() {
common.events.on('post.published', listener);
common.events.on('email.added', listener);
}

// Public API
module.exports = {
listen,
addEmail,
sendTestEmail,
handleUnsubscribeRequest,
createUnsubscribeUrl
Expand Down

0 comments on commit eca129c

Please sign in to comment.