refactor: async/await controllers

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

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

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

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

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

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

@ -12,10 +12,9 @@ var meta = require('./meta');
var plugins = require('./plugins');
var utils = require('./utils');
var sitemap = {
maps: {
topics: [],
},
var sitemap = module.exports;
sitemap.maps = {
topics: [],
};
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 viewsDir = nconf.get('views_dir');
app.renderAsync = util.promisify((tpl, data, callback) => app.render(tpl, data, callback));
app.engine('tpl', function (filepath, data, next) {
filepath = filepath.replace(/\.tpl$/, '.js');

Loading…
Cancel
Save