UNPKG

17 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 return new (P || (P = Promise))(function (resolve, reject) {
4 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 step((generator = generator.apply(thisArg, _arguments || [])).next());
8 });
9};
10var __generator = (this && this.__generator) || function (thisArg, body) {
11 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13 function verb(n) { return function (v) { return step([n, v]); }; }
14 function step(op) {
15 if (f) throw new TypeError("Generator is already executing.");
16 while (_) try {
17 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18 if (y = 0, t) op = [op[0] & 2, t.value];
19 switch (op[0]) {
20 case 0: case 1: t = op; break;
21 case 4: _.label++; return { value: op[1], done: false };
22 case 5: _.label++; y = op[1]; op = [0]; continue;
23 case 7: op = _.ops.pop(); _.trys.pop(); continue;
24 default:
25 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29 if (t[2]) _.ops.pop();
30 _.trys.pop(); continue;
31 }
32 op = body.call(thisArg, _);
33 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35 }
36};
37Object.defineProperty(exports, "__esModule", { value: true });
38var app_1 = require("./app");
39var render_response_1 = require("./render.response");
40var redirect_response_1 = require("./redirect.response");
41var skip_response_1 = require("./skip.response");
42var unauthorized_response_1 = require("./unauthorized.response");
43var file_response_1 = require("./file.response");
44var media_entity_1 = require("./entities/media.entity");
45var status_error_1 = require("./status-error");
46var nodemailer_1 = require("nodemailer");
47var logger_1 = require("./logger");
48var mailClient;
49var guard = false;
50function syncronizedInit() {
51 if (guard)
52 return;
53 guard = true;
54 if (!mailClient) {
55 if (!app_1.app.config.mailer.host) {
56 try {
57 nodemailer_1.createTestAccount(function (err, account) {
58 if (err) {
59 logger_1.logger.error(err);
60 guard = false;
61 return;
62 }
63 mailClient = nodemailer_1.createTransport({
64 host: "smtp.ethereal.email",
65 port: 587,
66 secure: false,
67 auth: {
68 user: account.user,
69 pass: account.pass // generated ethereal password
70 }
71 });
72 guard = false;
73 });
74 }
75 catch (e) {
76 guard = false;
77 logger_1.logger.error(e);
78 }
79 }
80 else {
81 try {
82 mailClient = nodemailer_1.createTransport(app_1.app.config.mailer);
83 guard = false;
84 }
85 catch (e) {
86 guard = false;
87 logger_1.logger.error(e);
88 }
89 }
90 }
91}
92var FlashType;
93(function (FlashType) {
94 FlashType[FlashType["primary"] = 0] = "primary";
95 FlashType[FlashType["secondary"] = 1] = "secondary";
96 FlashType[FlashType["success"] = 2] = "success";
97 FlashType[FlashType["danger"] = 3] = "danger";
98 FlashType[FlashType["warning"] = 4] = "warning";
99 FlashType[FlashType["info"] = 5] = "info";
100 FlashType[FlashType["light"] = 6] = "light";
101 FlashType[FlashType["dark"] = 7] = "dark";
102})(FlashType = exports.FlashType || (exports.FlashType = {}));
103function mapFlashTypeToString(type) {
104 switch (type) {
105 case FlashType.primary:
106 return "primary";
107 case FlashType.secondary:
108 return "secondary";
109 case FlashType.success:
110 return "success";
111 case FlashType.danger:
112 return "danger";
113 case FlashType.warning:
114 return "warning";
115 case FlashType.info:
116 return "info";
117 case FlashType.light:
118 return "light";
119 case FlashType.dark:
120 return "dark";
121 }
122}
123/**
124 * This class defines the basic class for any controllers. It implements a lot
125 * of utility methods in order to correctly generate any response.
126 */
127var BaseController = /** @class */ (function () {
128 function BaseController(app) {
129 this.logger = logger_1.logger;
130 this.app = app;
131 syncronizedInit();
132 }
133 Object.defineProperty(BaseController.prototype, "metadata", {
134 get: function () {
135 return this._metadata;
136 },
137 enumerable: true,
138 configurable: true
139 });
140 /**
141 * This method is called only when the constructed has been completed.
142 * Since this method is async, it can be used to perform some initialization
143 * that needed the use of the await keyword. */
144 BaseController.prototype.postConstructor = function () {
145 return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
146 return [2 /*return*/];
147 }); });
148 };
149 /**
150 * Add a value to the current request context.
151 * Any variable added with this method will available in the template context
152 * thought the @method render method.
153 * @param req the current Request
154 * @param key the key of the value to add
155 * @param value the value to add
156 */
157 BaseController.prototype.addToContext = function (req, key, value) {
158 if (!req.lynxContext) {
159 req.lynxContext = {};
160 }
161 req.lynxContext[key] = value;
162 };
163 /**
164 * Utility method to generate an error with a status code.
165 * This method should be used instead of the usual throw new Error(msg).
166 * In this way, a proper HTTP status code can be used (for example, 404 or 500),
167 * instead of the default 400.
168 * @param status the http status code to return
169 * @param message the error message
170 * @return a new @type StatusError object
171 */
172 BaseController.prototype.error = function (status, message) {
173 var err = new status_error_1.default(message);
174 err.statusCode = status;
175 return err;
176 };
177 /**
178 * This method generate an url to a route starting from the route name and
179 * optionally its parameters.
180 * If a parameter not is used to generate the route url, it will be appended
181 * as a query parameter.
182 * @param name the name of the route
183 * @param parameters a plain object containing the paramters for the route.
184 */
185 BaseController.prototype.route = function (name, parameters) {
186 return this.app.route(name, parameters);
187 };
188 /**
189 * Generate a web page starting from a template and using a generated context.
190 * @param view the name of the view
191 * @param req the request object
192 * @param context a plain object containing any necessary data needed by the view
193 */
194 BaseController.prototype.render = function (view, req, context) {
195 if (!view.endsWith(".njk")) {
196 view = view + ".njk";
197 }
198 if (!context) {
199 context = {};
200 }
201 context.req = req;
202 context.flash = req.session.sessionFlash;
203 for (var key in req.lynxContext) {
204 context[key] = req.lynxContext[key];
205 }
206 delete req.session.sessionFlash;
207 return new render_response_1.default(view, context);
208 };
209 /**
210 * Redirect the current route to another
211 * @param routeName the new of the target route
212 * @param routeParams a plain object containing the paramters for the route.
213 */
214 BaseController.prototype.redirect = function (routeName, routeParams) {
215 return new redirect_response_1.default(this.route(routeName, routeParams));
216 };
217 /**
218 * Add a flash message in the current request.
219 * @param msg the FlashMessage to be included
220 * @param req the request
221 */
222 BaseController.prototype.addFlashMessage = function (msg, req) {
223 var session = req.session;
224 if (!session.sessionFlash) {
225 session.sessionFlash = [];
226 }
227 session.sessionFlash.push({
228 type: mapFlashTypeToString(msg.type),
229 message: this.tr(msg.message, req)
230 });
231 };
232 /**
233 * Add a success flash message in the current request.
234 * @param msg the string (can be localized) of the message
235 * @param req the request
236 */
237 BaseController.prototype.addSuccessMessagge = function (msg, req) {
238 this.addFlashMessage({ type: FlashType.success, message: msg }, req);
239 };
240 /**
241 * Add an error flash message in the current request.
242 * @param msg the string (can be localized) of the message
243 * @param req the request
244 */
245 BaseController.prototype.addErrorMessage = function (msg, req) {
246 this.addFlashMessage({ type: FlashType.danger, message: msg }, req);
247 };
248 /**
249 * Generate a response suitable to file download. This method can also be
250 * used to generate images of specific dimensions.
251 * @param path the string path of the file, or a Media object to be downloaded
252 * @param options options to correctly generate the output file
253 */
254 BaseController.prototype.download = function (path, options) {
255 var f;
256 if (path instanceof media_entity_1.default) {
257 if (path.isDirectory) {
258 throw new Error("unable to download a directory");
259 }
260 f = new file_response_1.default(path.fileName);
261 f.contentType = path.mimetype;
262 if (path.originalName) {
263 f.fileName = path.originalName;
264 }
265 }
266 else {
267 f = new file_response_1.default(path);
268 }
269 if (options) {
270 f.options = options;
271 }
272 return f;
273 };
274 /**
275 * Generate an unauthorized response.
276 */
277 BaseController.prototype.unauthorized = function () {
278 return new unauthorized_response_1.default();
279 };
280 /**
281 * Generate a skip resopnse. In this particuar case, the original Express `next()`
282 * will be executed, causing the controller chain to continue its execution.
283 */
284 BaseController.prototype.next = function () {
285 return new skip_response_1.default();
286 };
287 /**
288 * Utility method to send emails from a controller.
289 * This method is similar to the `sendMail` method, but define a lower level API.
290 * Indeed, it directly accepts the text and the html of the email, and not the templates urls.
291 * @param dest the email destination (can also be an array of addresses)
292 * @param subject the subject of the email
293 * @param text the text version of the email
294 * @param html the html version of the email
295 */
296 BaseController.prototype.sendRawMail = function (dest, subject, text, html) {
297 return __awaiter(this, void 0, void 0, function () {
298 var mailOptions, result, e_1;
299 return __generator(this, function (_a) {
300 switch (_a.label) {
301 case 0:
302 mailOptions = {
303 from: this.app.config.mailer.sender,
304 to: dest,
305 subject: subject,
306 text: text,
307 html: html // html body
308 };
309 _a.label = 1;
310 case 1:
311 _a.trys.push([1, 3, , 4]);
312 return [4 /*yield*/, mailClient.sendMail(mailOptions)];
313 case 2:
314 result = _a.sent();
315 if (result) {
316 logger_1.logger.debug("Preview URL: %s", nodemailer_1.getTestMessageUrl(result));
317 }
318 return [2 /*return*/, true];
319 case 3:
320 e_1 = _a.sent();
321 logger_1.logger.error(e_1);
322 return [3 /*break*/, 4];
323 case 4: return [2 /*return*/, false];
324 }
325 });
326 });
327 };
328 /**
329 * Utility method to send an email from a controller. This method is async,
330 * so use the await keyword (or eventually a promise) to correctly read the
331 * return value.
332 * This method uses the template engine to compile the email.
333 * NOTE: internally, this method uses the `sendRawMail` method.
334 * @param req the current request
335 * @param dest the email destination (can also be an array of addresses)
336 * @param subjectTemplateString the subject of the email, that can also be a string template
337 * @param textTemplate the text version of the email, referencing a path in the view folders
338 * @param htmlTemplate the html version of the email, referencing a path in the view folders
339 * @param context a plain object containing any necessary data needed by the view
340 */
341 BaseController.prototype.sendMail = function (req, dest, subjectTemplateString, textTemplate, htmlTemplate, context) {
342 return __awaiter(this, void 0, void 0, function () {
343 var subject, text, html;
344 return __generator(this, function (_a) {
345 if (!context) {
346 context = {};
347 }
348 context.req = req;
349 subject = this.app.nunjucksEnvironment.renderString(subjectTemplateString, context);
350 if (!textTemplate.endsWith(".njk")) {
351 textTemplate += ".njk";
352 }
353 if (!htmlTemplate.endsWith(".njk")) {
354 htmlTemplate += ".njk";
355 }
356 text = this.app.nunjucksEnvironment.render(textTemplate, context);
357 html = this.app.nunjucksEnvironment.render(htmlTemplate, context);
358 return [2 /*return*/, this.sendRawMail(dest, subject, text, html)];
359 });
360 });
361 };
362 /**
363 * Utility method to obtain a translated string.
364 * @param str the string key to be translated
365 * @param req the original request
366 */
367 BaseController.prototype.tr = function (str, req) {
368 return this.app.translate(str, req);
369 };
370 /**
371 * Utility method to obtain a translated string, formatted with parameters.
372 * Each parameter should be encoded as {0}, {1}, etc...
373 * @param str the string key to be translated
374 * @param req the original request
375 * @param args the arguments to format the string
376 */
377 BaseController.prototype.trFormat = function (str, req) {
378 var args = [];
379 for (var _i = 2; _i < arguments.length; _i++) {
380 args[_i - 2] = arguments[_i];
381 }
382 var translated = this.tr(str, req);
383 return this.format(translated, args);
384 };
385 BaseController.prototype.format = function (fmt) {
386 var args = [];
387 for (var _i = 1; _i < arguments.length; _i++) {
388 args[_i - 1] = arguments[_i];
389 }
390 if (!fmt.match(/^(?:(?:(?:[^{}]|(?:\{\{)|(?:\}\}))+)|(?:\{[0-9]+\}))+$/)) {
391 throw new Error('invalid format string.');
392 }
393 return fmt.replace(/((?:[^{}]|(?:\{\{)|(?:\}\}))+)|(?:\{([0-9]+)\})/g, function (_, str, index) {
394 if (str) {
395 return str.replace(/(?:{{)|(?:}})/g, function (m) { return m[0]; });
396 }
397 else {
398 if (index >= args.length) {
399 throw new Error('argument index is out of range in format');
400 }
401 return args[index];
402 }
403 });
404 };
405 return BaseController;
406}());
407exports.BaseController = BaseController;