diff --git a/services/mailer.js b/services/mailer.js index 67cb188be..60fbd3ef3 100644 --- a/services/mailer.js +++ b/services/mailer.js @@ -4,7 +4,7 @@ const kue = require('./kue'); const i18n = require('./i18n'); const path = require('path'); const fs = require('fs-extra'); -const _ = require('lodash'); +const { get, set, merge, template } = require('lodash'); const { TEMPLATE_LOCALS } = require('../middleware/staticTemplate'); const { @@ -18,52 +18,76 @@ const { // load all the templates as strings const templates = { - data: {}, + cache: {}, + registered: {}, +}; + +// Registers a template with the given filename and format. +templates.register = async (filename, name, format) => { + // Check to see if this template was already registered. + if (get(templates.registered, [name, format], null) !== null) { + return; + } + + const file = await fs.readFile(filename, 'utf8'); + const view = template(file); + + set(templates.registered, [name, format], view); }; // load the templates per request during development templates.render = async (name, format = 'txt', context) => { + // Check to see if the template is a registered template (provided by a plugin + // ) and prefer that first. + let view = get(templates.registered, [name, format], null); + if (view !== null) { + return view(context); + } + if (process.env.NODE_ENV === 'production') { // If we are in production mode, check the view cache. - const view = _.get(templates.data, [name, format], null); + const view = get(templates.cache, [name, format], null); if (view !== null) { return view(context); } } + // Template was not registered and was not cached. Let's try and find it! const filename = path.join( __dirname, 'email', [name, format, 'ejs'].join('.') ); const file = await fs.readFile(filename, 'utf8'); - const view = _.template(file); + view = template(file); if (process.env.NODE_ENV === 'production') { // If we are in production mode, fill the view cache. - _.set(templates.data, [name, format], view); + set(templates.cache, [name, format], view); } return view(context); }; -const mailer = {}; +const mailer = { templates, helpers: {} }; // enabled is true when the required configuration is available. When testing // is enabled, we will be simulating that emails are being sent, because in a // production system, emails should and would be sent. mailer.enabled = - Boolean(SMTP_HOST && SMTP_USERNAME && SMTP_PASSWORD && SMTP_FROM_ADDRESS) || - process.env.NODE_ENV === 'test'; + Boolean(SMTP_HOST && SMTP_FROM_ADDRESS) || process.env.NODE_ENV === 'test'; if (mailer.enabled) { const options = { host: SMTP_HOST, - auth: { + }; + + if (SMTP_USERNAME && SMTP_PASSWORD) { + options.auth = { user: SMTP_USERNAME, pass: SMTP_PASSWORD, - }, - }; + }; + } if (SMTP_PORT) { try { @@ -85,6 +109,16 @@ mailer.task = new kue.Task({ name: 'mailer', }); +/** + * registerHelpers will register the helpers on the mailer. + * + * @param {Object} helpers the helpers in object form that should be used by the + * mailer. + */ +mailer.registerHelpers = helpers => { + mailer.helpers = merge(mailer.helpers, helpers); +}; + /** * send will create a new message and send it. */ @@ -99,12 +133,14 @@ mailer.send = async options => { // Create the new locals object and attach the static locals and the i18n // framework. - const locals = _.merge({}, options.locals, TEMPLATE_LOCALS, { t: i18n.t }); + const locals = merge({}, mailer.helpers, options.locals, TEMPLATE_LOCALS, { + t: i18n.t, + }); // Render the templates. const [html, text] = await Promise.all( ['html', 'txt'].map(fmt => { - return templates.render(options.template, fmt, locals); + return mailer.templates.render(options.template, fmt, locals); }) );