refactor: async/await controllers

v1.18.x
Barış Soner Uşaklı 6 years ago
parent a121098513
commit 2c4f04462f

@ -1,16 +1,15 @@
'use strict'; 'use strict';
var async = require('async'); const nconf = require('nconf');
var nconf = require('nconf'); const validator = require('validator');
var validator = require('validator');
var meta = require('../meta'); const meta = require('../meta');
var user = require('../user'); const user = require('../user');
var plugins = require('../plugins'); const plugins = require('../plugins');
var privileges = require('../privileges'); const privileges = require('../privileges');
var helpers = require('./helpers'); const helpers = require('./helpers');
var Controllers = module.exports; const Controllers = module.exports;
Controllers.ping = require('./ping'); Controllers.ping = require('./ping');
Controllers.home = require('./home'); Controllers.home = require('./home');
@ -154,94 +153,77 @@ Controllers.login = function (req, res, next) {
}); });
}; };
Controllers.register = function (req, res, next) { Controllers.register = async function (req, res, next) {
var registrationType = meta.config.registrationType || 'normal'; const registrationType = meta.config.registrationType || 'normal';
if (registrationType === 'disabled') { if (registrationType === 'disabled') {
return setImmediate(next); return setImmediate(next);
} }
var errorText; let errorText;
if (req.query.error === 'csrf-invalid') { if (req.query.error === 'csrf-invalid') {
errorText = '[[error:csrf-invalid]]'; errorText = '[[error:csrf-invalid]]';
} }
try {
async.waterfall([
function (next) {
if (registrationType === 'invite-only' || registrationType === 'admin-invite-only') { if (registrationType === 'invite-only' || registrationType === 'admin-invite-only') {
user.verifyInvitation(req.query, next); await user.verifyInvitation(req.query);
} else {
next();
} }
}, const termsOfUse = await plugins.fireHook('filter:parse.post', {
function (next) {
plugins.fireHook('filter:parse.post', {
postData: { postData: {
content: meta.config.termsOfUse || '', content: meta.config.termsOfUse || '',
}, },
}, next); });
}, const loginStrategies = require('../routes/authentication').getLoginStrategies();
function (termsOfUse) { res.render('register', {
var loginStrategies = require('../routes/authentication').getLoginStrategies();
var data = {
'register_window:spansize': loginStrategies.length ? 'col-md-6' : 'col-md-12', 'register_window:spansize': loginStrategies.length ? 'col-md-6' : 'col-md-12',
alternate_logins: !!loginStrategies.length, alternate_logins: !!loginStrategies.length,
}; authentication: loginStrategies,
data.authentication = loginStrategies;
data.minimumUsernameLength = meta.config.minimumUsernameLength; minimumUsernameLength: meta.config.minimumUsernameLength,
data.maximumUsernameLength = meta.config.maximumUsernameLength; maximumUsernameLength: meta.config.maximumUsernameLength,
data.minimumPasswordLength = meta.config.minimumPasswordLength; minimumPasswordLength: meta.config.minimumPasswordLength,
data.minimumPasswordStrength = meta.config.minimumPasswordStrength; minimumPasswordStrength: meta.config.minimumPasswordStrength,
data.termsOfUse = termsOfUse.postData.content; termsOfUse: termsOfUse.postData.content,
data.breadcrumbs = helpers.buildBreadcrumbs([{ breadcrumbs: helpers.buildBreadcrumbs([{
text: '[[register:register]]', text: '[[register:register]]',
}]); }]),
data.regFormEntry = []; regFormEntry: [],
data.error = req.flash('error')[0] || errorText; error: req.flash('error')[0] || errorText,
data.title = '[[pages:register]]'; title: '[[pages:register]]',
});
res.render('register', data); } catch (err) {
}, next(err);
], next); }
}; };
Controllers.registerInterstitial = function (req, res, next) { Controllers.registerInterstitial = async function (req, res, next) {
if (!req.session.hasOwnProperty('registration')) { if (!req.session.hasOwnProperty('registration')) {
return res.redirect(nconf.get('relative_path') + '/register'); return res.redirect(nconf.get('relative_path') + '/register');
} }
try {
async.waterfall([ const data = await plugins.fireHook('filter:register.interstitial', {
function (next) {
plugins.fireHook('filter:register.interstitial', {
userData: req.session.registration, userData: req.session.registration,
interstitials: [], interstitials: [],
}, next); });
},
function (data, next) {
if (!data.interstitials.length) { if (!data.interstitials.length) {
// No interstitials, redirect to home // No interstitials, redirect to home
const returnTo = req.session.returnTo || req.session.registration.returnTo; const returnTo = req.session.returnTo || req.session.registration.returnTo;
delete req.session.registration; delete req.session.registration;
return helpers.redirect(res, returnTo || '/'); return helpers.redirect(res, returnTo || '/');
} }
var renders = data.interstitials.map(function (interstitial) {
return async.apply(req.app.render.bind(req.app), interstitial.template, interstitial.data || {});
});
const renders = data.interstitials.map(interstitial => req.app.renderAsync(interstitial.template, interstitial.data || {}));
const sections = await Promise.all(renders);
async.parallel(renders, next);
},
function (sections) {
var errors = req.flash('errors');
res.render('registerComplete', { res.render('registerComplete', {
title: '[[pages:registration-complete]]', title: '[[pages:registration-complete]]',
errors: errors, errors: req.flash('errors'),
sections: sections, sections: sections,
}); });
}, } catch (err) {
], next); next(err);
}
}; };
Controllers.confirmEmail = function (req, res) { Controllers.confirmEmail = function (req, res) {

@ -1,58 +1,50 @@
'use strict'; 'use strict';
var async = require('async'); const user = require('../user');
const categories = require('../categories');
var user = require('../user'); const flags = require('../flags');
var categories = require('../categories'); const analytics = require('../analytics');
var flags = require('../flags'); const plugins = require('../plugins');
var analytics = require('../analytics'); const pagination = require('../pagination');
var plugins = require('../plugins'); const utils = require('../utils');
var pagination = require('../pagination');
const adminPostQueueController = require('./admin/postqueue');
var adminPostQueueController = require('./admin/postqueue'); const modsController = module.exports;
var modsController = module.exports;
modsController.flags = {}; modsController.flags = {};
modsController.flags.list = function (req, res, next) { modsController.flags.list = async function (req, res, next) {
var filters; let validFilters = ['assignee', 'state', 'reporterId', 'type', 'targetUid', 'cid', 'quick', 'page', 'perPage'];
var hasFilter;
var validFilters = ['assignee', 'state', 'reporterId', 'type', 'targetUid', 'cid', 'quick', 'page', 'perPage'];
// Reset filters if explicitly requested // Reset filters if explicitly requested
if (parseInt(req.query.reset, 10) === 1) { if (parseInt(req.query.reset, 10) === 1) {
delete req.session.flags_filters; delete req.session.flags_filters;
} }
async.waterfall([ const [isAdminOrGlobalMod, moderatedCids, data] = await Promise.all([
function (next) { user.isAdminOrGlobalMod(req.uid),
async.parallel({ user.getModeratedCids(req.uid),
isAdminOrGlobalMod: async.apply(user.isAdminOrGlobalMod, req.uid), plugins.fireHook('filter:flags.validateFilters', { filters: validFilters }),
moderatedCids: async.apply(user.getModeratedCids, req.uid), ]);
validFilters: async.apply(plugins.fireHook, 'filter:flags.validateFilters', { filters: validFilters }),
}, next); if (!(isAdminOrGlobalMod || !!moderatedCids.length)) {
},
function (results, next) {
if (!(results.isAdminOrGlobalMod || !!results.moderatedCids.length)) {
return next(new Error('[[error:no-privileges]]')); return next(new Error('[[error:no-privileges]]'));
} }
if (!results.isAdminOrGlobalMod && results.moderatedCids.length) { if (!isAdminOrGlobalMod && moderatedCids.length) {
res.locals.cids = results.moderatedCids; res.locals.cids = moderatedCids;
} }
validFilters = results.validFilters.filters; validFilters = data.filters;
// Parse query string params for filters // Parse query string params for filters
hasFilter = false; let filters = validFilters.reduce(function (memo, cur) {
filters = validFilters.reduce(function (memo, cur) {
if (req.query.hasOwnProperty(cur)) { if (req.query.hasOwnProperty(cur)) {
memo[cur] = req.query[cur]; memo[cur] = req.query[cur];
} }
return memo; return memo;
}, {}); }, {});
hasFilter = !!Object.keys(filters).length; let hasFilter = !!Object.keys(filters).length;
if (!hasFilter && req.session.hasOwnProperty('flags_filters')) { if (!hasFilter && req.session.hasOwnProperty('flags_filters')) {
// Load filters from session object // Load filters from session object
@ -66,9 +58,7 @@ modsController.flags.list = function (req, res, next) {
filters.cid = res.locals.cids; filters.cid = res.locals.cids;
} else if (Array.isArray(filters.cid)) { } else if (Array.isArray(filters.cid)) {
// Remove cids they do not moderate // Remove cids they do not moderate
filters.cid = filters.cid.filter(function (cid) { filters.cid = filters.cid.filter(cid => res.locals.cids.includes(String(cid)));
return res.locals.cids.includes(String(cid));
});
} else if (!res.locals.cids.includes(String(filters.cid))) { } else if (!res.locals.cids.includes(String(filters.cid))) {
filters.cid = res.locals.cids; filters.cid = res.locals.cids;
hasFilter = false; hasFilter = false;
@ -83,38 +73,34 @@ modsController.flags.list = function (req, res, next) {
// Save filters into session unless removed // Save filters into session unless removed
req.session.flags_filters = filters; req.session.flags_filters = filters;
async.parallel({ const [flagsData, analyticsData, categoriesData] = await Promise.all([
flags: async.apply(flags.list, filters, req.uid), flags.list(filters, req.uid),
analytics: async.apply(analytics.getDailyStatsForSet, 'analytics:flags', Date.now(), 30), analytics.getDailyStatsForSet('analytics:flags', Date.now(), 30),
categories: async.apply(categories.buildForSelect, req.uid, 'read'), categories.buildForSelect(req.uid, 'read'),
}, next); ]);
},
function (data) {
data.categories = filterCategories(res.locals.cids, data.categories);
res.render('flags/list', { res.render('flags/list', {
flags: data.flags.flags, flags: flagsData.flags,
analytics: data.analytics, analytics: analyticsData,
categories: data.categories, categories: filterCategories(res.locals.cids, categoriesData),
hasFilter: hasFilter, hasFilter: hasFilter,
filters: filters, filters: filters,
title: '[[pages:flags]]', title: '[[pages:flags]]',
pagination: pagination.create(data.flags.page, data.flags.pageCount, req.query), pagination: pagination.create(flagsData.page, flagsData.pageCount, req.query),
}); });
},
], next);
}; };
modsController.flags.detail = function (req, res, next) { modsController.flags.detail = async function (req, res, next) {
async.parallel({ const results = await utils.promiseParallel({
isAdminOrGlobalMod: async.apply(user.isAdminOrGlobalMod, req.uid), isAdminOrGlobalMod: user.isAdminOrGlobalMod(req.uid),
moderatedCids: async.apply(user.getModeratedCids, req.uid), moderatedCids: user.getModeratedCids(req.uid),
flagData: async.apply(flags.get, req.params.flagId), flagData: flags.get(req.params.flagId),
assignees: async.apply(user.getAdminsandGlobalModsandModerators), assignees: user.getAdminsandGlobalModsandModerators(),
categories: async.apply(categories.buildForSelect, req.uid, 'read'), categories: categories.buildForSelect(req.uid, 'read'),
}, function (err, results) { });
if (err || !results.flagData) {
return next(err || new Error('[[error:invalid-data]]')); if (!results.flagData) {
return next(new Error('[[error:invalid-data]]'));
} else if (!(results.isAdminOrGlobalMod || !!results.moderatedCids.length)) { } else if (!(results.isAdminOrGlobalMod || !!results.moderatedCids.length)) {
return next(new Error('[[error:no-privileges]]')); return next(new Error('[[error:no-privileges]]'));
} }
@ -145,15 +131,12 @@ modsController.flags.detail = function (req, res, next) {
title: '[[pages:flag-details, ' + req.params.flagId + ']]', title: '[[pages:flag-details, ' + req.params.flagId + ']]',
categories: results.categories, categories: results.categories,
})); }));
});
}; };
function filterCategories(moderatedCids, categories) { function filterCategories(moderatedCids, categories) {
// If cids is populated, then slim down the categories list // If cids is populated, then slim down the categories list
if (moderatedCids) { if (moderatedCids) {
categories = categories.filter(function (category) { categories = categories.filter(category => moderatedCids.includes(String(category.cid)));
return moderatedCids.includes(String(category.cid));
});
} }
return categories.reduce(function (memo, cur) { return categories.reduce(function (memo, cur) {
@ -171,16 +154,10 @@ function filterCategories(moderatedCids, categories) {
}, {}); }, {});
} }
modsController.postQueue = function (req, res, next) { modsController.postQueue = async function (req, res, next) {
async.waterfall([ const isPrivileged = await user.isPrivileged(req.uid);
function (next) {
user.isPrivileged(req.uid, next);
},
function (isPrivileged, next) {
if (!isPrivileged) { if (!isPrivileged) {
return next(); return next();
} }
adminPostQueueController.get(req, res, next); await adminPostQueueController.get(req, res, next);
},
], next);
}; };

@ -1,10 +1,10 @@
'use strict'; 'use strict';
var xml = require('xml'); const xml = require('xml');
var nconf = require('nconf'); const nconf = require('nconf');
var plugins = require('../plugins'); const plugins = require('../plugins');
var meta = require('../meta'); const meta = require('../meta');
module.exports.handle = function (req, res, next) { module.exports.handle = function (req, res, next) {
if (plugins.hasListeners('filter:search.query')) { if (plugins.hasListeners('filter:search.query')) {

@ -1,28 +1,18 @@
'use strict'; 'use strict';
var async = require('async'); const sitemap = require('../sitemap');
const meta = require('../meta');
var sitemap = require('../sitemap'); const sitemapController = module.exports;
var meta = require('../meta');
var sitemapController = module.exports; sitemapController.render = async function (req, res, next) {
sitemapController.render = function (req, res, next) {
if (meta.config['feeds:disableSitemap']) { if (meta.config['feeds:disableSitemap']) {
return setImmediate(next); return setImmediate(next);
} }
async.waterfall([ const tplData = await sitemap.render();
function (next) { const xml = await req.app.renderAsync('sitemap', tplData);
sitemap.render(next);
},
function (tplData, next) {
req.app.render('sitemap', tplData, next);
},
function (xml) {
res.header('Content-Type', 'application/xml'); res.header('Content-Type', 'application/xml');
res.send(xml); res.send(xml);
},
], next);
}; };
sitemapController.getPages = function (req, res, next) { sitemapController.getPages = function (req, res, next) {
@ -34,26 +24,19 @@ sitemapController.getCategories = function (req, res, next) {
}; };
sitemapController.getTopicPage = function (req, res, next) { sitemapController.getTopicPage = function (req, res, next) {
sendSitemap(function (callback) { sendSitemap(async function () {
sitemap.getTopicPage(parseInt(req.params[0], 10), callback); return await sitemap.getTopicPage(parseInt(req.params[0], 10));
}, res, next); }, res, next);
}; };
function sendSitemap(method, res, callback) { async function sendSitemap(method, res, callback) {
if (meta.config['feeds:disableSitemap']) { if (meta.config['feeds:disableSitemap']) {
return setImmediate(callback); return setImmediate(callback);
} }
async.waterfall([ const xml = await method();
function (next) {
method(next);
},
function (xml) {
if (!xml) { if (!xml) {
return callback(); return callback();
} }
res.header('Content-Type', 'application/xml'); res.header('Content-Type', 'application/xml');
res.send(xml); res.send(xml);
},
], callback);
} }

@ -1,82 +1,58 @@
'use strict'; 'use strict';
var async = require('async'); const nconf = require('nconf');
var nconf = require('nconf'); const querystring = require('querystring');
var querystring = require('querystring');
var meta = require('../meta'); const meta = require('../meta');
var pagination = require('../pagination'); const pagination = require('../pagination');
var user = require('../user'); const user = require('../user');
var categories = require('../categories'); const categories = require('../categories');
var topics = require('../topics'); const topics = require('../topics');
var plugins = require('../plugins'); const plugins = require('../plugins');
var helpers = require('./helpers'); const helpers = require('./helpers');
var unreadController = module.exports; const unreadController = module.exports;
unreadController.get = function (req, res, next) { unreadController.get = async function (req, res, next) {
var page = parseInt(req.query.page, 10) || 1; const cid = req.query.cid;
var results; const filter = req.query.filter || '';
var cid = req.query.cid;
var filter = req.query.filter || '';
var settings;
async.waterfall([ const filterData = await plugins.fireHook('filter:unread.getValidFilters', { filters: { ...helpers.validFilters } });
function (next) { if (!filterData.filters[filter]) {
plugins.fireHook('filter:unread.getValidFilters', { filters: { ...helpers.validFilters } }, next);
},
function (data, _next) {
if (!data.filters[filter]) {
return next(); return next();
} }
const [watchedCategories, userSettings] = await Promise.all([
getWatchedCategories(req.uid, cid, filter),
user.getSettings(req.uid),
]);
async.parallel({ const page = parseInt(req.query.page, 10) || 1;
watchedCategories: function (next) { const start = Math.max(0, (page - 1) * userSettings.topicsPerPage);
if (plugins.hasListeners('filter:unread.categories')) { const stop = start + userSettings.topicsPerPage - 1;
plugins.fireHook('filter:unread.categories', { uid: req.uid, cid: cid }, next); const cutoff = req.session.unreadCutoff ? req.session.unreadCutoff : topics.unreadCutoff();
} else { const data = await topics.getUnreadTopics({
const states = [categories.watchStates.watching];
if (filter === 'watched') {
states.push(categories.watchStates.notwatching, categories.watchStates.ignoring);
}
helpers.getCategoriesByStates(req.uid, cid, states, next);
}
},
settings: function (next) {
user.getSettings(req.uid, next);
},
}, _next);
},
function (_results, next) {
results = _results;
settings = results.settings;
var start = Math.max(0, (page - 1) * settings.topicsPerPage);
var stop = start + settings.topicsPerPage - 1;
var cutoff = req.session.unreadCutoff ? req.session.unreadCutoff : topics.unreadCutoff();
topics.getUnreadTopics({
cid: cid, cid: cid,
uid: req.uid, uid: req.uid,
start: start, start: start,
stop: stop, stop: stop,
filter: filter, filter: filter,
cutoff: cutoff, cutoff: cutoff,
}, next); });
},
function (data) {
data.title = meta.config.homePageTitle || '[[pages:home]]'; data.title = meta.config.homePageTitle || '[[pages:home]]';
data.pageCount = Math.max(1, Math.ceil(data.topicCount / settings.topicsPerPage)); data.pageCount = Math.max(1, Math.ceil(data.topicCount / userSettings.topicsPerPage));
data.pagination = pagination.create(page, data.pageCount, req.query); data.pagination = pagination.create(page, data.pageCount, req.query);
if (settings.usePagination && (page < 1 || page > data.pageCount)) { if (userSettings.usePagination && (page < 1 || page > data.pageCount)) {
req.query.page = Math.max(1, Math.min(data.pageCount, page)); req.query.page = Math.max(1, Math.min(data.pageCount, page));
return helpers.redirect(res, '/unread?' + querystring.stringify(req.query)); return helpers.redirect(res, '/unread?' + querystring.stringify(req.query));
} }
data.categories = results.watchedCategories.categories; data.categories = watchedCategories.categories;
data.allCategoriesUrl = 'unread' + helpers.buildQueryString('', filter, ''); data.allCategoriesUrl = 'unread' + helpers.buildQueryString('', filter, '');
data.selectedCategory = results.watchedCategories.selectedCategory; data.selectedCategory = watchedCategories.selectedCategory;
data.selectedCids = results.watchedCategories.selectedCids; data.selectedCids = watchedCategories.selectedCids;
if (req.originalUrl.startsWith(nconf.get('relative_path') + '/api/unread') || req.originalUrl.startsWith(nconf.get('relative_path') + '/unread')) { if (req.originalUrl.startsWith(nconf.get('relative_path') + '/api/unread') || req.originalUrl.startsWith(nconf.get('relative_path') + '/unread')) {
data.title = '[[pages:unread]]'; data.title = '[[pages:unread]]';
data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[unread:title]]' }]); data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[unread:title]]' }]);
@ -84,30 +60,32 @@ unreadController.get = function (req, res, next) {
data.filters = helpers.buildFilters('unread', filter, req.query); data.filters = helpers.buildFilters('unread', filter, req.query);
data.selectedFilter = data.filters.find(function (filter) { data.selectedFilter = data.filters.find(filter => filter && filter.selected);
return filter && filter.selected;
});
res.render('unread', data); res.render('unread', data);
},
], next);
}; };
unreadController.unreadTotal = function (req, res, next) { async function getWatchedCategories(uid, cid, filter) {
var filter = req.query.filter || ''; if (plugins.hasListeners('filter:unread.categories')) {
return await plugins.fireHook('filter:unread.categories', { uid: uid, cid: cid });
}
const states = [categories.watchStates.watching];
if (filter === 'watched') {
states.push(categories.watchStates.notwatching, categories.watchStates.ignoring);
}
return await helpers.getCategoriesByStates(uid, cid, states);
}
async.waterfall([ unreadController.unreadTotal = async function (req, res, next) {
function (next) { const filter = req.query.filter || '';
plugins.fireHook('filter:unread.getValidFilters', { filters: { ...helpers.validFilters } }, next); try {
}, const data = await plugins.fireHook('filter:unread.getValidFilters', { filters: { ...helpers.validFilters } });
function (data, _next) {
if (!data.filters[filter]) { if (!data.filters[filter]) {
return next(); return next();
} }
topics.getTotalUnread(req.uid, filter, _next); const unreadCount = await topics.getTotalUnread(req.uid, filter);
}, res.json(unreadCount);
function (data) { } catch (err) {
res.json(data); next(err);
}, }
], next);
}; };

@ -12,10 +12,9 @@ var meta = require('./meta');
var plugins = require('./plugins'); var plugins = require('./plugins');
var utils = require('./utils'); var utils = require('./utils');
var sitemap = { var sitemap = module.exports;
maps: { sitemap.maps = {
topics: [], topics: [],
},
}; };
sitemap.render = function (callback) { sitemap.render = function (callback) {
@ -174,4 +173,4 @@ sitemap.clearCache = function () {
} }
}; };
module.exports = sitemap; require('./promisify')(sitemap);

@ -115,6 +115,8 @@ function setupExpressApp(app) {
const relativePath = nconf.get('relative_path'); const relativePath = nconf.get('relative_path');
const viewsDir = nconf.get('views_dir'); const viewsDir = nconf.get('views_dir');
app.renderAsync = util.promisify((tpl, data, callback) => app.render(tpl, data, callback));
app.engine('tpl', function (filepath, data, next) { app.engine('tpl', function (filepath, data, next) {
filepath = filepath.replace(/\.tpl$/, '.js'); filepath = filepath.replace(/\.tpl$/, '.js');

Loading…
Cancel
Save