From da4034a10aedb7fa4964b2fd0f3560ca2ccb7dfa Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 11 Oct 2015 23:05:33 -0400 Subject: [PATCH] middleware refactor --- src/controllers/search.js | 7 +- src/middleware/header.js | 174 +++++++++++++++++++++ src/middleware/middleware.js | 290 +++-------------------------------- src/middleware/render.js | 83 ++++++++++ src/routes/accounts.js | 2 +- src/routes/index.js | 2 +- 6 files changed, 284 insertions(+), 274 deletions(-) create mode 100644 src/middleware/header.js create mode 100644 src/middleware/render.js diff --git a/src/controllers/search.js b/src/controllers/search.js index 82257f1a64..e32ab67c4b 100644 --- a/src/controllers/search.js +++ b/src/controllers/search.js @@ -2,7 +2,8 @@ 'use strict'; var async = require('async'), - validator = require('validator'), + + meta = require('../meta'), plugins = require('../plugins'), search = require('../search'), categories = require('../categories'), @@ -17,6 +18,10 @@ searchController.search = function(req, res, next) { return next(); } + if (!req.user && parseInt(meta.config.allowGuestSearching, 10) !== 1) { + return helpers.notAllowed(req, res); + } + var page = Math.max(1, parseInt(req.query.page, 10)) || 1; if (req.query.categories && !Array.isArray(req.query.categories)) { req.query.categories = [req.query.categories]; diff --git a/src/middleware/header.js b/src/middleware/header.js new file mode 100644 index 0000000000..edd7306fa1 --- /dev/null +++ b/src/middleware/header.js @@ -0,0 +1,174 @@ +'use strict'; + +var async = require('async'); +var nconf = require('nconf'); + +var user = require('../user'); +var meta = require('../meta'); +var plugins = require('../plugins'); +var navigation = require('../navigation'); +var translator = require('../../public/src/modules/translator'); + +var controllers = { + api: require('../controllers/api'), + helpers: require('../controllers/helpers') +}; + +module.exports = function(app, middleware) { + + middleware.buildHeader = function(req, res, next) { + res.locals.renderHeader = true; + res.locals.isAPI = false; + + middleware.applyCSRF(req, res, function() { + async.parallel({ + config: function(next) { + controllers.api.getConfig(req, res, next); + }, + footer: function(next) { + app.render('footer', {loggedIn: (req.user ? parseInt(req.user.uid, 10) !== 0 : false)}, next); + }, + plugins: function(next) { + plugins.fireHook('filter:middleware.buildHeader', {req: req, locals: res.locals}, next); + } + }, function(err, results) { + if (err) { + return next(err); + } + + res.locals.config = results.config; + + translator.translate(results.footer, results.config.defaultLang, function(parsedTemplate) { + res.locals.footer = parsedTemplate; + next(); + }); + }); + }); + }; + + middleware.renderHeader = function(req, res, data, callback) { + var registrationType = meta.config.registrationType || 'normal'; + var templateValues = { + bootswatchCSS: meta.config['theme:src'], + title: meta.config.title || '', + description: meta.config.description || '', + 'cache-buster': meta.config['cache-buster'] ? 'v=' + 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' || registrationType === 'admin-approval', + searchEnabled: plugins.hasListeners('filter:search.query'), + config: res.locals.config, + relative_path: nconf.get('relative_path') + }; + + templateValues.configJSON = JSON.stringify(res.locals.config); + + async.parallel({ + customCSS: function(next) { + templateValues.useCustomCSS = parseInt(meta.config.useCustomCSS, 10) === 1; + if (!templateValues.useCustomCSS || !meta.config.customCSS || !meta.config.renderedCustomCSS) { + return next(null, ''); + } + next(null, meta.config.renderedCustomCSS); + }, + customJS: function(next) { + templateValues.useCustomJS = parseInt(meta.config.useCustomJS, 10) === 1; + next(null, templateValues.useCustomJS ? meta.config.customJS : ''); + }, + settings: function(next) { + if (req.uid) { + user.getSettings(req.uid, next); + } else { + next(); + } + }, + title: function(next) { + next(null, controllers.helpers.buildTitle(data.title)); + }, + isAdmin: function(next) { + user.isAdministrator(req.uid, next); + }, + user: function(next) { + if (req.uid) { + user.getUserFields(req.uid, ['username', 'userslug', 'email', 'picture', 'status', 'email:confirmed', 'banned'], next); + } else { + next(null, { + username: '[[global:guest]]', + userslug: '', + picture: user.createGravatarURLFromEmail(''), + status: 'offline', + banned: false, + uid: 0 + }); + } + }, + navigation: async.apply(navigation.get), + tags: async.apply(meta.tags.parse, res.locals.metaTags, res.locals.linkTags) + }, function(err, results) { + if (err) { + return callback(err); + } + + if (results.user && parseInt(results.user.banned, 10) === 1) { + req.logout(); + return res.redirect('/'); + } + results.user.isAdmin = results.isAdmin || false; + results.user.uid = parseInt(results.user.uid, 10); + results.user['email:confirmed'] = parseInt(results.user['email:confirmed'], 10) === 1; + + if (results.settings && results.settings.bootswatchSkin && results.settings.bootswatchSkin !== 'default') { + templateValues.bootswatchCSS = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + results.settings.bootswatchSkin + '/bootstrap.min.css'; + } + + templateValues.browserTitle = results.title; + templateValues.navigation = results.navigation; + templateValues.metaTags = results.tags.meta; + templateValues.linkTags = results.tags.link; + templateValues.isAdmin = results.user.isAdmin; + templateValues.user = results.user; + templateValues.userJSON = JSON.stringify(results.user); + templateValues.customCSS = results.customCSS; + templateValues.customJS = results.customJS; + templateValues.maintenanceHeader = parseInt(meta.config.maintenanceMode, 10) === 1 && !results.isAdmin; + templateValues.defaultLang = meta.config.defaultLang || 'en_GB'; + + templateValues.template = {name: res.locals.template}; + templateValues.template[res.locals.template] = true; + + if (req.route && req.route.path === '/') { + modifyTitle(templateValues); + } + + plugins.fireHook('filter:middleware.renderHeader', {templateValues: templateValues, req: req, res: res}, function(err, data) { + if (err) { + return callback(err); + } + + app.render('header', data.templateValues, callback); + }); + }); + }; + + + function modifyTitle(obj) { + var title = controllers.helpers.buildTitle('[[pages:home]]'); + obj.browserTitle = title; + + if (obj.metaTags) { + obj.metaTags.forEach(function(tag, i) { + if (tag.property === 'og:title') { + obj.metaTags[i].content = title; + } + }); + } + + return title; + } + +}; + + + diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 6049970468..d7c06ae4aa 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -7,21 +7,16 @@ var app, async = require('async'), path = require('path'), csrf = require('csurf'), - winston = require('winston'), + validator = require('validator'), nconf = require('nconf'), ensureLoggedIn = require('connect-ensure-login'), plugins = require('../plugins'), - navigation = require('../navigation'), meta = require('../meta'), - translator = require('../../public/src/modules/translator'), user = require('../user'), groups = require('../groups'), - db = require('../database'), - categories = require('../categories'), - topics = require('../topics'), - messaging = require('../messaging'), + analytics = require('../analytics'), @@ -87,14 +82,6 @@ middleware.redirectToAccountIfLoggedIn = function(req, res, next) { }); }; -middleware.redirectToLoginIfGuest = function(req, res, next) { - if (!req.user || parseInt(req.user.uid, 10) === 0) { - return redirectToLogin(req, res); - } - - next(); -}; - middleware.validateFiles = function(req, res, next) { if (!Array.isArray(req.files.files) || !req.files.files.length) { return next(new Error(['[[error:invalid-files]]'])); @@ -108,14 +95,6 @@ middleware.prepareAPI = function(req, res, next) { next(); }; -middleware.guestSearchingAllowed = function(req, res, next) { - if (!req.user && parseInt(meta.config.allowGuestSearching, 10) !== 1) { - return controllers.helpers.notAllowed(req, res); - } - - next(); -}; - middleware.checkGlobalPrivacySettings = function(req, res, next) { if (!req.user && !!parseInt(meta.config.privateUserInfo, 10)) { return controllers.helpers.notAllowed(req, res); @@ -149,11 +128,11 @@ middleware.checkAccountPermissions = function(req, res, next) { }; middleware.isAdmin = function(req, res, next) { - if (!req.user) { - return redirectToLogin(req, res); + if (!req.uid) { + return controllers.helpers.notAllowed(req, res); } - user.isAdministrator((req.user && req.user.uid) ? req.user.uid : 0, function (err, isAdmin) { + user.isAdministrator(req.uid, function (err, isAdmin) { if (err || isAdmin) { return next(err); } @@ -168,218 +147,7 @@ middleware.isAdmin = function(req, res, next) { }); }; -middleware.buildHeader = function(req, res, next) { - res.locals.renderHeader = true; - res.locals.isAPI = false; - - middleware.applyCSRF(req, res, function() { - async.parallel({ - config: function(next) { - controllers.api.getConfig(req, res, next); - }, - footer: function(next) { - app.render('footer', {loggedIn: (req.user ? parseInt(req.user.uid, 10) !== 0 : false)}, next); - }, - plugins: function(next) { - plugins.fireHook('filter:middleware.buildHeader', {req: req, locals: res.locals}, next); - } - }, function(err, results) { - if (err) { - return next(err); - } - - res.locals.config = results.config; - - translator.translate(results.footer, results.config.defaultLang, function(parsedTemplate) { - res.locals.footer = parsedTemplate; - next(); - }); - }); - }); -}; - -middleware.renderHeader = function(req, res, data, callback) { - var registrationType = meta.config.registrationType || 'normal'; - var templateValues = { - bootswatchCSS: meta.config['theme:src'], - title: meta.config.title || '', - description: meta.config.description || '', - 'cache-buster': meta.config['cache-buster'] ? 'v=' + 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' || registrationType === 'admin-approval', - searchEnabled: plugins.hasListeners('filter:search.query'), - config: res.locals.config, - relative_path: nconf.get('relative_path') - }; - templateValues.configJSON = JSON.stringify(res.locals.config); - - async.parallel({ - customCSS: function(next) { - templateValues.useCustomCSS = parseInt(meta.config.useCustomCSS, 10) === 1; - if (!templateValues.useCustomCSS || !meta.config.customCSS || !meta.config.renderedCustomCSS) { - return next(null, ''); - } - next(null, meta.config.renderedCustomCSS); - }, - customJS: function(next) { - templateValues.useCustomJS = parseInt(meta.config.useCustomJS, 10) === 1; - next(null, templateValues.useCustomJS ? meta.config.customJS : ''); - }, - settings: function(next) { - if (req.uid) { - user.getSettings(req.uid, next); - } else { - next(); - } - }, - title: function(next) { - next(null, controllers.helpers.buildTitle(data.title)); - }, - isAdmin: function(next) { - user.isAdministrator(req.uid, next); - }, - user: function(next) { - if (req.uid) { - user.getUserFields(req.uid, ['username', 'userslug', 'email', 'picture', 'status', 'email:confirmed', 'banned'], next); - } else { - next(null, { - username: '[[global:guest]]', - userslug: '', - picture: user.createGravatarURLFromEmail(''), - status: 'offline', - banned: false, - uid: 0 - }); - } - }, - navigation: async.apply(navigation.get), - tags: async.apply(meta.tags.parse, res.locals.metaTags, res.locals.linkTags) - }, function(err, results) { - if (err) { - return callback(err); - } - - if (results.user && parseInt(results.user.banned, 10) === 1) { - req.logout(); - return res.redirect('/'); - } - results.user.isAdmin = results.isAdmin || false; - results.user.uid = parseInt(results.user.uid, 10); - results.user['email:confirmed'] = parseInt(results.user['email:confirmed'], 10) === 1; - - if (results.settings && results.settings.bootswatchSkin && results.settings.bootswatchSkin !== 'default') { - templateValues.bootswatchCSS = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + results.settings.bootswatchSkin + '/bootstrap.min.css'; - } - - templateValues.browserTitle = results.title; - templateValues.navigation = results.navigation; - templateValues.metaTags = results.tags.meta; - templateValues.linkTags = results.tags.link; - templateValues.isAdmin = results.user.isAdmin; - templateValues.user = results.user; - templateValues.userJSON = JSON.stringify(results.user); - templateValues.customCSS = results.customCSS; - templateValues.customJS = results.customJS; - templateValues.maintenanceHeader = parseInt(meta.config.maintenanceMode, 10) === 1 && !results.isAdmin; - templateValues.defaultLang = meta.config.defaultLang || 'en_GB'; - - templateValues.template = {name: res.locals.template}; - templateValues.template[res.locals.template] = true; - - if (req.route && req.route.path === '/') { - modifyTitle(templateValues); - } - - plugins.fireHook('filter:middleware.renderHeader', {templateValues: templateValues, req: req, res: res}, function(err, data) { - if (err) { - return callback(err); - } - - app.render('header', data.templateValues, callback); - }); - }); -}; - -middleware.processRender = function(req, res, next) { - // res.render post-processing, modified from here: https://gist.github.com/mrlannigan/5051687 - var render = res.render; - res.render = function(template, options, fn) { - var self = this, - req = this.req, - app = req.app, - defaultFn = function(err, str){ - if (err) { - return req.next(err); - } - - self.send(str); - }; - options = options || {}; - - if ('function' === typeof options) { - fn = options; - options = {}; - } - - options.loggedIn = req.user ? parseInt(req.user.uid, 10) !== 0 : false; - options.relative_path = nconf.get('relative_path'); - options.template = {name: template}; - options.template[template] = true; - res.locals.template = template; - - if ('function' !== typeof fn) { - fn = defaultFn; - } - - if (res.locals.isAPI) { - if (req.route && req.route.path === '/api/') { - options.title = '[[pages:home]]'; - } - - return res.json(options); - } - - var ajaxifyData = encodeURIComponent(JSON.stringify(options)); - render.call(self, template, options, function(err, str) { - if (err) { - winston.error(err); - return fn(err); - } - - str = str + ''; - str = (res.locals.postHeader ? res.locals.postHeader : '') + str + (res.locals.preFooter ? res.locals.preFooter : ''); - - if (res.locals.footer) { - str = str + res.locals.footer; - } else if (res.locals.adminFooter) { - str = str + res.locals.adminFooter; - } - - if (res.locals.renderHeader || res.locals.renderAdminHeader) { - var method = res.locals.renderHeader ? middleware.renderHeader : middleware.admin.renderHeader; - method(req, res, options, function(err, template) { - if (err) { - return fn(err); - } - str = template + str; - var language = res.locals.config ? res.locals.config.userLang || 'en_GB' : 'en_GB'; - language = req.query.lang || language; - translator.translate(str, language, function(translated) { - fn(err, translated); - }); - }); - } else { - fn(err, str); - } - }); - }; - - next(); -}; middleware.routeTouchIcon = function(req, res) { if (meta.config['brand:logo'] && validator.isURL(meta.config['brand:logo'])) { @@ -403,8 +171,6 @@ middleware.addExpiresHeaders = function(req, res, next) { next(); }; - - middleware.privateTagListing = function(req, res, next) { if (!req.user && parseInt(meta.config.privateTagListing, 10) === 1) { controllers.helpers.notAllowed(req, res); @@ -414,7 +180,9 @@ middleware.privateTagListing = function(req, res, next) { }; middleware.exposeGroupName = function(req, res, next) { - if (!req.params.hasOwnProperty('slug')) { return next(); } + if (!req.params.hasOwnProperty('slug')) { + return next(); + } groups.getGroupNameByGroupSlug(req.params.slug, function(err, groupName) { if (err) { @@ -427,18 +195,17 @@ middleware.exposeGroupName = function(req, res, next) { }; middleware.exposeUid = function(req, res, next) { - if (req.params.hasOwnProperty('userslug')) { - user.getUidByUserslug(req.params.userslug, function(err, uid) { - if (err) { - return next(err); - } + if (!req.params.hasOwnProperty('userslug')) { + return nex(); + } + user.getUidByUserslug(req.params.userslug, function(err, uid) { + if (err) { + return next(err); + } - res.locals.uid = uid; - next(); - }); - } else { + res.locals.uid = uid; next(); - } + }); }; middleware.requireUser = function(req, res, next) { @@ -449,32 +216,13 @@ middleware.requireUser = function(req, res, next) { res.render('403', {title: '[[global:403.title]]'}); }; -function redirectToLogin(req, res) { - req.session.returnTo = nconf.get('relative_path') + req.url.replace(/^\/api/, ''); - return controllers.helpers.redirect(res, '/login'); -} - - - -function modifyTitle(obj) { - var title = controllers.helpers.buildTitle('[[pages:home]]'); - obj.browserTitle = title; - - if (obj.metaTags) { - obj.metaTags.forEach(function(tag, i) { - if (tag.property === 'og:title') { - obj.metaTags[i].content = title; - } - }); - } - - return title; -} module.exports = function(webserver) { app = webserver; middleware.admin = require('./admin')(webserver); + require('./header')(app, middleware); + require('./render')(middleware); require('./maintenance')(middleware); return middleware; diff --git a/src/middleware/render.js b/src/middleware/render.js new file mode 100644 index 0000000000..ba0c06552e --- /dev/null +++ b/src/middleware/render.js @@ -0,0 +1,83 @@ +'use strict'; + +var nconf = require('nconf'); +var translator = require('../../public/src/modules/translator'); + +module.exports = function(middleware) { + + middleware.processRender = function(req, res, next) { + // res.render post-processing, modified from here: https://gist.github.com/mrlannigan/5051687 + var render = res.render; + res.render = function(template, options, fn) { + var self = this, + req = this.req, + defaultFn = function(err, str){ + if (err) { + return req.next(err); + } + + self.send(str); + }; + options = options || {}; + + if ('function' === typeof options) { + fn = options; + options = {}; + } + + options.loggedIn = req.user ? parseInt(req.user.uid, 10) !== 0 : false; + options.relative_path = nconf.get('relative_path'); + options.template = {name: template}; + options.template[template] = true; + res.locals.template = template; + + if (res.locals.isAPI) { + if (req.route && req.route.path === '/api/') { + options.title = '[[pages:home]]'; + } + + return res.json(options); + } + + if ('function' !== typeof fn) { + fn = defaultFn; + } + + var ajaxifyData = encodeURIComponent(JSON.stringify(options)); + render.call(self, template, options, function(err, str) { + if (err) { + return fn(err); + } + + str = str + ''; + str = (res.locals.postHeader ? res.locals.postHeader : '') + str + (res.locals.preFooter ? res.locals.preFooter : ''); + + if (res.locals.footer) { + str = str + res.locals.footer; + } else if (res.locals.adminFooter) { + str = str + res.locals.adminFooter; + } + + if (res.locals.renderHeader || res.locals.renderAdminHeader) { + var method = res.locals.renderHeader ? middleware.renderHeader : middleware.admin.renderHeader; + method(req, res, options, function(err, template) { + if (err) { + return fn(err); + } + str = template + str; + var language = res.locals.config ? res.locals.config.userLang || 'en_GB' : 'en_GB'; + language = req.query.lang || language; + translator.translate(str, language, function(translated) { + fn(err, translated); + }); + }); + } else { + fn(err, str); + } + }); + }; + + next(); + }; + +}; \ No newline at end of file diff --git a/src/routes/accounts.js b/src/routes/accounts.js index 3b486ef5e5..2d492c6c78 100644 --- a/src/routes/accounts.js +++ b/src/routes/accounts.js @@ -23,5 +23,5 @@ module.exports = function (app, middleware, controllers) { setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.settings.get); setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get); - setupPageRoute(app, '/chats/:userslug?', middleware, [middleware.redirectToLoginIfGuest], controllers.accounts.chats.get); + setupPageRoute(app, '/chats/:userslug?', middleware, [middleware.authenticate], controllers.accounts.chats.get); }; diff --git a/src/routes/index.js b/src/routes/index.js index 16a6084cc2..93dc9aaedb 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -30,7 +30,7 @@ function mainRoutes(app, middleware, controllers) { setupPageRoute(app, '/compose', middleware, [middleware.authenticate], controllers.compose); setupPageRoute(app, '/confirm/:code', middleware, [], controllers.confirmEmail); setupPageRoute(app, '/outgoing', middleware, [], controllers.outgoing); - setupPageRoute(app, '/search/:term?', middleware, [middleware.guestSearchingAllowed], controllers.search.search); + setupPageRoute(app, '/search/:term?', middleware, [], controllers.search.search); setupPageRoute(app, '/reset/:code?', middleware, [], controllers.reset); setupPageRoute(app, '/tos', middleware, [], controllers.termsOfUse); }