| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | const nconf = require('nconf'); | 
					
						
							|  |  |  | const validator = require('validator'); | 
					
						
							|  |  |  | const winston = require('winston'); | 
					
						
							| 
									
										
										
										
											2016-04-30 10:47:28 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | const plugins = require('../plugins'); | 
					
						
							|  |  |  | const meta = require('../meta'); | 
					
						
							|  |  |  | const translator = require('../translator'); | 
					
						
							|  |  |  | const widgets = require('../widgets'); | 
					
						
							|  |  |  | const utils = require('../utils'); | 
					
						
							| 
									
										
										
										
											2020-10-11 21:49:37 -04:00
										 |  |  | const slugify = require('../slugify'); | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | const relative_path = nconf.get('relative_path'); | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-13 11:43:39 +02:00
										 |  |  | module.exports = function (middleware) { | 
					
						
							| 
									
										
										
										
											2018-12-17 16:36:43 -05:00
										 |  |  | 	middleware.processRender = function processRender(req, res, next) { | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 		// res.render post-processing, modified from here: https://gist.github.com/mrlannigan/5051687
 | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 		const render = res.render; | 
					
						
							|  |  |  | 		res.render = async function renderOverride(template, options, fn) { | 
					
						
							|  |  |  | 			const self = this; | 
					
						
							|  |  |  | 			const req = this.req; | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 10:47:28 +03:00
										 |  |  | 			options = options || {}; | 
					
						
							| 
									
										
										
										
											2017-02-18 14:00:29 -07:00
										 |  |  | 			if (typeof options === 'function') { | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 				fn = options; | 
					
						
							|  |  |  | 				options = {}; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			options.loggedIn = req.uid > 0; | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 			options.relative_path = relative_path; | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 			options.template = { name: template, [template]: true }; | 
					
						
							|  |  |  | 			options.url = (req.baseUrl + req.path.replace(/^\/api/, '')); | 
					
						
							|  |  |  | 			options.bodyClass = buildBodyClass(req, res, options); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-03 23:59:08 -07:00
										 |  |  | 			const buildResult = await plugins.hooks.fire(`filter:${template}.build`, { req: req, res: res, templateData: options }); | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 			const templateToRender = buildResult.templateData.templateToRender || template; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:06:26 -05:00
										 |  |  | 			const renderResult = await plugins.hooks.fire('filter:middleware.render', { req: req, res: res, templateData: buildResult.templateData }); | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 			options = renderResult.templateData; | 
					
						
							|  |  |  | 			options._header = { | 
					
						
							|  |  |  | 				tags: await meta.tags.parse(req, renderResult, res.locals.metaTags, res.locals.linkTags), | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			options.widgets = await widgets.render(req.uid, { | 
					
						
							| 
									
										
										
										
											2021-02-03 23:59:08 -07:00
										 |  |  | 				template: `${template}.tpl`, | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 				url: options.url, | 
					
						
							|  |  |  | 				templateData: options, | 
					
						
							|  |  |  | 				req: req, | 
					
						
							|  |  |  | 				res: res, | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			res.locals.template = template; | 
					
						
							|  |  |  | 			options._locals = undefined; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (res.locals.isAPI) { | 
					
						
							|  |  |  | 				if (req.route && req.route.path === '/api/') { | 
					
						
							|  |  |  | 					options.title = '[[pages:home]]'; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				req.app.set('json spaces', global.env === 'development' || req.query.pretty ? 4 : 0); | 
					
						
							|  |  |  | 				return res.json(options); | 
					
						
							| 
									
										
										
										
											2016-10-05 15:22:35 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			const results = await utils.promiseParallel({ | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 				header: renderHeaderFooter('renderHeader', req, res, options), | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 				content: renderContent(render, templateToRender, req, res, options), | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 				footer: renderHeaderFooter('renderFooter', req, res, options), | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-03 23:59:08 -07:00
										 |  |  | 			const str = `${results.header + | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 				(res.locals.postHeader || '') + | 
					
						
							| 
									
										
										
										
											2021-02-03 23:59:08 -07:00
										 |  |  | 				results.content | 
					
						
							|  |  |  | 			}<script id="ajaxify-data" type="application/json">${ | 
					
						
							|  |  |  | 				JSON.stringify(options).replace(/<\//g, '<\\/') | 
					
						
							|  |  |  | 			}</script>${ | 
					
						
							|  |  |  | 				res.locals.preFooter || '' | 
					
						
							|  |  |  | 			}${results.footer}`;
 | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 			if (typeof fn !== 'function') { | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 				self.send(str); | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 				fn(null, str); | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		next(); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 	async function renderContent(render, tpl, req, res, options) { | 
					
						
							| 
									
										
										
										
											2021-02-04 00:01:39 -07:00
										 |  |  | 		return new Promise((resolve, reject) => { | 
					
						
							|  |  |  | 			render.call(res, tpl, options, async (err, str) => { | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 				if (err) reject(err); | 
					
						
							|  |  |  | 				else resolve(await translate(str, getLang(req, res))); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 	async function renderHeaderFooter(method, req, res, options) { | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 		let str = ''; | 
					
						
							| 
									
										
										
										
											2020-11-15 16:43:06 -05:00
										 |  |  | 		if (res.locals.renderHeader) { | 
					
						
							|  |  |  | 			str = await middleware[method](req, res, options); | 
					
						
							|  |  |  | 		} else if (res.locals.renderAdminHeader) { | 
					
						
							|  |  |  | 			str = await middleware.admin[method](req, res, options); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			str = ''; | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-11-15 16:43:06 -05:00
										 |  |  | 		return await translate(str, getLang(req, res)); | 
					
						
							| 
									
										
										
										
											2016-10-05 15:22:35 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 	function getLang(req, res) { | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 		let language = (res.locals.config && res.locals.config.userLang) || 'en-GB'; | 
					
						
							| 
									
										
										
										
											2018-02-12 17:12:18 -05:00
										 |  |  | 		if (res.locals.renderAdminHeader) { | 
					
						
							|  |  |  | 			language = (res.locals.config && res.locals.config.acpLang) || 'en-GB'; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-10-26 10:43:18 -04:00
										 |  |  | 		return req.query.lang ? validator.escape(String(req.query.lang)) : language; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	async function translate(str, language) { | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 		const translated = await translator.translate(str, language); | 
					
						
							|  |  |  | 		return translator.unescape(translated); | 
					
						
							| 
									
										
										
										
											2016-10-05 15:22:35 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 14:49:30 -05:00
										 |  |  | 	function buildBodyClass(req, res, templateData) { | 
					
						
							| 
									
										
										
										
											2019-12-16 08:44:55 -05:00
										 |  |  | 		const clean = req.path.replace(/^\/api/, '').replace(/^\/|\/$/g, ''); | 
					
						
							|  |  |  | 		const parts = clean.split('/').slice(0, 3); | 
					
						
							| 
									
										
										
										
											2021-02-04 00:01:39 -07:00
										 |  |  | 		parts.forEach((p, index) => { | 
					
						
							| 
									
										
										
										
											2017-02-02 13:11:27 +03:00
										 |  |  | 			try { | 
					
						
							| 
									
										
										
										
											2020-10-11 21:49:37 -04:00
										 |  |  | 				p = slugify(decodeURIComponent(p)); | 
					
						
							| 
									
										
										
										
											2017-02-02 13:11:27 +03:00
										 |  |  | 			} catch (err) { | 
					
						
							| 
									
										
										
										
											2020-06-20 23:32:12 -04:00
										 |  |  | 				winston.error(err.stack); | 
					
						
							| 
									
										
										
										
											2017-02-02 13:11:27 +03:00
										 |  |  | 				p = ''; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-03-09 20:18:42 +03:00
										 |  |  | 			p = validator.escape(String(p)); | 
					
						
							| 
									
										
										
										
											2021-02-03 23:59:08 -07:00
										 |  |  | 			parts[index] = index ? `${parts[0]}-${p}` : `page-${p || 'home'}`; | 
					
						
							| 
									
										
										
										
											2015-10-16 18:43:40 -04:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-12-01 11:11:37 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (templateData.template.topic) { | 
					
						
							| 
									
										
										
										
											2021-02-03 23:59:08 -07:00
										 |  |  | 			parts.push(`page-topic-category-${templateData.category.cid}`); | 
					
						
							|  |  |  | 			parts.push(`page-topic-category-${slugify(templateData.category.name)}`); | 
					
						
							| 
									
										
										
										
											2017-12-01 11:11:37 -05:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-03-26 12:04:04 -04:00
										 |  |  | 		if (templateData.breadcrumbs) { | 
					
						
							| 
									
										
										
										
											2021-02-04 00:01:39 -07:00
										 |  |  | 			templateData.breadcrumbs.forEach((crumb) => { | 
					
						
							| 
									
										
										
										
											2020-03-26 12:04:04 -04:00
										 |  |  | 				if (crumb.hasOwnProperty('cid')) { | 
					
						
							| 
									
										
										
										
											2021-02-03 23:59:08 -07:00
										 |  |  | 					parts.push(`parent-category-${crumb.cid}`); | 
					
						
							| 
									
										
										
										
											2020-03-26 12:04:04 -04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-12-01 11:11:37 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-03 23:59:08 -07:00
										 |  |  | 		parts.push(`page-status-${res.statusCode}`); | 
					
						
							| 
									
										
										
										
											2015-10-16 18:43:40 -04:00
										 |  |  | 		return parts.join(' '); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-20 15:11:32 -05:00
										 |  |  | }; |