| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var nconf = require('nconf'); | 
					
						
							| 
									
										
										
										
											2017-10-25 09:08:03 -04:00
										 |  |  | var jsesc = require('jsesc'); | 
					
						
							| 
									
										
										
										
											2018-12-16 00:09:13 -05:00
										 |  |  | var _ = require('lodash'); | 
					
						
							| 
									
										
										
										
											2020-06-26 15:19:18 -04:00
										 |  |  | const validator = require('validator'); | 
					
						
							| 
									
										
										
										
											2020-06-04 01:14:46 -04:00
										 |  |  | var util = require('util'); | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-29 16:26:27 +03:00
										 |  |  | var db = require('../database'); | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | var user = require('../user'); | 
					
						
							| 
									
										
										
										
											2017-12-20 13:56:14 -07:00
										 |  |  | var topics = require('../topics'); | 
					
						
							|  |  |  | var messaging = require('../messaging'); | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | var meta = require('../meta'); | 
					
						
							|  |  |  | var plugins = require('../plugins'); | 
					
						
							|  |  |  | var navigation = require('../navigation'); | 
					
						
							| 
									
										
										
										
											2017-06-26 17:27:48 -04:00
										 |  |  | var translator = require('../translator'); | 
					
						
							| 
									
										
										
										
											2017-12-18 15:43:57 -05:00
										 |  |  | var privileges = require('../privileges'); | 
					
						
							| 
									
										
										
										
											2020-08-11 11:06:46 -04:00
										 |  |  | var languages = require('../languages'); | 
					
						
							| 
									
										
										
										
											2017-07-06 14:09:59 -04:00
										 |  |  | var utils = require('../utils'); | 
					
						
							| 
									
										
										
										
											2020-06-03 20:18:42 -04:00
										 |  |  | var helpers = require('./helpers'); | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | var controllers = { | 
					
						
							|  |  |  | 	api: require('../controllers/api'), | 
					
						
							| 
									
										
										
										
											2017-02-17 19:31:21 -07:00
										 |  |  | 	helpers: require('../controllers/helpers'), | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | const middleware = module.exports; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | middleware.buildHeader = helpers.try(async function buildHeader(req, res, next) { | 
					
						
							|  |  |  | 	res.locals.renderHeader = true; | 
					
						
							|  |  |  | 	res.locals.isAPI = false; | 
					
						
							|  |  |  | 	const [config] = await Promise.all([ | 
					
						
							|  |  |  | 		controllers.api.loadConfig(req), | 
					
						
							|  |  |  | 		plugins.fireHook('filter:middleware.buildHeader', { req: req, locals: res.locals }), | 
					
						
							|  |  |  | 	]); | 
					
						
							|  |  |  | 	res.locals.config = config; | 
					
						
							|  |  |  | 	next(); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | middleware.buildHeaderAsync = util.promisify(middleware.buildHeader); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function generateHeader(req, res, data) { | 
					
						
							|  |  |  | 	var registrationType = meta.config.registrationType || 'normal'; | 
					
						
							|  |  |  | 	res.locals.config = res.locals.config || {}; | 
					
						
							|  |  |  | 	var templateValues = { | 
					
						
							|  |  |  | 		title: meta.config.title || '', | 
					
						
							|  |  |  | 		'title:url': meta.config['title:url'] || '', | 
					
						
							|  |  |  | 		description: meta.config.description || '', | 
					
						
							|  |  |  | 		'cache-buster': meta.config['cache-buster'] || '', | 
					
						
							|  |  |  | 		'brand:logo': meta.config['brand:logo'] || '', | 
					
						
							|  |  |  | 		'brand:logo:url': meta.config['brand:logo:url'] || '', | 
					
						
							|  |  |  | 		'brand:logo:alt': meta.config['brand:logo:alt'] || '', | 
					
						
							|  |  |  | 		'brand:logo:display': meta.config['brand:logo'] ? '' : 'hide', | 
					
						
							|  |  |  | 		allowRegistration: registrationType === 'normal', | 
					
						
							|  |  |  | 		searchEnabled: plugins.hasListeners('filter:search.query'), | 
					
						
							|  |  |  | 		config: res.locals.config, | 
					
						
							|  |  |  | 		relative_path: nconf.get('relative_path'), | 
					
						
							|  |  |  | 		bodyClass: data.bodyClass, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	templateValues.configJSON = jsesc(JSON.stringify(res.locals.config), { isScriptContext: true }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const results = await utils.promiseParallel({ | 
					
						
							|  |  |  | 		isAdmin: user.isAdministrator(req.uid), | 
					
						
							|  |  |  | 		isGlobalMod: user.isGlobalModerator(req.uid), | 
					
						
							|  |  |  | 		isModerator: user.isModeratorOfAnyCategory(req.uid), | 
					
						
							|  |  |  | 		privileges: privileges.global.get(req.uid), | 
					
						
							|  |  |  | 		user: user.getUserData(req.uid), | 
					
						
							|  |  |  | 		isEmailConfirmSent: (!meta.config.requireEmailConfirmation || req.uid <= 0) ? false : await db.get('uid:' + req.uid + ':confirm:email:sent'), | 
					
						
							|  |  |  | 		languageDirection: translator.translate('[[language:dir]]', res.locals.config.userLang), | 
					
						
							|  |  |  | 		browserTitle: translator.translate(controllers.helpers.buildTitle(translator.unescape(data.title))), | 
					
						
							|  |  |  | 		navigation: navigation.get(req.uid), | 
					
						
							|  |  |  | 		banned: user.bans.isBanned(req.uid), | 
					
						
							|  |  |  | 		banReason: user.bans.getReason(req.uid), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		unreadData: topics.getUnreadData({ uid: req.uid }), | 
					
						
							|  |  |  | 		unreadChatCount: messaging.getUnreadCount(req.uid), | 
					
						
							|  |  |  | 		unreadNotificationCount: user.notifications.getUnreadCount(req.uid), | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2017-12-20 13:56:14 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	if (results.banned) { | 
					
						
							|  |  |  | 		req.logout(); | 
					
						
							|  |  |  | 		return res.redirect('/'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-18 15:32:49 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	const unreadData = { | 
					
						
							|  |  |  | 		'': {}, | 
					
						
							|  |  |  | 		new: {}, | 
					
						
							|  |  |  | 		watched: {}, | 
					
						
							|  |  |  | 		unreplied: {}, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	results.user.unreadData = unreadData; | 
					
						
							|  |  |  | 	results.user.isAdmin = results.isAdmin; | 
					
						
							|  |  |  | 	results.user.isGlobalMod = results.isGlobalMod; | 
					
						
							|  |  |  | 	results.user.isMod = !!results.isModerator; | 
					
						
							|  |  |  | 	results.user.privileges = results.privileges; | 
					
						
							|  |  |  | 	results.user[results.user.status] = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	results.user.email = String(results.user.email); | 
					
						
							|  |  |  | 	results.user['email:confirmed'] = results.user['email:confirmed'] === 1; | 
					
						
							|  |  |  | 	results.user.isEmailConfirmSent = !!results.isEmailConfirmSent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	templateValues.bootswatchSkin = (parseInt(meta.config.disableCustomUserSkins, 10) !== 1 ? res.locals.config.bootswatchSkin : '') || meta.config.bootswatchSkin || ''; | 
					
						
							|  |  |  | 	templateValues.config.bootswatchSkin = templateValues.bootswatchSkin || 'noskin';	// TODO remove in v1.12.0+
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const unreadCounts = results.unreadData.counts; | 
					
						
							|  |  |  | 	const unreadCount = { | 
					
						
							|  |  |  | 		topic: unreadCounts[''] || 0, | 
					
						
							|  |  |  | 		newTopic: unreadCounts.new || 0, | 
					
						
							|  |  |  | 		watchedTopic: unreadCounts.watched || 0, | 
					
						
							|  |  |  | 		unrepliedTopic: unreadCounts.unreplied || 0, | 
					
						
							|  |  |  | 		chat: results.unreadChatCount || 0, | 
					
						
							|  |  |  | 		notification: results.unreadNotificationCount || 0, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2019-05-16 10:51:02 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	Object.keys(unreadCount).forEach(function (key) { | 
					
						
							|  |  |  | 		if (unreadCount[key] > 99) { | 
					
						
							|  |  |  | 			unreadCount[key] = '99+'; | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	const tidsByFilter = results.unreadData.tidsByFilter; | 
					
						
							|  |  |  | 	results.navigation = results.navigation.map(function (item) { | 
					
						
							|  |  |  | 		function modifyNavItem(item, route, filter, content) { | 
					
						
							|  |  |  | 			if (item && validator.unescape(item.originalRoute) === route) { | 
					
						
							|  |  |  | 				unreadData[filter] = _.zipObject(tidsByFilter[filter], tidsByFilter[filter].map(() => true)); | 
					
						
							|  |  |  | 				item.content = content; | 
					
						
							|  |  |  | 				if (unreadCounts[filter] > 0) { | 
					
						
							|  |  |  | 					item.iconClass += ' unread-count'; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 		modifyNavItem(item, '/unread', '', unreadCount.topic); | 
					
						
							|  |  |  | 		modifyNavItem(item, '/unread?filter=new', 'new', unreadCount.newTopic); | 
					
						
							|  |  |  | 		modifyNavItem(item, '/unread?filter=watched', 'watched', unreadCount.watchedTopic); | 
					
						
							|  |  |  | 		modifyNavItem(item, '/unread?filter=unreplied', 'unreplied', unreadCount.unrepliedTopic); | 
					
						
							|  |  |  | 		return item; | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	templateValues.browserTitle = results.browserTitle; | 
					
						
							|  |  |  | 	templateValues.navigation = results.navigation; | 
					
						
							|  |  |  | 	templateValues.unreadCount = unreadCount; | 
					
						
							|  |  |  | 	templateValues.isAdmin = results.user.isAdmin; | 
					
						
							|  |  |  | 	templateValues.isGlobalMod = results.user.isGlobalMod; | 
					
						
							|  |  |  | 	templateValues.showModMenu = results.user.isAdmin || results.user.isGlobalMod || results.user.isMod; | 
					
						
							|  |  |  | 	templateValues.canChat = results.canChat && meta.config.disableChat !== 1; | 
					
						
							|  |  |  | 	templateValues.user = results.user; | 
					
						
							|  |  |  | 	templateValues.userJSON = jsesc(JSON.stringify(results.user), { isScriptContext: true }); | 
					
						
							|  |  |  | 	templateValues.useCustomCSS = meta.config.useCustomCSS && meta.config.customCSS; | 
					
						
							|  |  |  | 	templateValues.customCSS = templateValues.useCustomCSS ? (meta.config.renderedCustomCSS || '') : ''; | 
					
						
							|  |  |  | 	templateValues.useCustomHTML = meta.config.useCustomHTML; | 
					
						
							|  |  |  | 	templateValues.customHTML = templateValues.useCustomHTML ? meta.config.customHTML : ''; | 
					
						
							|  |  |  | 	templateValues.maintenanceHeader = meta.config.maintenanceMode && !results.isAdmin; | 
					
						
							|  |  |  | 	templateValues.defaultLang = meta.config.defaultLang || 'en-GB'; | 
					
						
							|  |  |  | 	templateValues.userLang = res.locals.config.userLang; | 
					
						
							|  |  |  | 	templateValues.languageDirection = results.languageDirection; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	templateValues.template = { name: res.locals.template }; | 
					
						
							|  |  |  | 	templateValues.template[res.locals.template] = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (data.hasOwnProperty('_header')) { | 
					
						
							|  |  |  | 		templateValues.metaTags = data._header.tags.meta; | 
					
						
							|  |  |  | 		templateValues.linkTags = data._header.tags.link; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-11-07 12:34:12 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	if (req.route && req.route.path === '/') { | 
					
						
							|  |  |  | 		modifyTitle(templateValues); | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	const hookReturn = await plugins.fireHook('filter:middleware.renderHeader', { | 
					
						
							|  |  |  | 		req: req, | 
					
						
							|  |  |  | 		res: res, | 
					
						
							|  |  |  | 		templateValues: templateValues, | 
					
						
							|  |  |  | 		data: data, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	return hookReturn.templateValues; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | middleware.renderHeader = async function renderHeader(req, res, data) { | 
					
						
							|  |  |  | 	return await req.app.renderAsync('header', await generateHeader(req, res, data)); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-08-11 11:06:46 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | middleware.renderFooter = async function renderFooter(req, res, templateValues) { | 
					
						
							|  |  |  | 	const data = await plugins.fireHook('filter:middleware.renderFooter', { | 
					
						
							|  |  |  | 		req: req, | 
					
						
							|  |  |  | 		res: res, | 
					
						
							|  |  |  | 		templateValues: templateValues, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2020-08-11 11:06:46 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	const results = await utils.promiseParallel({ | 
					
						
							|  |  |  | 		scripts: plugins.fireHook('filter:scripts.get', []), | 
					
						
							|  |  |  | 		timeagoLocale: (async () => { | 
					
						
							|  |  |  | 			const languageCodes = await languages.listCodes(); | 
					
						
							|  |  |  | 			const userLang = res.locals.config.userLang; | 
					
						
							|  |  |  | 			const timeagoCode = utils.userLangToTimeagoCode(userLang); | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 			if (languageCodes.includes(userLang) && languages.timeagoCodes.includes(timeagoCode)) { | 
					
						
							|  |  |  | 				const pathToLocaleFile = '/vendor/jquery/timeago/locales/jquery.timeago.' + timeagoCode + '.js'; | 
					
						
							|  |  |  | 				return res.locals.config.assetBaseUrl + pathToLocaleFile; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		})(), | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2020-06-03 19:07:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	if (results.timeagoLocale) { | 
					
						
							|  |  |  | 		results.scripts.push(results.timeagoLocale); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data.templateValues.scripts = results.scripts.map(function (script) { | 
					
						
							|  |  |  | 		return { src: script }; | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	data.templateValues.useCustomJS = meta.config.useCustomJS; | 
					
						
							|  |  |  | 	data.templateValues.customJS = data.templateValues.useCustomJS ? meta.config.customJS : ''; | 
					
						
							|  |  |  | 	data.templateValues.isSpider = req.uid === -1; | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 	return await req.app.renderAsync('footer', data.templateValues); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | function modifyTitle(obj) { | 
					
						
							|  |  |  | 	var title = controllers.helpers.buildTitle(meta.config.homePageTitle || '[[pages:home]]'); | 
					
						
							|  |  |  | 	obj.browserTitle = title; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (obj.metaTags) { | 
					
						
							|  |  |  | 		obj.metaTags.forEach(function (tag, i) { | 
					
						
							|  |  |  | 			if (tag.property === 'og:title') { | 
					
						
							|  |  |  | 				obj.metaTags[i].content = title; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2015-10-11 23:05:33 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-21 15:29:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return title; | 
					
						
							|  |  |  | } |