UNPKG

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