2017-11-27 14:08:18 +00:00
|
|
|
var fs = require('fs');
|
|
|
|
var mustache = require('mustache');
|
|
|
|
var locale = require('./locale.js');
|
|
|
|
var inlineCss = require('inline-css');
|
|
|
|
var path = require('path');
|
|
|
|
|
|
|
|
module.exports = {
|
2018-05-28 10:22:35 +00:00
|
|
|
|
2017-11-27 14:08:18 +00:00
|
|
|
/**
|
|
|
|
* 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`);
|
2017-12-26 09:02:47 +00:00
|
|
|
var stylePath = path.join(__dirname, 'template', `${template}`, 'style.css');
|
2017-11-27 14:08:18 +00:00
|
|
|
|
|
|
|
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('<title>(.*?)</title>', 'i'));
|
|
|
|
|
|
|
|
if (title)
|
|
|
|
params.subject = title[1];
|
2018-05-28 10:22:35 +00:00
|
|
|
}
|
2017-11-27 14:08:18 +00:00
|
|
|
|
2017-12-26 09:02:47 +00:00
|
|
|
this.renderImages(template, body, params.isPreview, (error, body) => {
|
2017-11-27 14:08:18 +00:00
|
|
|
if (error)
|
|
|
|
return cb(error);
|
|
|
|
|
|
|
|
cb(null, {body: body});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
let getDataCb = () => {
|
2017-12-26 09:02:47 +00:00
|
|
|
this.render(templatePath, params, instance, (error, result) => getRenderedStyles(error, result));
|
2017-11-27 14:08:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
2017-12-26 09:02:47 +00:00
|
|
|
instance.isPreview = params.isPreview;
|
2017-11-27 14:08:18 +00:00
|
|
|
getDataCb(null, result);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Render template
|
|
|
|
* @param {String} path - Template path
|
|
|
|
* @param {Object} data - Params
|
|
|
|
* @param {Object} cb - Callback
|
|
|
|
*/
|
2017-12-26 09:02:47 +00:00
|
|
|
render: function(path, params, data, cb) {
|
2017-11-27 14:08:18 +00:00
|
|
|
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;
|
2018-05-28 10:22:35 +00:00
|
|
|
this.renderSub(parentBody, subTpl, data, regexp, (error, body) => {
|
2017-11-27 14:08:18 +00:00
|
|
|
if (error)
|
|
|
|
return cb(error);
|
|
|
|
|
|
|
|
mustache.parse(body);
|
|
|
|
cb(null, mustache.render(body, data));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-12-26 09:02:47 +00:00
|
|
|
renderSub: function(body, subTpl, params, regexp, cb) {
|
2017-11-27 14:08:18 +00:00
|
|
|
let index = 1;
|
|
|
|
|
|
|
|
subTpl.forEach(keyName => {
|
|
|
|
subTplName = keyName.replace(regexp, '$1');
|
|
|
|
|
2017-12-26 09:02:47 +00:00
|
|
|
this.get(subTplName, params, (error, result) => {
|
2017-11-27 14:08:18 +00:00
|
|
|
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
|
2018-05-28 10:22:35 +00:00
|
|
|
let comPath = path.join(__dirname, '../', 'static', 'css', 'common.css');
|
2017-11-27 14:08:18 +00:00
|
|
|
|
|
|
|
fs.readFile(comPath, 'utf8', (error, comCss) => {
|
|
|
|
fs.stat(stylePath, error => {
|
2018-05-28 10:22:35 +00:00
|
|
|
if (error)
|
2017-11-27 14:08:18 +00:00
|
|
|
return cb(new Error('Template stylesheet not found'));
|
2018-05-28 10:22:35 +00:00
|
|
|
|
2017-11-27 14:08:18 +00:00
|
|
|
fs.readFile(stylePath, 'utf8', (error, css) => {
|
|
|
|
let style = '<style>' + comCss + css + '</style>';
|
|
|
|
let body = style + html;
|
|
|
|
let options = {url: ' '};
|
2017-12-26 09:02:47 +00:00
|
|
|
|
2017-11-27 14:08:18 +00:00
|
|
|
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
|
|
|
|
*/
|
2017-12-26 09:02:47 +00:00
|
|
|
renderImages: function(template, body, isPreview, cb) {
|
2017-11-27 14:08:18 +00:00
|
|
|
let tplImages = body.match(new RegExp('src="cid:(.*?)"', 'ig'));
|
|
|
|
|
|
|
|
if (!tplImages)
|
|
|
|
tplImages = {};
|
|
|
|
|
|
|
|
// Template default attachments
|
|
|
|
for (var i = 0; i < tplImages.length; i++) {
|
2017-12-26 09:02:47 +00:00
|
|
|
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}"`);
|
|
|
|
}
|
2017-11-27 14:08:18 +00:00
|
|
|
}
|
2018-05-28 10:22:35 +00:00
|
|
|
|
2017-11-27 14:08:18 +00:00
|
|
|
cb(null, body);
|
2018-05-28 10:22:35 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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();
|
2017-11-27 14:08:18 +00:00
|
|
|
}
|
2018-05-28 10:22:35 +00:00
|
|
|
};
|