Merge pull request #2 from trucknet-io/transactional-mail-v2
Transactional mail v2
This commit is contained in:
		
						commit
						dc4f0922ef
					
				
					 5 changed files with 108 additions and 1 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
/.idea
 | 
			
		||||
/.vscode
 | 
			
		||||
/last-failed-e2e-test.*
 | 
			
		||||
 | 
			
		||||
node_modules
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										75
									
								
								server/lib/template-sender.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								server/lib/template-sender.js
									
										
									
									
									
										Normal 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue