-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMailing.js
More file actions
162 lines (139 loc) · 4.58 KB
/
Copy pathMailing.js
File metadata and controls
162 lines (139 loc) · 4.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
var fs = require("fs");
var glob = require('glob');
var path = require('path');
var _ = require('lodash');
var Q = require('q');
var async = require('async');
var Mail = require('./Mail');
function Mailing(options) {
options = options || {};
this.mails = [];
this.mailProvider = options.mailProvider ? options.mailProvider : Mailing.mailProvider;
this.templateEngine = options.templateEngine ? options.templateEngine : Mailing.templateEngine;
if (!this.templateEngine.compile || !_.isFunction(this.templateEngine.compile) || this.templateEngine.compile.length !== 1 || !this.templateEngine.exec || !_.isFunction(this.templateEngine.exec) || this.templateEngine.exec.length !== 2) {
throw new Error(Mailing.TEMPLATE_ENGINE_ERR);
}
if (!this.mailProvider || !_.isFunction(this.mailProvider.send) || this.mailProvider.send.length !== 2) {
throw new Error(Mailing.MAIL_PROVIDER_ERR);
}
}
Mailing.MAIL_INTERNAL_CONCURRENT_LIMIT = 4;
Mailing.MAIL_PROVIDER_ERR = "Please use a supported email provider like `transacemail-mandrill`\nThe provider should implement .send(mail, callback);";
Mailing.TEMPLATE_ENGINE_ERR = "the Template Engine should implement\ncompile(templateString): Function\nexec(fnCompiledTemplate, data): String";
/**
* Mailing Factory
* @param {String} path Path to mails folder
* @param {Object} options Option object option parameters are:
* templateEngine : Set the Template Engine
* mailProvider : Set the Mail Provider
* @optional
* @return {Mailing}
*/
Mailing.compile = function (path, options) {
var mailing = new Mailing(options);
return mailing._reset(path);
};
/**
* Send emails that comply with .sendIf(args, ...)
* @param {Variadic} args... Any number of arguments that will be forwarded to each email `.sendIf`
* @return {Promise}
*/
Mailing.prototype.sendIf = function () {
var deferred = Q.defer();
var args = _.toArray(arguments);
function mailChecker(mail, fn) {
mail.sendIf.apply(mail, args.concat(this._sendThroughProvider.bind(this, function (err, ok) {
// We must silent the error otherwise forEachLimit will be stopped
fn(null, ok);
}, mail)));
}
async.forEachLimit(
this.mails,
Mailing.MAIL_INTERNAL_CONCURRENT_LIMIT,
mailChecker.bind(this),
deferred.makeNodeResolver());
return deferred.promise;
};
Mailing.prototype.getMail = function (name) {
return _.find(this.mails, function (mail) {
return mail.getName() === name;
});
};
/**
* Helper to send one email (beware the sendIf function must accept the parameters)
*/
Mailing.prototype.sendMail = function (templateName /*, args... , fn*/ ) {
var args = _.toArray(arguments).slice(1);
var fn = args.pop();
if (!_.isFunction(fn)) {
throw new Error(".sendMail: last parameter must be a function");
}
var mail = this.getMail(templateName);
if (!mail) {
return fn(new Error("Template not found"));
}
args.push(this._sendThroughProvider.bind(this, fn, mail));
mail.sendIf.apply(mail, args);
};
/**
* Default mail provider
* @type {Object}
*/
Mailing.mailProvider = {
send: function (fn, mail) {
throw new Error(Mailing.MAIL_PROVIDER_ERR);
}
};
/**
* Default template engine (Underscore template)
* @type {Object}
*/
Mailing.templateEngine = {
compile: function (templateString) {
return _.template(templateString, null, {
evaluate: /\{\{#([\s\S]+?)\}\}/g, // {{# console.log("blah") }}
interpolate: /\{\{[^#\{]([\s\S]+?)[^\}]\}\}/g, // {{ title }}
escape: /\{\{\{([\s\S]+?)\}\}\}/g // {{{ title }}}
});
},
exec: function (compiledTemplate, data) {
return compiledTemplate(data);
}
};
/**
* ._sendThroughProvider
* @ignore
* @param {Function} fn [description]
* @param {[type]} mail [description]
* @param {[type]} sendIfReturn [description]
* @return {[type]} [description]
*/
Mailing.prototype._sendThroughProvider = function (fn, mail, sendIfReturn) {
if (!sendIfReturn) {
return fn(new Error("sendIf returned a falsy value"));
}
this.mailProvider.send(mail._compileWith(sendIfReturn), fn);
};
/**
* ._reset
* @ignore
* @param {[type]} mailDir [description]
* @return {[type]} [description]
*/
Mailing.prototype._reset = function (mailDir) {
glob(path.resolve(mailDir, './' + '*.meta.js'), {
sync: true
}, function (err, files) {
this.mails = files.map(Mail.Factory.bind(Mail, this.templateEngine));
this.mails.forEach(function setRef(mail) {
mail._mailing = this;
}.bind(this));
}.bind(this));
return this;
};
/**
* Export Mail
* @ignore
*/
Mailing.Mail = Mail;
module.exports = Mailing;