Merge pull request #2 from trucknet-io/transactional-mail-v2

Transactional mail v2
This commit is contained in:
Alexander Gusev 2019-03-31 11:40:44 +03:00 committed by GitHub
commit dc4f0922ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 108 additions and 1 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
/.idea
/.vscode
/last-failed-e2e-test.*
node_modules

View file

@ -348,7 +348,7 @@ function createApp(appType) {
data: []
};
return status(err.status || 500).json(resp);
return res.status(err.status || 500).json(resp);
} else {
if (err instanceof interoperableErrors.NotLoggedInError) {

View file

@ -8,6 +8,10 @@ const fs = require('fs-extra-promise');
const tryRequire = require('try-require');
const posix = tryRequire('posix');
// process.getuid and process.getgid are not supported on Windows
process.getuid = process.getuid || (() => 100);
process.getgid = process.getuid || (() => 100);
function _getConfigUidGid(userKey, groupKey, defaultUid, defaultGid) {
let uid = defaultUid;
let gid = defaultGid;

View file

@ -0,0 +1,75 @@
'use strict';
const contextHelpers = require('./context-helpers');
const mailers = require('./mailers');
const templates = require('../models/templates');
class TemplateSender {
constructor({ templateId, maxMails = 100 } = {}) {
if (!templateId) {
throw new Error('Cannot create template sender without templateId');
}
this.templateId = templateId;
this.maxMails = maxMails;
}
async send(options) {
this._validateMailOptions(options);
const [mailer, template] = await Promise.all([
mailers.getOrCreateMailer(),
templates.getById(
contextHelpers.getAdminContext(),
this.templateId,
false
)
]);
const html = this._substituteVariables(
template.html,
options.variables
);
return mailer.sendTransactionalMail(
{
to: options.email,
subject: options.subject
},
{
html: { template: html },
locale: options.locale
}
);
}
_validateMailOptions(options) {
let { email, locale } = options;
if (!email || email.length === 0) {
throw new Error('Missing email');
}
if (typeof email === 'string') {
email = email.split(',');
}
if (email.length > this.maxMails) {
throw new Error(
`Cannot send more than ${this.maxMails} emails at once`
);
}
if (!locale) {
throw new Error('Missing locale');
}
}
_substituteVariables(html, variables) {
if (!variables) return html;
return Object.keys(variables).reduce((res, key) => {
return res.replace(
new RegExp(`\\[${key}\\]`, 'gmi'),
variables[key]
);
}, html);
}
}
module.exports = TemplateSender;

View file

@ -16,6 +16,7 @@ const contextHelpers = require('../lib/context-helpers');
const shares = require('../models/shares');
const slugify = require('slugify');
const passport = require('../lib/passport');
const TemplateSender = require('../lib/template-sender');
const campaigns = require('../models/campaigns');
class APIError extends Error {
@ -285,5 +286,31 @@ router.getAsync('/rss/fetch/:campaignCid', passport.loggedIn, async (req, res) =
return res.json();
});
router.postAsync('/templates/:templateId/send', async (req, res) => {
const input = {};
Object.keys(req.body).forEach(key => {
input[
(key || '')
.toString()
.trim()
.toUpperCase()
] = req.body[key] || '';
});
try {
const templateSender = new TemplateSender({
templateId: req.params.templateId
});
const info = await templateSender.send({
email: input.EMAIL,
subject: input.SUBJECT,
locale: req.locale,
variables: input.VARIABLES
});
res.status(200).json({ data: info });
} catch (e) {
throw new APIError(e.message, 400);
}
});
module.exports = router;