var fs = require('fs'); var mustache = require('mustache'); var locale = require('./locale.js'); var inlineCss = require('inline-css'); var path = require('path'); module.exports = { /** * Get template. * @param {String} template - Template name * @param {Object} countryCode - Language code * @param {Object} params - Params * @param {Object} cb - Callback */ get: function(template, params, cb) { var templatePath = path.join(__dirname, 'template', `${template}`, `index.html`); var classPath = path.join(__dirname, 'template', `${template}`, `${template}.js`); var stylePath = path.join(__dirname, 'template', `${template}`, 'style.css'); fs.stat(templatePath, (error, stat) => { if (error) return cb(new Error('Template ' + template + ' not found')); let TemplateClass = require(classPath); let instance = new TemplateClass(); let getRenderedStyles = (error, body) => { if (error) return cb(error); this.renderStyles(stylePath, body, (error, body) => { if (error) return cb(error); // Check if has a subject param params.subject = params.subject || instance.subject; if (params.subject == undefined) { // Try to find a subject from Html source let title = body.match(new RegExp('(.*?)', 'i')); if (title) params.subject = title[1]; } this.renderImages(template, body, params.isPreview, (error, body) => { if (error) return cb(error); cb(null, {body: body}); }); }); }; let getDataCb = () => { this.render(templatePath, params, instance, (error, result) => getRenderedStyles(error, result)); }; instance.getData(params, (error, result) => { if (error) return cb(error); locale.load(template, instance.countryCode, (error, result) => { if (error) return cb(error); instance._ = result.locale; instance.isPreview = params.isPreview; getDataCb(null, result); }); }); }); }, /** * Render template * @param {String} path - Template path * @param {Object} data - Params * @param {Object} cb - Callback */ render: function(path, params, data, cb) { fs.readFile(path, 'utf8', (error, body) => { // Find matching sub-templates let regexp = new RegExp(/\{\{\$\.(.*?)\}\}/, 'ig'); let subTpl = body.match(regexp); if (!subTpl) { mustache.parse(body); return cb(null, mustache.render(body, data)); } let parentBody = body; this.renderSub(parentBody, subTpl, data, regexp, (error, body) => { if (error) return cb(error); mustache.parse(body); cb(null, mustache.render(body, data)); }); }); }, renderSub: function(body, subTpl, params, regexp, cb) { let index = 1; subTpl.forEach(keyName => { subTplName = keyName.replace(regexp, '$1'); this.get(subTplName, params, (error, result) => { if (error) return cb(error); let subTplBody = result.body; body = body.replace(keyName, subTplBody); if (index === subTpl.length) cb(null, body); index++; }); }); }, /** * Render template style. * @param {String} path - Stylesheet path * @param {String} body - Rendered html * @param {Object} cb - Callback */ renderStyles: function(stylePath, html, cb) { // Common components let comPath = path.join(__dirname, '../', 'static', 'css', 'common.css'); fs.readFile(comPath, 'utf8', (error, comCss) => { fs.stat(stylePath, error => { if (error) return cb(new Error('Template stylesheet not found')); fs.readFile(stylePath, 'utf8', (error, css) => { let style = ''; let body = style + html; let options = {url: ' '}; inlineCss(body, options) .then(function(body) { cb(null, body); }); }); }); }); }, /** * Render template images * @param {String} template - Template name * @param {String} body - template body * @param {Object} cb - Callback */ renderImages: function(template, body, isPreview, cb) { let tplImages = body.match(new RegExp('src="cid:(.*?)"', 'ig')); if (!tplImages) tplImages = {}; // Template default attachments for (var i = 0; i < tplImages.length; i++) { let src = tplImages[i].replace('src="cid:', '').replace('"', '').split('/'); let attachmentTpl = src[0]; let attachment = src[1]; if (isPreview) { let imagePath = `/print/static/${attachmentTpl}/${attachment}`; body = body.replace(tplImages[i], `src="${imagePath}"`); } else { let imagePath = path.join(__dirname, 'template', attachmentTpl, 'image', attachment); body = body.replace(tplImages[i], `src="file:///${imagePath}"`); } } cb(null, body); }, /** * Get template attachments * @param {String} template - Template name * @param {String} body - template body * @param {Object} cb - Callback */ getAttachments: function(template, body, isPreview, cb) { let attachments = []; let tplAttachments = body.match(new RegExp('src="cid:(.*?)"', 'ig')); if (!tplAttachments) tplAttachments = {}; // Template default attachments for (var i = 0; i < tplAttachments.length; i++) { let src = tplAttachments[i].replace('src="cid:', '').replace('"', '').split('/'); let attachmentTpl = src[0]; let attachment = src[1]; if (isPreview) { let attachmentPath = `/mailer/static/${attachmentTpl}/${attachment}`; body = body.replace(tplAttachments[i], `src="${attachmentPath}"`); } else { let attachmentPath = path.join(__dirname, 'template', `${attachmentTpl}`, 'image', attachment); let attachmentName = attachmentTpl + '/' + attachment; attachments.push({filename: attachmentName, path: attachmentPath, cid: attachmentName}); } } if (isPreview) return cb(null, {body: body, attachments: attachments}); // Template attachment files let attachmentsPath = path.join(__dirname, 'template', `${template}`, 'attachment.json'); fs.stat(attachmentsPath, (error, stats) => { if (error) return cb(null, {body: body, attachments: attachments}); let attachObj = require(attachmentsPath); for (var i = 0; i < attachObj.length; i++) { let filename = attachObj[i]; let attachmentPath = path.join(__dirname, 'template', `${template}`, 'attachment', filename); attachments.push({filename: filename, path: attachmentPath, cid: filename}); } this.checkAttachments(attachments, error => { if (error) return cb(error); cb(null, {body: body, attachments: attachments}); }); }); }, /** * Check all template attachments * @param {Object} attachments - Attachments object * @param {Object} cb - Callback */ checkAttachments: function(attachments, cb) { for (var i = 0; i < attachments.length; i++) { var attachment = attachments[i]; fs.stat(attachment.path, error => { if (error) return cb(new Error(`Could not load attachment file ${attachment.path}`)); }); } cb(); } };