mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 11:55:03 +03:00
Refactored email utils to a class with DI params
refs https://github.com/TryGhost/Toolbox/issues/292 - There's a need to reuse these utils in the version mismatch notification service. Having loads of tightly coupled dependencies makes it super hard to rip out this module for reuse - It's a groundwork for extraction of the email-utils package - Rewrote the unit tests that were written for these utils previously - they weren't testing anything useful. The goal of this util is to generate specific content based on provided data and available templates - now the tests do test those specific things, not the mailer itself!
This commit is contained in:
parent
499bb293c9
commit
551bd5e511
55
core/server/services/mail/EmailContentGenerator.js
Normal file
55
core/server/services/mail/EmailContentGenerator.js
Normal file
@ -0,0 +1,55 @@
|
||||
const _ = require('lodash').runInContext();
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const htmlToText = require('html-to-text');
|
||||
|
||||
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
|
||||
|
||||
class EmailContentGenerator {
|
||||
/**
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {function} options.getSiteUrl
|
||||
* @param {function} options.getSiteTitle
|
||||
* @param {string} options.templatesDir - path to the directory containing email templates
|
||||
*/
|
||||
constructor({getSiteUrl, getSiteTitle, templatesDir}) {
|
||||
this.getSiteUrl = getSiteUrl;
|
||||
this.getSiteTitle = getSiteTitle;
|
||||
this.templatesDir = templatesDir;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {string} options.template - HTML template name to use for generation
|
||||
* @param {Object} [options.data] - variable data to use during HTML template compilation
|
||||
* @returns {Promise} resolves with an object containing html and text properties
|
||||
*/
|
||||
async getContent(options) {
|
||||
const defaults = {
|
||||
siteUrl: this.getSiteUrl(),
|
||||
siteTitle: this.getSiteTitle()
|
||||
};
|
||||
|
||||
const data = _.defaults(defaults, options.data);
|
||||
|
||||
// read the proper email body template
|
||||
return fs.readFile(path.join(this.templatesDir, options.template + '.html'), 'utf8')
|
||||
.then(function (content) {
|
||||
// insert user-specific data into the email
|
||||
const compiled = _.template(content);
|
||||
const htmlContent = compiled(data);
|
||||
|
||||
// generate a plain-text version of the same email
|
||||
const textContent = htmlToText.fromString(htmlContent);
|
||||
|
||||
return {
|
||||
html: htmlContent,
|
||||
text: textContent
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EmailContentGenerator;
|
@ -1,2 +1,15 @@
|
||||
const path = require('path');
|
||||
const urlUtils = require('../../../shared/url-utils');
|
||||
const settingsCache = require('../../../shared/settings-cache');
|
||||
const EmailContentGenerator = require('./EmailContentGenerator');
|
||||
|
||||
const emailContentGenerator = new EmailContentGenerator({
|
||||
getSiteUrl: () => urlUtils.urlFor('home', true),
|
||||
getSiteTitle: () => settingsCache.get('title'),
|
||||
templatesDir: path.resolve(__dirname, '..', 'mail', 'templates')
|
||||
});
|
||||
|
||||
exports.GhostMailer = require('./GhostMailer');
|
||||
exports.utils = require('./utils');
|
||||
exports.utils = {
|
||||
generateContent: emailContentGenerator.getContent.bind(emailContentGenerator)
|
||||
};
|
||||
|
@ -1,34 +0,0 @@
|
||||
const _ = require('lodash').runInContext();
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const htmlToText = require('html-to-text');
|
||||
const urlUtils = require('../../../shared/url-utils');
|
||||
const settingsCache = require('../../../shared/settings-cache');
|
||||
const templatesDir = path.resolve(__dirname, '..', 'mail', 'templates');
|
||||
|
||||
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
|
||||
|
||||
exports.generateContent = function generateContent(options) {
|
||||
const defaults = {
|
||||
siteUrl: urlUtils.urlFor('home', true),
|
||||
siteTitle: settingsCache.get('title')
|
||||
};
|
||||
|
||||
const data = _.defaults(defaults, options.data);
|
||||
|
||||
// read the proper email body template
|
||||
return fs.readFile(path.join(templatesDir, options.template + '.html'), 'utf8')
|
||||
.then(function (content) {
|
||||
// insert user-specific data into the email
|
||||
const compiled = _.template(content);
|
||||
const htmlContent = compiled(data);
|
||||
|
||||
// generate a plain-text version of the same email
|
||||
const textContent = htmlToText.fromString(htmlContent);
|
||||
|
||||
return {
|
||||
html: htmlContent,
|
||||
text: textContent
|
||||
};
|
||||
});
|
||||
};
|
@ -1,41 +1,38 @@
|
||||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const mail = require('../../../../../core/server/services/mail');
|
||||
const configUtils = require('../../../../utils/configUtils');
|
||||
const assert = require('assert');
|
||||
const path = require('path');
|
||||
|
||||
describe('Mail: Utils', function () {
|
||||
const scope = {ghostMailer: null};
|
||||
const EmailContentGenerator = require('../../../../../core/server/services/mail/EmailContentGenerator');
|
||||
|
||||
beforeEach(function () {
|
||||
configUtils.set({mail: {transport: 'stub'}});
|
||||
scope.ghostMailer = new mail.GhostMailer();
|
||||
});
|
||||
describe('Mail: EmailContentGenerator', function () {
|
||||
it('generate welcome', async function () {
|
||||
const emailContentGenerator = new EmailContentGenerator({
|
||||
getSiteTitle: () => 'The Ghost Blog',
|
||||
getSiteUrl: () => 'http://myblog.com',
|
||||
templatesDir: path.resolve(__dirname, '../../../../../core/server/services/mail/templates/')
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
it('generate welcome', function (done) {
|
||||
mail.utils.generateContent({
|
||||
const content = await emailContentGenerator.getContent({
|
||||
template: 'welcome',
|
||||
data: {
|
||||
ownerEmail: 'test@example.com'
|
||||
}
|
||||
}).then(function (result) {
|
||||
return scope.ghostMailer.send({
|
||||
to: 'test@example.com',
|
||||
subject: 'lol',
|
||||
html: result.html,
|
||||
text: result.text
|
||||
});
|
||||
}).then(function () {
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
assert.match(content.html, /<title>Welcome to Ghost<\/title>/);
|
||||
assert.match(content.html, /This email was sent from <a href="http:\/\/myblog.com" style="color: #738A94;">http:\/\/myblog.com<\/a> to <a href="mailto:test@example.com" style="color: #738A94;">test@example.com<\/a><\/p>/);
|
||||
|
||||
assert.match(content.text, /Email Address: test@example.com \[test@example.com\]/);
|
||||
assert.match(content.text, /This email was sent from http:\/\/myblog.com/);
|
||||
});
|
||||
|
||||
it('generates newsletter template', function (done) {
|
||||
mail.utils.generateContent({
|
||||
it('generates newsletter template', async function () {
|
||||
const emailContentGenerator = new EmailContentGenerator({
|
||||
getSiteTitle: () => 'The Ghost Blog',
|
||||
getSiteUrl: () => 'http://myblog.com',
|
||||
templatesDir: path.resolve(__dirname, '../../../../../core/server/services/mail/templates/')
|
||||
});
|
||||
|
||||
const content = await emailContentGenerator.getContent({
|
||||
template: 'newsletter',
|
||||
data: {
|
||||
blog: {
|
||||
@ -93,15 +90,13 @@ describe('Mail: Utils', function () {
|
||||
date: 'june, 9th 2016'
|
||||
}
|
||||
}
|
||||
}).then(function (result) {
|
||||
return scope.ghostMailer.send({
|
||||
to: 'jbloggs@example.com',
|
||||
subject: 'The Newsletter Blog',
|
||||
html: result.html,
|
||||
text: result.text
|
||||
});
|
||||
}).then(function () {
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
assert.match(content.html, /<title>The Ghost Blog<\/title>/);
|
||||
assert.match(content.html, /<span style="text-transform:capitalize">monthly<\/span> digest/);
|
||||
assert.match(content.html, /<span style="text-transform:capitalize">june, 9th 2016<\/span><\/h3>/);
|
||||
|
||||
assert.match(content.text, /MONTHLY DIGEST — JUNE, 9TH 2016/);
|
||||
assert.match(content.text, /SECOND BLOG POST \[HTTP:\/\/MYBLOG.COM\/SECOND-BLOG-POST\]/);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user