| 
									
										
										
										
											2014-11-15 23:22:57 -05:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | const nconf = require('nconf'); | 
					
						
							|  |  |  | const validator = require('validator'); | 
					
						
							|  |  |  | const querystring = require('querystring'); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:00:37 -04:00
										 |  |  | const _ = require('lodash'); | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | const user = require('../user'); | 
					
						
							|  |  |  | const privileges = require('../privileges'); | 
					
						
							|  |  |  | const categories = require('../categories'); | 
					
						
							|  |  |  | const plugins = require('../plugins'); | 
					
						
							|  |  |  | const meta = require('../meta'); | 
					
						
							|  |  |  | const middleware = require('../middleware'); | 
					
						
							| 
									
										
										
										
											2020-03-26 20:25:23 -04:00
										 |  |  | const translator = require('../translator'); | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 20:25:23 -04:00
										 |  |  | const isLanguageKey = /^\[\[[\w.\-_:]+]]$/; | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | const helpers = module.exports; | 
					
						
							| 
									
										
										
										
											2014-11-15 23:22:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 01:14:46 -04:00
										 |  |  | helpers.noScriptErrors = async function (req, res, error, httpStatus) { | 
					
						
							| 
									
										
										
										
											2017-07-20 08:51:04 -04:00
										 |  |  | 	if (req.body.noscript !== 'true') { | 
					
						
							|  |  |  | 		return res.status(httpStatus).send(error); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	const httpStatusString = httpStatus.toString(); | 
					
						
							| 
									
										
										
										
											2020-06-04 01:14:46 -04:00
										 |  |  | 	await middleware.buildHeaderAsync(req, res); | 
					
						
							|  |  |  | 	res.status(httpStatus).render(httpStatusString, { | 
					
						
							|  |  |  | 		path: req.path, | 
					
						
							|  |  |  | 		loggedIn: req.loggedIn, | 
					
						
							|  |  |  | 		error: error, | 
					
						
							|  |  |  | 		returnLink: true, | 
					
						
							|  |  |  | 		title: '[[global:' + httpStatusString + '.title]]', | 
					
						
							| 
									
										
										
										
											2017-07-20 08:51:04 -04:00
										 |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-18 14:37:32 -04:00
										 |  |  | helpers.terms = { | 
					
						
							|  |  |  | 	daily: 'day', | 
					
						
							|  |  |  | 	weekly: 'week', | 
					
						
							|  |  |  | 	monthly: 'month', | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | helpers.buildQueryString = function (query, key, value) { | 
					
						
							|  |  |  | 	const queryObj = _.clone(query); | 
					
						
							|  |  |  | 	if (value) { | 
					
						
							|  |  |  | 		queryObj[key] = value; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		delete queryObj[key]; | 
					
						
							| 
									
										
										
										
											2018-06-18 14:37:32 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | 	delete queryObj._; | 
					
						
							|  |  |  | 	return Object.keys(queryObj).length ? '?' + querystring.stringify(queryObj) : ''; | 
					
						
							| 
									
										
										
										
											2018-06-18 14:37:32 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 11:34:32 -04:00
										 |  |  | helpers.addLinkTags = function (params) { | 
					
						
							|  |  |  | 	params.res.locals.linkTags = params.res.locals.linkTags || []; | 
					
						
							|  |  |  | 	params.res.locals.linkTags.push({ | 
					
						
							|  |  |  | 		rel: 'canonical', | 
					
						
							|  |  |  | 		href: nconf.get('url') + '/' + params.url, | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	params.tags.forEach(function (rel) { | 
					
						
							|  |  |  | 		rel.href = nconf.get('url') + '/' + params.url + rel.href; | 
					
						
							|  |  |  | 		params.res.locals.linkTags.push(rel); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-18 14:37:32 -04:00
										 |  |  | helpers.buildFilters = function (url, filter, query) { | 
					
						
							| 
									
										
										
										
											2017-10-19 13:53:05 -04:00
										 |  |  | 	return [{ | 
					
						
							|  |  |  | 		name: '[[unread:all-topics]]', | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | 		url: url + helpers.buildQueryString(query, 'filter', ''), | 
					
						
							| 
									
										
										
										
											2017-10-19 13:53:05 -04:00
										 |  |  | 		selected: filter === '', | 
					
						
							|  |  |  | 		filter: '', | 
					
						
							| 
									
										
										
										
											2020-07-08 14:09:10 -04:00
										 |  |  | 		icon: 'fa-book', | 
					
						
							| 
									
										
										
										
											2017-10-19 13:53:05 -04:00
										 |  |  | 	}, { | 
					
						
							|  |  |  | 		name: '[[unread:new-topics]]', | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | 		url: url + helpers.buildQueryString(query, 'filter', 'new'), | 
					
						
							| 
									
										
										
										
											2017-10-19 13:53:05 -04:00
										 |  |  | 		selected: filter === 'new', | 
					
						
							|  |  |  | 		filter: 'new', | 
					
						
							| 
									
										
										
										
											2020-07-08 14:09:10 -04:00
										 |  |  | 		icon: 'fa-clock-o', | 
					
						
							| 
									
										
										
										
											2017-10-19 13:53:05 -04:00
										 |  |  | 	}, { | 
					
						
							|  |  |  | 		name: '[[unread:watched-topics]]', | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | 		url: url + helpers.buildQueryString(query, 'filter', 'watched'), | 
					
						
							| 
									
										
										
										
											2017-10-19 13:53:05 -04:00
										 |  |  | 		selected: filter === 'watched', | 
					
						
							|  |  |  | 		filter: 'watched', | 
					
						
							| 
									
										
										
										
											2020-07-08 14:09:10 -04:00
										 |  |  | 		icon: 'fa-bell-o', | 
					
						
							| 
									
										
										
										
											2017-10-19 13:53:05 -04:00
										 |  |  | 	}, { | 
					
						
							|  |  |  | 		name: '[[unread:unreplied-topics]]', | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | 		url: url + helpers.buildQueryString(query, 'filter', 'unreplied'), | 
					
						
							| 
									
										
										
										
											2017-10-19 13:53:05 -04:00
										 |  |  | 		selected: filter === 'unreplied', | 
					
						
							|  |  |  | 		filter: 'unreplied', | 
					
						
							| 
									
										
										
										
											2020-07-08 14:09:10 -04:00
										 |  |  | 		icon: 'fa-reply', | 
					
						
							| 
									
										
										
										
											2017-10-19 13:53:05 -04:00
										 |  |  | 	}]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-18 14:37:32 -04:00
										 |  |  | helpers.buildTerms = function (url, term, query) { | 
					
						
							|  |  |  | 	return [{ | 
					
						
							|  |  |  | 		name: '[[recent:alltime]]', | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | 		url: url + helpers.buildQueryString(query, 'term', ''), | 
					
						
							| 
									
										
										
										
											2018-06-18 14:37:32 -04:00
										 |  |  | 		selected: term === 'alltime', | 
					
						
							|  |  |  | 		term: 'alltime', | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		name: '[[recent:day]]', | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | 		url: url + helpers.buildQueryString(query, 'term', 'daily'), | 
					
						
							| 
									
										
										
										
											2018-06-18 14:37:32 -04:00
										 |  |  | 		selected: term === 'day', | 
					
						
							|  |  |  | 		term: 'day', | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		name: '[[recent:week]]', | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | 		url: url + helpers.buildQueryString(query, 'term', 'weekly'), | 
					
						
							| 
									
										
										
										
											2018-06-18 14:37:32 -04:00
										 |  |  | 		selected: term === 'week', | 
					
						
							|  |  |  | 		term: 'week', | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		name: '[[recent:month]]', | 
					
						
							| 
									
										
										
										
											2020-09-13 19:41:39 -04:00
										 |  |  | 		url: url + helpers.buildQueryString(query, 'term', 'monthly'), | 
					
						
							| 
									
										
										
										
											2018-06-18 14:37:32 -04:00
										 |  |  | 		selected: term === 'month', | 
					
						
							|  |  |  | 		term: 'month', | 
					
						
							|  |  |  | 	}]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 01:14:46 -04:00
										 |  |  | helpers.notAllowed = async function (req, res, error) { | 
					
						
							|  |  |  | 	const data = await plugins.fireHook('filter:helpers.notAllowed', { | 
					
						
							| 
									
										
										
										
											2016-06-22 14:58:46 -04:00
										 |  |  | 		req: req, | 
					
						
							|  |  |  | 		res: res, | 
					
						
							| 
									
										
										
										
											2017-02-17 19:31:21 -07:00
										 |  |  | 		error: error, | 
					
						
							| 
									
										
										
										
											2020-06-04 01:14:46 -04:00
										 |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (req.loggedIn || req.uid === -1) { | 
					
						
							|  |  |  | 		if (res.locals.isAPI) { | 
					
						
							| 
									
										
										
										
											2020-10-01 10:52:05 -04:00
										 |  |  | 			helpers.formatApiResponse(403, res, error); | 
					
						
							| 
									
										
										
										
											2014-11-15 23:22:57 -05:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2020-06-04 01:14:46 -04:00
										 |  |  | 			await middleware.buildHeaderAsync(req, res); | 
					
						
							|  |  |  | 			res.status(403).render('403', { | 
					
						
							|  |  |  | 				path: req.path, | 
					
						
							|  |  |  | 				loggedIn: req.loggedIn, | 
					
						
							|  |  |  | 				error: data.error, | 
					
						
							|  |  |  | 				title: '[[global:403.title]]', | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2014-11-15 23:22:57 -05:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-04 01:14:46 -04:00
										 |  |  | 	} else if (res.locals.isAPI) { | 
					
						
							|  |  |  | 		req.session.returnTo = req.url.replace(/^\/api/, ''); | 
					
						
							| 
									
										
										
										
											2020-10-01 10:52:05 -04:00
										 |  |  | 		helpers.formatApiResponse(401, res, error); | 
					
						
							| 
									
										
										
										
											2020-06-04 01:14:46 -04:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		req.session.returnTo = req.url; | 
					
						
							|  |  |  | 		res.redirect(nconf.get('relative_path') + '/login'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-15 23:22:57 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-06 10:48:35 -04:00
										 |  |  | helpers.redirect = function (res, url, permanent) { | 
					
						
							| 
									
										
										
										
											2015-03-09 18:22:44 -04:00
										 |  |  | 	if (res.locals.isAPI) { | 
					
						
							| 
									
										
										
										
											2017-07-05 11:36:35 -04:00
										 |  |  | 		res.set('X-Redirect', encodeURI(url)).status(200).json(url); | 
					
						
							| 
									
										
										
										
											2015-03-09 18:22:44 -04:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2020-08-06 10:48:35 -04:00
										 |  |  | 		res.redirect(permanent ? 308 : 307, nconf.get('relative_path') + encodeURI(url)); | 
					
						
							| 
									
										
										
										
											2015-03-09 18:22:44 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | helpers.buildCategoryBreadcrumbs = async function (cid) { | 
					
						
							|  |  |  | 	const breadcrumbs = []; | 
					
						
							| 
									
										
										
										
											2014-12-11 22:55:00 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	while (parseInt(cid, 10)) { | 
					
						
							|  |  |  | 		/* eslint-disable no-await-in-loop */ | 
					
						
							|  |  |  | 		const data = await categories.getCategoryFields(cid, ['name', 'slug', 'parentCid', 'disabled', 'isSection']); | 
					
						
							|  |  |  | 		if (!data.disabled && !data.isSection) { | 
					
						
							| 
									
										
										
										
											2016-04-21 11:40:40 -04:00
										 |  |  | 			breadcrumbs.unshift({ | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 				text: String(data.name), | 
					
						
							|  |  |  | 				url: nconf.get('relative_path') + '/category/' + data.slug, | 
					
						
							| 
									
										
										
										
											2020-03-26 12:04:04 -04:00
										 |  |  | 				cid: cid, | 
					
						
							| 
									
										
										
										
											2016-04-21 11:40:40 -04:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 		cid = data.parentCid; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (meta.config.homePageRoute && meta.config.homePageRoute !== 'categories') { | 
					
						
							| 
									
										
										
										
											2015-01-29 01:06:48 -05:00
										 |  |  | 		breadcrumbs.unshift({ | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 			text: '[[global:header.categories]]', | 
					
						
							|  |  |  | 			url: nconf.get('relative_path') + '/categories', | 
					
						
							| 
									
										
										
										
											2014-12-11 22:55:00 -05:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-29 01:06:48 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	breadcrumbs.unshift({ | 
					
						
							|  |  |  | 		text: '[[global:home]]', | 
					
						
							|  |  |  | 		url: nconf.get('relative_path') + '/', | 
					
						
							| 
									
										
										
										
											2015-01-29 01:06:48 -05:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return breadcrumbs; | 
					
						
							| 
									
										
										
										
											2015-01-29 01:06:48 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-13 11:43:39 +02:00
										 |  |  | helpers.buildBreadcrumbs = function (crumbs) { | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	const breadcrumbs = [ | 
					
						
							| 
									
										
										
										
											2015-01-29 01:06:48 -05:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			text: '[[global:home]]', | 
					
						
							| 
									
										
										
										
											2017-02-17 19:31:21 -07:00
										 |  |  | 			url: nconf.get('relative_path') + '/', | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2015-01-29 01:06:48 -05:00
										 |  |  | 	]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-13 11:43:39 +02:00
										 |  |  | 	crumbs.forEach(function (crumb) { | 
					
						
							| 
									
										
										
										
											2015-01-29 01:06:48 -05:00
										 |  |  | 		if (crumb) { | 
					
						
							|  |  |  | 			if (crumb.url) { | 
					
						
							|  |  |  | 				crumb.url = nconf.get('relative_path') + crumb.url; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			breadcrumbs.push(crumb); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-12-11 22:55:00 -05:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-01-29 01:06:48 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return breadcrumbs; | 
					
						
							| 
									
										
										
										
											2014-12-11 22:55:00 -05:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-11-15 23:22:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-13 11:43:39 +02:00
										 |  |  | helpers.buildTitle = function (pageTitle) { | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	const titleLayout = meta.config.titleLayout || '{pageTitle} | {browserTitle}'; | 
					
						
							| 
									
										
										
										
											2015-09-23 01:59:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	const browserTitle = validator.escape(String(meta.config.browserTitle || meta.config.title || 'NodeBB')); | 
					
						
							| 
									
										
										
										
											2015-09-23 01:59:13 -04:00
										 |  |  | 	pageTitle = pageTitle || ''; | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	const title = titleLayout.replace('{pageTitle}', () => pageTitle).replace('{browserTitle}', () => browserTitle); | 
					
						
							| 
									
										
										
										
											2015-09-23 01:59:13 -04:00
										 |  |  | 	return title; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | helpers.getCategories = async function (set, uid, privilege, selectedCid) { | 
					
						
							|  |  |  | 	const cids = await categories.getCidsByPrivilege(set, uid, privilege); | 
					
						
							| 
									
										
										
										
											2020-10-02 16:35:20 -04:00
										 |  |  | 	return await getCategoryData(cids, uid, selectedCid, privilege); | 
					
						
							| 
									
										
										
										
											2018-08-17 16:39:50 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 16:35:20 -04:00
										 |  |  | helpers.getCategoriesByStates = async function (uid, selectedCid, states, privilege = 'topics:read') { | 
					
						
							| 
									
										
										
										
											2019-10-04 22:00:37 -04:00
										 |  |  | 	const cids = await categories.getAllCidsFromSet('categories:cid'); | 
					
						
							| 
									
										
										
										
											2020-10-02 16:35:20 -04:00
										 |  |  | 	return await getCategoryData(cids, uid, selectedCid, states, privilege); | 
					
						
							| 
									
										
										
										
											2018-08-17 16:39:50 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 16:35:20 -04:00
										 |  |  | async function getCategoryData(cids, uid, selectedCid, states, privilege) { | 
					
						
							| 
									
										
										
										
											2018-08-17 16:39:50 -04:00
										 |  |  | 	if (selectedCid && !Array.isArray(selectedCid)) { | 
					
						
							|  |  |  | 		selectedCid = [selectedCid]; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-12 14:57:37 -04:00
										 |  |  | 	selectedCid = selectedCid && selectedCid.map(String); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:00:37 -04:00
										 |  |  | 	states = states || [categories.watchStates.watching, categories.watchStates.notwatching]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const [allowed, watchState, categoryData, isAdmin] = await Promise.all([ | 
					
						
							| 
									
										
										
										
											2020-10-02 16:35:20 -04:00
										 |  |  | 		privileges.categories.isUserAllowedTo(privilege, cids, uid), | 
					
						
							| 
									
										
										
										
											2019-10-04 22:00:37 -04:00
										 |  |  | 		categories.getWatchState(cids, uid), | 
					
						
							|  |  |  | 		categories.getCategoriesData(cids), | 
					
						
							|  |  |  | 		user.isAdministrator(uid), | 
					
						
							|  |  |  | 	]); | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-20 19:04:47 -04:00
										 |  |  | 	categories.getTree(categoryData); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:00:37 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	const cidToAllowed = _.zipObject(cids, allowed.map(allowed => isAdmin || allowed)); | 
					
						
							|  |  |  | 	const cidToCategory = _.zipObject(cids, categoryData); | 
					
						
							|  |  |  | 	const cidToWatchState = _.zipObject(cids, watchState); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const visibleCategories = categoryData.filter(function (c) { | 
					
						
							| 
									
										
										
										
											2019-10-30 12:47:01 -04:00
										 |  |  | 		const hasVisibleChildren = checkVisibleChildren(c, cidToAllowed, cidToWatchState, states); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:00:37 -04:00
										 |  |  | 		const isCategoryVisible = c && cidToAllowed[c.cid] && !c.link && !c.disabled && states.includes(cidToWatchState[c.cid]); | 
					
						
							|  |  |  | 		const shouldBeRemoved = !hasVisibleChildren && !isCategoryVisible; | 
					
						
							| 
									
										
										
										
											2020-10-02 16:35:20 -04:00
										 |  |  | 		const shouldBeDisaplayedAsDisabled = hasVisibleChildren && !isCategoryVisible; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (shouldBeDisaplayedAsDisabled) { | 
					
						
							|  |  |  | 			c.disabledClass = true; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-10-04 22:00:37 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (shouldBeRemoved && c && c.parent && c.parent.cid && cidToCategory[c.parent.cid]) { | 
					
						
							|  |  |  | 			cidToCategory[c.parent.cid].children = cidToCategory[c.parent.cid].children.filter(child => child.cid !== c.cid); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return c && !shouldBeRemoved; | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 16:35:20 -04:00
										 |  |  | 	const categoriesData = categories.buildForSelectCategories(visibleCategories, ['disabledClass']); | 
					
						
							| 
									
										
										
										
											2019-09-20 19:04:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	let selectedCategory = []; | 
					
						
							|  |  |  | 	const selectedCids = []; | 
					
						
							| 
									
										
										
										
											2019-09-20 19:04:47 -04:00
										 |  |  | 	categoriesData.forEach(function (category) { | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 		category.selected = selectedCid ? selectedCid.includes(String(category.cid)) : false; | 
					
						
							|  |  |  | 		if (category.selected) { | 
					
						
							|  |  |  | 			selectedCategory.push(category); | 
					
						
							|  |  |  | 			selectedCids.push(category.cid); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 	selectedCids.sort((a, b) => a - b); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (selectedCategory.length > 1) { | 
					
						
							|  |  |  | 		selectedCategory = { | 
					
						
							|  |  |  | 			icon: 'fa-plus', | 
					
						
							|  |  |  | 			name: '[[unread:multiple-categories-selected]]', | 
					
						
							|  |  |  | 			bgColor: '#ddd', | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	} else if (selectedCategory.length === 1) { | 
					
						
							|  |  |  | 		selectedCategory = selectedCategory[0]; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2020-10-02 16:57:26 -04:00
										 |  |  | 		selectedCategory = null; | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-03 13:06:21 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:32 -04:00
										 |  |  | 	return { | 
					
						
							| 
									
										
										
										
											2019-09-20 19:04:47 -04:00
										 |  |  | 		categories: categoriesData, | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:32 -04:00
										 |  |  | 		selectedCategory: selectedCategory, | 
					
						
							|  |  |  | 		selectedCids: selectedCids, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2016-11-03 13:06:21 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-03 12:48:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 12:47:01 -04:00
										 |  |  | function checkVisibleChildren(c, cidToAllowed, cidToWatchState, states) { | 
					
						
							|  |  |  | 	if (!c || !Array.isArray(c.children)) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-11 09:25:28 -04:00
										 |  |  | 	return c.children.some(c => c && !c.disabled && ( | 
					
						
							| 
									
										
										
										
											2019-10-30 12:47:01 -04:00
										 |  |  | 		(cidToAllowed[c.cid] && states.includes(cidToWatchState[c.cid])) || checkVisibleChildren(c, cidToAllowed, cidToWatchState, states) | 
					
						
							|  |  |  | 	)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 16:27:58 -04:00
										 |  |  | helpers.getHomePageRoutes = async function (uid) { | 
					
						
							|  |  |  | 	let cids = await categories.getAllCidsFromSet('categories:cid'); | 
					
						
							|  |  |  | 	cids = await privileges.categories.filterCids('find', cids, uid); | 
					
						
							|  |  |  | 	const categoryData = await categories.getCategoriesFields(cids, ['name', 'slug']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const categoryRoutes = categoryData.map(function (category) { | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			route: 'category/' + category.slug, | 
					
						
							|  |  |  | 			name: 'Category: ' + category.name, | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 	const routes = [ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			route: 'categories', | 
					
						
							|  |  |  | 			name: 'Categories', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			route: 'unread', | 
					
						
							|  |  |  | 			name: 'Unread', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			route: 'recent', | 
					
						
							|  |  |  | 			name: 'Recent', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			route: 'top', | 
					
						
							|  |  |  | 			name: 'Top', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			route: 'popular', | 
					
						
							|  |  |  | 			name: 'Popular', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	].concat(categoryRoutes, [ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			route: 'custom', | 
					
						
							|  |  |  | 			name: 'Custom', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	]); | 
					
						
							|  |  |  | 	const data = await plugins.fireHook('filter:homepage.get', { routes: routes }); | 
					
						
							|  |  |  | 	return data.routes; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 20:25:23 -04:00
										 |  |  | helpers.formatApiResponse = async (statusCode, res, payload) => { | 
					
						
							|  |  |  | 	if (statusCode === 200) { | 
					
						
							|  |  |  | 		res.status(200).json({ | 
					
						
							|  |  |  | 			status: { | 
					
						
							|  |  |  | 				code: 'ok', | 
					
						
							|  |  |  | 				message: 'OK', | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			response: payload || {}, | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} else if (payload instanceof Error) { | 
					
						
							|  |  |  | 		if (isLanguageKey.test(payload.message)) { | 
					
						
							|  |  |  | 			const translated = await translator.translate(payload.message, 'en-GB'); | 
					
						
							|  |  |  | 			res.status(statusCode).json(helpers.generateError(statusCode, translated)); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			res.status(statusCode).json(helpers.generateError(statusCode, payload.message)); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-10-01 10:52:05 -04:00
										 |  |  | 	} else if (!payload) { | 
					
						
							|  |  |  | 		// Non-2xx statusCode, generate predefined error
 | 
					
						
							|  |  |  | 		res.status(statusCode).json(helpers.generateError(statusCode)); | 
					
						
							| 
									
										
										
										
											2020-03-26 20:25:23 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | helpers.generateError = (statusCode, message) => { | 
					
						
							|  |  |  | 	var payload = { | 
					
						
							|  |  |  | 		status: { | 
					
						
							|  |  |  | 			code: 'internal-server-error', | 
					
						
							|  |  |  | 			message: 'An unexpected error was encountered while attempting to service your request.', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		response: {}, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Need to turn all these into translation strings
 | 
					
						
							|  |  |  | 	switch (statusCode) { | 
					
						
							| 
									
										
										
										
											2020-10-01 10:52:05 -04:00
										 |  |  | 		case 400: | 
					
						
							|  |  |  | 			payload.status.code = 'bad-request'; | 
					
						
							|  |  |  | 			payload.status.message = message || 'Something was wrong with the request payload you passed in.'; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 401: | 
					
						
							|  |  |  | 			payload.status.code = 'not-authorised'; | 
					
						
							|  |  |  | 			payload.status.message = message || 'A valid login session was not found. Please log in and try again.'; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 403: | 
					
						
							|  |  |  | 			payload.status.code = 'forbidden'; | 
					
						
							|  |  |  | 			payload.status.message = message || 'You are not authorised to make this call'; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 404: | 
					
						
							|  |  |  | 			payload.status.code = 'not-found'; | 
					
						
							|  |  |  | 			payload.status.message = message || 'Invalid API call'; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 426: | 
					
						
							|  |  |  | 			payload.status.code = 'upgrade-required'; | 
					
						
							|  |  |  | 			payload.status.message = message || 'HTTPS is required for requests to the write api, please re-send your request via HTTPS'; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case 500: | 
					
						
							|  |  |  | 			payload.status.code = 'internal-server-error'; | 
					
						
							|  |  |  | 			payload.status.message = message || payload.status.message; | 
					
						
							| 
									
										
										
										
											2020-03-26 20:25:23 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return payload; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 23:17:43 -04:00
										 |  |  | require('../promisify')(helpers); |