diff --git a/src/rewards/index.js b/src/rewards/index.js index 578ba5af2d..2d201e33f3 100644 --- a/src/rewards/index.js +++ b/src/rewards/index.js @@ -36,9 +36,7 @@ rewards.checkConditionAndRewardUser = function (uid, condition, method, callback return next(null, false); } - checkCondition(reward, method, function (result) { - next(null, result); - }); + checkCondition(reward, method, next); }, function (err, eligible) { if (err || !eligible) { return next(false); @@ -59,29 +57,30 @@ function getIDsByCondition(condition, callback) { } function filterCompletedRewards(uid, rewards, callback) { - db.getSortedSetRangeByScoreWithScores('uid:' + uid + ':rewards', 0, -1, 1, '+inf', function (err, data) { - if (err) { - return callback(err); - } - - var userRewards = {}; + async.waterfall([ + function (next) { + db.getSortedSetRangeByScoreWithScores('uid:' + uid + ':rewards', 0, -1, 1, '+inf', next); + }, + function (data, next) { + var userRewards = {}; - data.forEach(function (obj) { - userRewards[obj.value] = parseInt(obj.score, 10); - }); + data.forEach(function (obj) { + userRewards[obj.value] = parseInt(obj.score, 10); + }); - rewards = rewards.filter(function (reward) { - if (!reward) { - return false; - } + rewards = rewards.filter(function (reward) { + if (!reward) { + return false; + } - var claimable = parseInt(reward.claimable, 10); + var claimable = parseInt(reward.claimable, 10); - return claimable === 0 || (userRewards[reward.id] < reward.claimable); - }); + return claimable === 0 || (userRewards[reward.id] < reward.claimable); + }); - callback(null, rewards); - }); + next(null, rewards); + }, + ], callback); } function getRewardDataByIDs(ids, callback) { @@ -97,26 +96,29 @@ function getRewardsByRewardData(rewards, callback) { } function checkCondition(reward, method, callback) { - method(function (err, value) { - if (err) { - return callback(err); - } - - plugins.fireHook('filter:rewards.checkConditional:' + reward.conditional, { left: value, right: reward.value }, function (err, bool) { - callback(err || bool); - }); - }); + async.waterfall([ + function (next) { + method(next); + }, + function (value, next) { + plugins.fireHook('filter:rewards.checkConditional:' + reward.conditional, { left: value, right: reward.value }, next); + }, + function (bool, next) { + next(null, bool); + }, + ], callback); } function giveRewards(uid, rewards, callback) { - getRewardsByRewardData(rewards, function (err, rewardData) { - if (err) { - return callback(err); - } - - async.each(rewards, function (reward, next) { - plugins.fireHook('action:rewards.award:' + reward.rid, { uid: uid, reward: rewardData[rewards.indexOf(reward)] }); - db.sortedSetIncrBy('uid:' + uid + ':rewards', 1, reward.id, next); - }, callback); - }); + async.waterfall([ + function (next) { + getRewardsByRewardData(rewards, next); + }, + function (rewardData, next) { + async.each(rewards, function (reward, next) { + plugins.fireHook('action:rewards.award:' + reward.rid, { uid: uid, reward: rewardData[rewards.indexOf(reward)] }); + db.sortedSetIncrBy('uid:' + uid + ':rewards', 1, reward.id, next); + }, next); + }, + ], callback); } diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 0e1d2aa6e2..61ea8e3f28 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -1,54 +1,55 @@ 'use strict'; -(function (Auth) { - var passport = require('passport'); - var passportLocal = require('passport-local').Strategy; - var nconf = require('nconf'); - var winston = require('winston'); - var express = require('express'); +var async = require('async'); +var passport = require('passport'); +var passportLocal = require('passport-local').Strategy; +var nconf = require('nconf'); +var winston = require('winston'); +var express = require('express'); - var controllers = require('../controllers'); - var plugins = require('../plugins'); - var hotswap = require('../hotswap'); +var controllers = require('../controllers'); +var plugins = require('../plugins'); +var hotswap = require('../hotswap'); - var loginStrategies = []; +var loginStrategies = []; - Auth.initialize = function (app, middleware) { - app.use(passport.initialize()); - app.use(passport.session()); +var Auth = module.exports; - app.use(function (req, res, next) { - req.uid = req.user ? parseInt(req.user.uid, 10) : 0; - next(); - }); +Auth.initialize = function (app, middleware) { + app.use(passport.initialize()); + app.use(passport.session()); - Auth.app = app; - Auth.middleware = middleware; - }; + app.use(function (req, res, next) { + req.uid = req.user ? parseInt(req.user.uid, 10) : 0; + next(); + }); - Auth.getLoginStrategies = function () { - return loginStrategies; - }; + Auth.app = app; + Auth.middleware = middleware; +}; - Auth.reloadRoutes = function (callback) { - var router = express.Router(); - router.hotswapId = 'auth'; +Auth.getLoginStrategies = function () { + return loginStrategies; +}; - loginStrategies.length = 0; +Auth.reloadRoutes = function (callback) { + var router = express.Router(); + router.hotswapId = 'auth'; - if (plugins.hasListeners('action:auth.overrideLogin')) { - winston.warn('[authentication] Login override detected, skipping local login strategy.'); - plugins.fireHook('action:auth.overrideLogin'); - } else { - passport.use(new passportLocal({ passReqToCallback: true }, controllers.authentication.localLogin)); - } + loginStrategies.length = 0; - plugins.fireHook('filter:auth.init', loginStrategies, function (err) { - if (err) { - winston.error('filter:auth.init - plugin failure'); - return callback(err); - } + if (plugins.hasListeners('action:auth.overrideLogin')) { + winston.warn('[authentication] Login override detected, skipping local login strategy.'); + plugins.fireHook('action:auth.overrideLogin'); + } else { + passport.use(new passportLocal({ passReqToCallback: true }, controllers.authentication.localLogin)); + } + async.waterfall([ + function (next) { + plugins.fireHook('filter:auth.init', loginStrategies, next); + }, + function (loginStrategies, next) { loginStrategies.forEach(function (strategy) { if (strategy.url) { router.get(strategy.url, passport.authenticate(strategy.name, { @@ -70,19 +71,17 @@ router.post('/logout', Auth.middleware.applyCSRF, controllers.authentication.logout); hotswap.replace('auth', router); - if (typeof callback === 'function') { - callback(); - } - }); - }; - - passport.serializeUser(function (user, done) { - done(null, user.uid); - }); + next(); + }, + ], callback); +}; + +passport.serializeUser(function (user, done) { + done(null, user.uid); +}); - passport.deserializeUser(function (uid, done) { - done(null, { - uid: uid, - }); +passport.deserializeUser(function (uid, done) { + done(null, { + uid: uid, }); -}(exports)); +}); diff --git a/src/routes/index.js b/src/routes/index.js index 3dc6047b22..15339b4e11 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -205,11 +205,11 @@ module.exports = function (app, middleware, hotswapIds, callback) { async.apply(plugins.reloadRoutes), async.apply(authRoutes.reloadRoutes), async.apply(user.addInterstitials), + function (next) { + winston.info('Routes added'); + next(); + }, ], function (err) { - if (err) { - return callback(err); - } - winston.info('Routes added'); - callback(); + callback(err); }); }; diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index b63b099815..10167d06ff 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -38,13 +38,18 @@ var SocketAdmin = { }; SocketAdmin.before = function (socket, method, data, next) { - user.isAdministrator(socket.uid, function (err, isAdmin) { - if (err || isAdmin) { - return next(err); - } - winston.warn('[socket.io] Call to admin method ( ' + method + ' ) blocked (accessed by uid ' + socket.uid + ')'); - next(new Error('[[error:no-privileges]]')); - }); + async.waterfall([ + function (next) { + user.isAdministrator(socket.uid, next); + }, + function (isAdmin) { + if (isAdmin) { + return next(); + } + winston.warn('[socket.io] Call to admin method ( ' + method + ' ) blocked (accessed by uid ' + socket.uid + ')'); + next(new Error('[[error:no-privileges]]')); + }, + ], next); }; SocketAdmin.reload = function (socket, data, callback) { @@ -58,26 +63,27 @@ SocketAdmin.reload = function (socket, data, callback) { }; SocketAdmin.restart = function (socket, data, callback) { - require('../meta/build').buildAll(function (err) { - if (err) { - return callback(err); - } - - events.log({ - type: 'build', - uid: socket.uid, - ip: socket.ip, - }); - - events.log({ - type: 'restart', - uid: socket.uid, - ip: socket.ip, - }); - - meta.restart(); - callback(); - }); + async.waterfall([ + function (next) { + require('../meta/build').buildAll(next); + }, + function (next) { + events.log({ + type: 'build', + uid: socket.uid, + ip: socket.ip, + }); + + events.log({ + type: 'restart', + uid: socket.uid, + ip: socket.ip, + }); + + meta.restart(); + next(); + }, + ], callback); }; SocketAdmin.fireEvent = function (socket, data, callback) { diff --git a/src/socket.io/admin/categories.js b/src/socket.io/admin/categories.js index d4e8ef1414..232b2041d1 100644 --- a/src/socket.io/admin/categories.js +++ b/src/socket.io/admin/categories.js @@ -30,13 +30,7 @@ Categories.getAll = function (socket, data, callback) { function (result, next) { next(null, categories.getTree(result.categories, 0)); }, - ], function (err, categoriesTree) { - if (err) { - return callback(err); - } - - callback(null, categoriesTree); - }); + ], callback); }; Categories.getNames = function (socket, data, callback) { @@ -93,27 +87,31 @@ Categories.getPrivilegeSettings = function (socket, cid, callback) { }; Categories.copyPrivilegesToChildren = function (socket, cid, callback) { - categories.getCategories([cid], socket.uid, function (err, categories) { - if (err) { - return callback(err); - } - var category = categories[0]; - - async.eachSeries(category.children, function (child, next) { - copyPrivilegesToChildrenRecursive(cid, child, next); - }, callback); - }); + async.waterfall([ + function (next) { + categories.getCategories([cid], socket.uid, next); + }, + function (categories, next) { + var category = categories[0]; + + async.eachSeries(category.children, function (child, next) { + copyPrivilegesToChildrenRecursive(cid, child, next); + }, next); + }, + ], callback); }; function copyPrivilegesToChildrenRecursive(parentCid, category, callback) { - categories.copyPrivilegesFrom(parentCid, category.cid, function (err) { - if (err) { - return callback(err); - } - async.eachSeries(category.children, function (child, next) { - copyPrivilegesToChildrenRecursive(parentCid, child, next); - }, callback); - }); + async.waterfall([ + function (next) { + categories.copyPrivilegesFrom(parentCid, category.cid, next); + }, + function (next) { + async.eachSeries(category.children, function (child, next) { + copyPrivilegesToChildrenRecursive(parentCid, child, next); + }, next); + }, + ], callback); } Categories.copySettingsFrom = function (socket, data, callback) { diff --git a/src/socket.io/admin/groups.js b/src/socket.io/admin/groups.js index fdb50e0561..63b07ff6d2 100644 --- a/src/socket.io/admin/groups.js +++ b/src/socket.io/admin/groups.js @@ -3,7 +3,7 @@ var async = require('async'); var groups = require('../../groups'); -var Groups = {}; +var Groups = module.exports; Groups.create = function (socket, data, callback) { if (!data) { @@ -66,5 +66,3 @@ Groups.update = function (socket, data, callback) { groups.update(data.groupName, data.values, callback); }; - -module.exports = Groups; diff --git a/src/socket.io/admin/navigation.js b/src/socket.io/admin/navigation.js index 807b10ae85..d9297f55e1 100644 --- a/src/socket.io/admin/navigation.js +++ b/src/socket.io/admin/navigation.js @@ -1,10 +1,8 @@ 'use strict'; var navigationAdmin = require('../../navigation/admin'); -var SocketNavigation = {}; +var SocketNavigation = module.exports; SocketNavigation.save = function (socket, data, callback) { navigationAdmin.save(data, callback); }; - -module.exports = SocketNavigation; diff --git a/src/socket.io/admin/rooms.js b/src/socket.io/admin/rooms.js index 70b908d4dc..85aec8e52e 100644 --- a/src/socket.io/admin/rooms.js +++ b/src/socket.io/admin/rooms.js @@ -11,11 +11,11 @@ var pubsub = require('../../pubsub'); var stats = {}; var totals = {}; -var SocketRooms = { - stats: stats, - totals: totals, -}; +var SocketRooms = module.exports; + +SocketRooms.stats = stats; +SocketRooms.totals = totals; pubsub.on('sync:stats:start', function () { SocketRooms.getLocalStats(function (err, stats) { @@ -181,6 +181,3 @@ SocketRooms.getLocalStats = function (callback) { callback(null, socketData); }; - - -module.exports = SocketRooms; diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index cf002001cb..de2ccfc299 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -10,28 +10,29 @@ var events = require('../../events'); var meta = require('../../meta'); var plugins = require('../../plugins'); -var User = {}; +var User = module.exports; User.makeAdmins = function (socket, uids, callback) { if (!Array.isArray(uids)) { return callback(new Error('[[error:invalid-data]]')); } - user.getUsersFields(uids, ['banned'], function (err, userData) { - if (err) { - return callback(err); - } - - for (var i = 0; i < userData.length; i += 1) { - if (userData[i] && parseInt(userData[i].banned, 10) === 1) { - return callback(new Error('[[error:cant-make-banned-users-admin]]')); + async.waterfall([ + function (next) { + user.getUsersFields(uids, ['banned'], next); + }, + function (userData, next) { + for (var i = 0; i < userData.length; i += 1) { + if (userData[i] && parseInt(userData[i].banned, 10) === 1) { + return callback(new Error('[[error:cant-make-banned-users-admin]]')); + } } - } - async.each(uids, function (uid, next) { - groups.join('administrators', uid, next); - }, callback); - }); + async.each(uids, function (uid, next) { + groups.join('administrators', uid, next); + }, next); + }, + ], callback); }; User.removeAdmins = function (socket, uids, callback) { @@ -40,17 +41,18 @@ User.removeAdmins = function (socket, uids, callback) { } async.eachSeries(uids, function (uid, next) { - groups.getMemberCount('administrators', function (err, count) { - if (err) { - return next(err); - } - - if (count === 1) { - return next(new Error('[[error:cant-remove-last-admin]]')); - } + async.waterfall([ + function (next) { + groups.getMemberCount('administrators', next); + }, + function (count, next) { + if (count === 1) { + return next(new Error('[[error:cant-remove-last-admin]]')); + } - groups.leave('administrators', uid, next); - }); + groups.leave('administrators', uid, next); + }, + ], next); }, callback); }; @@ -78,14 +80,16 @@ User.validateEmail = function (socket, uids, callback) { return parseInt(uid, 10); }); - async.each(uids, function (uid, next) { - user.setUserField(uid, 'email:confirmed', 1, next); - }, function (err) { - if (err) { - return callback(err); - } - db.sortedSetRemove('users:notvalidated', uids, callback); - }); + async.waterfall([ + function (next) { + async.each(uids, function (uid, next) { + user.setUserField(uid, 'email:confirmed', 1, next); + }, next); + }, + function (next) { + db.sortedSetRemove('users:notvalidated', uids, next); + }, + ], callback); }; User.sendValidationEmail = function (socket, uids, callback) { @@ -123,15 +127,17 @@ User.sendPasswordResetEmail = function (socket, uids, callback) { }); async.each(uids, function (uid, next) { - user.getUserFields(uid, ['email', 'username'], function (err, userData) { - if (err) { - return next(err); - } - if (!userData.email) { - return next(new Error('[[error:user-doesnt-have-email, ' + userData.username + ']]')); - } - user.reset.send(userData.email, next); - }); + async.waterfall([ + function (next) { + user.getUserFields(uid, ['email', 'username'], next); + }, + function (userData, next) { + if (!userData.email) { + return next(new Error('[[error:user-doesnt-have-email, ' + userData.username + ']]')); + } + user.reset.send(userData.email, next); + }, + ], next); }, callback); }; @@ -257,5 +263,3 @@ User.rejectRegistration = function (socket, data, callback) { User.restartJobs = function (socket, data, callback) { user.startJobs(callback); }; - -module.exports = User; diff --git a/src/socket.io/blacklist.js b/src/socket.io/blacklist.js index 8592a8b901..1435d20737 100644 --- a/src/socket.io/blacklist.js +++ b/src/socket.io/blacklist.js @@ -1,24 +1,28 @@ 'use strict'; +var async = require('async'); + var user = require('../user'); var meta = require('../meta'); -var SocketBlacklist = {}; +var SocketBlacklist = module.exports; SocketBlacklist.validate = function (socket, data, callback) { meta.blacklist.validate(data.rules, callback); }; SocketBlacklist.save = function (socket, rules, callback) { - user.isAdminOrGlobalMod(socket.uid, function (err, isAdminOrGlobalMod) { - if (err || !isAdminOrGlobalMod) { - return callback(err || new Error('[[error:no-privileges]]')); - } - - meta.blacklist.save(rules, callback); - }); + async.waterfall([ + function (next) { + user.isAdminOrGlobalMod(socket.uid, next); + }, + function (isAdminOrGlobalMod, next) { + if (!isAdminOrGlobalMod) { + return callback(new Error('[[error:no-privileges]]')); + } + + meta.blacklist.save(rules, next); + }, + ], callback); }; - - -module.exports = SocketBlacklist; diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 1678b553bf..3404fb3fee 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -8,133 +8,134 @@ var user = require('../user'); var topics = require('../topics'); var apiController = require('../controllers/api'); -var SocketCategories = {}; +var SocketCategories = module.exports; SocketCategories.getRecentReplies = function (socket, cid, callback) { categories.getRecentReplies(cid, socket.uid, 4, callback); }; SocketCategories.get = function (socket, data, callback) { - async.parallel({ - isAdmin: async.apply(user.isAdministrator, socket.uid), - categories: function (next) { - async.waterfall([ - async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), - async.apply(categories.getCategoriesData), - ], next); + async.waterfall([ + function (next) { + async.parallel({ + isAdmin: async.apply(user.isAdministrator, socket.uid), + categories: function (next) { + async.waterfall([ + async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), + async.apply(categories.getCategoriesData), + ], next); + }, + }, next); }, - }, function (err, results) { - if (err) { - return callback(err); - } - - results.categories = results.categories.filter(function (category) { - return category && (!category.disabled || results.isAdmin); - }); + function (results, next) { + results.categories = results.categories.filter(function (category) { + return category && (!category.disabled || results.isAdmin); + }); - callback(null, results.categories); - }); + next(null, results.categories); + }, + ], callback); }; SocketCategories.getWatchedCategories = function (socket, data, callback) { - async.parallel({ - categories: async.apply(categories.getCategoriesByPrivilege, 'cid:0:children', socket.uid, 'find'), - ignoredCids: async.apply(user.getIgnoredCategories, socket.uid), - }, function (err, results) { - if (err) { - return callback(err); - } - var watchedCategories = results.categories.filter(function (category) { - return category && results.ignoredCids.indexOf(category.cid.toString()) === -1; - }); - - callback(null, watchedCategories); - }); + async.waterfall([ + function (next) { + async.parallel({ + categories: async.apply(categories.getCategoriesByPrivilege, 'cid:0:children', socket.uid, 'find'), + ignoredCids: async.apply(user.getIgnoredCategories, socket.uid), + }, next); + }, + function (results, next) { + var watchedCategories = results.categories.filter(function (category) { + return category && results.ignoredCids.indexOf(category.cid.toString()) === -1; + }); + + next(null, watchedCategories); + }, + ], callback); }; SocketCategories.loadMore = function (socket, data, callback) { if (!data) { return callback(new Error('[[error:invalid-data]]')); } - - async.parallel({ - privileges: function (next) { - privileges.categories.get(data.cid, socket.uid, next); - }, - settings: function (next) { - user.getSettings(socket.uid, next); + var userPrivileges; + async.waterfall([ + function (next) { + async.parallel({ + privileges: function (next) { + privileges.categories.get(data.cid, socket.uid, next); + }, + settings: function (next) { + user.getSettings(socket.uid, next); + }, + targetUid: function (next) { + if (data.author) { + user.getUidByUserslug(data.author, next); + } else { + next(); + } + }, + }, next); }, - targetUid: function (next) { - if (data.author) { - user.getUidByUserslug(data.author, next); - } else { - next(); + function (results, next) { + userPrivileges = results.privileges; + if (!userPrivileges.read) { + return callback(new Error('[[error:no-privileges]]')); } - }, - }, function (err, results) { - if (err) { - return callback(err); - } - - if (!results.privileges.read) { - return callback(new Error('[[error:no-privileges]]')); - } - - var infScrollTopicsPerPage = 20; - var set = 'cid:' + data.cid + ':tids'; - var reverse = false; - - if (data.categoryTopicSort === 'newest_to_oldest') { - reverse = true; - } else if (data.categoryTopicSort === 'most_posts') { - reverse = true; - set = 'cid:' + data.cid + ':tids:posts'; - } - - var start = Math.max(0, parseInt(data.after, 10)); - - if (data.direction === -1) { - start -= reverse ? infScrollTopicsPerPage : -infScrollTopicsPerPage; - } - - var stop = start + infScrollTopicsPerPage - 1; - - start = Math.max(0, start); - stop = Math.max(0, stop); - - if (results.targetUid) { - set = 'cid:' + data.cid + ':uid:' + results.targetUid + ':tids'; - } - - if (data.tag) { - set = [set, 'tag:' + data.tag + ':topics']; - } - - categories.getCategoryTopics({ - cid: data.cid, - set: set, - reverse: reverse, - start: start, - stop: stop, - uid: socket.uid, - targetUid: results.targetUid, - settings: results.settings, - }, function (err, data) { - if (err) { - return callback(err); + var infScrollTopicsPerPage = 20; + var set = 'cid:' + data.cid + ':tids'; + var reverse = false; + + if (data.categoryTopicSort === 'newest_to_oldest') { + reverse = true; + } else if (data.categoryTopicSort === 'most_posts') { + reverse = true; + set = 'cid:' + data.cid + ':tids:posts'; + } + + var start = Math.max(0, parseInt(data.after, 10)); + + if (data.direction === -1) { + start -= reverse ? infScrollTopicsPerPage : -infScrollTopicsPerPage; + } + + var stop = start + infScrollTopicsPerPage - 1; + + start = Math.max(0, start); + stop = Math.max(0, stop); + + if (results.targetUid) { + set = 'cid:' + data.cid + ':uid:' + results.targetUid + ':tids'; + } + + if (data.tag) { + set = [set, 'tag:' + data.tag + ':topics']; } - categories.modifyTopicsByPrivilege(data.topics, results.privileges); + categories.getCategoryTopics({ + cid: data.cid, + set: set, + reverse: reverse, + start: start, + stop: stop, + uid: socket.uid, + targetUid: results.targetUid, + settings: results.settings, + }, next); + }, + function (data, next) { + categories.modifyTopicsByPrivilege(data.topics, userPrivileges); - data.privileges = results.privileges; + data.privileges = userPrivileges; data.template = { category: true, name: 'category', }; - callback(null, data); - }); - }); + next(null, data); + }, + ], callback); }; SocketCategories.getPageCount = function (socket, cid, callback) { @@ -150,32 +151,33 @@ SocketCategories.getCategoriesByPrivilege = function (socket, privilege, callbac }; SocketCategories.getMoveCategories = function (socket, data, callback) { - async.parallel({ - isAdmin: async.apply(user.isAdministrator, socket.uid), - categories: function (next) { - async.waterfall([ - function (next) { - db.getSortedSetRange('cid:0:children', 0, -1, next); - }, - function (cids, next) { - privileges.categories.filterCids('read', cids, socket.uid, next); - }, - function (cids, next) { - categories.getCategories(cids, socket.uid, next); + async.waterfall([ + function (next) { + async.parallel({ + isAdmin: async.apply(user.isAdministrator, socket.uid), + categories: function (next) { + async.waterfall([ + function (next) { + db.getSortedSetRange('cid:0:children', 0, -1, next); + }, + function (cids, next) { + privileges.categories.filterCids('read', cids, socket.uid, next); + }, + function (cids, next) { + categories.getCategories(cids, socket.uid, next); + }, + ], next); }, - ], next); + }, next); }, - }, function (err, results) { - if (err) { - return callback(err); - } - - results.categories = results.categories.filter(function (category) { - return category && (!category.disabled || results.isAdmin) && !category.link; - }); + function (results, next) { + results.categories = results.categories.filter(function (category) { + return category && (!category.disabled || results.isAdmin) && !category.link; + }); - callback(null, results.categories); - }); + next(null, results.categories); + }, + ], callback); }; SocketCategories.watch = function (socket, cid, callback) { @@ -231,5 +233,3 @@ SocketCategories.isModerator = function (socket, cid, callback) { SocketCategories.getCategory = function (socket, cid, callback) { apiController.getCategoryData(cid, socket.uid, callback); }; - -module.exports = SocketCategories; diff --git a/src/socket.io/flags.js b/src/socket.io/flags.js index f2952b1671..6c3e7725ca 100644 --- a/src/socket.io/flags.js +++ b/src/socket.io/flags.js @@ -26,14 +26,11 @@ SocketFlags.create = function (socket, data, callback) { // If we got here, then no errors occurred flags.create(data.type, data.id, socket.uid, data.reason, next); }, - ], function (err, flagObj) { - if (err) { - return callback(err); - } - - flags.notify(flagObj, socket.uid); - callback(null, flagObj); - }); + function (flagObj, next) { + flags.notify(flagObj, socket.uid); + next(null, flagObj); + }, + ], callback); }; SocketFlags.update = function (socket, data, callback) { diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index f9f6c1b263..83ca8b1383 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -8,8 +8,7 @@ var user = require('../user'); var utils = require('../utils'); var groupsController = require('../controllers/groups'); -var SocketGroups = {}; - +var SocketGroups = module.exports; SocketGroups.before = function (socket, method, data, next) { if (!data) { @@ -304,5 +303,3 @@ SocketGroups.cover.remove = function (socket, data, callback) { }, ], callback); }; - -module.exports = SocketGroups; diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 07e24df082..f50c9e53fa 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -13,7 +13,7 @@ var utils = require('../utils'); var apiController = require('../controllers/api'); -var SocketPosts = {}; +var SocketPosts = module.exports; require('./posts/edit')(SocketPosts); require('./posts/move')(SocketPosts); @@ -152,6 +152,3 @@ SocketPosts.getReplies = function (socket, pid, callback) { }, ], callback); }; - - -module.exports = SocketPosts; diff --git a/src/socket.io/posts/votes.js b/src/socket.io/posts/votes.js index 3e65964343..0d708f2901 100644 --- a/src/socket.io/posts/votes.js +++ b/src/socket.io/posts/votes.js @@ -60,25 +60,30 @@ module.exports = function (SocketPosts) { return callback(new Error('[[error:invalid-data]]')); } - posts.getUpvotedUidsByPids(pids, function (err, data) { - if (err || !Array.isArray(data) || !data.length) { - return callback(err, []); - } - - async.map(data, function (uids, next) { - var otherCount = 0; - if (uids.length > 6) { - otherCount = uids.length - 5; - uids = uids.slice(0, 5); + async.waterfall([ + function (next) { + posts.getUpvotedUidsByPids(pids, next); + }, + function (data, next) { + if (!data.length) { + return callback(null, []); } - user.getUsernamesByUids(uids, function (err, usernames) { - next(err, { - otherCount: otherCount, - usernames: usernames, + + async.map(data, function (uids, next) { + var otherCount = 0; + if (uids.length > 6) { + otherCount = uids.length - 5; + uids = uids.slice(0, 5); + } + user.getUsernamesByUids(uids, function (err, usernames) { + next(err, { + otherCount: otherCount, + usernames: usernames, + }); }); - }); - }, callback); - }); + }, next); + }, + ], callback); }; SocketPosts.upvote = function (socket, data, callback) { diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 9777c46f05..f14e0c0c89 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -197,17 +197,18 @@ SocketUser.unfollow = function (socket, data, callback) { }; function toggleFollow(method, uid, theiruid, callback) { - user[method](uid, theiruid, function (err) { - if (err) { - return callback(err); - } - - plugins.fireHook('action:user.' + method, { - fromUid: uid, - toUid: theiruid, - }); - callback(); - }); + async.waterfall([ + function (next) { + user[method](uid, theiruid, next); + }, + function (next) { + plugins.fireHook('action:user.' + method, { + fromUid: uid, + toUid: theiruid, + }); + next(); + }, + ], callback); } SocketUser.saveSettings = function (socket, data, callback) { diff --git a/src/socket.io/user/ban.js b/src/socket.io/user/ban.js index 3af03becb8..d6cfbd6f68 100644 --- a/src/socket.io/user/ban.js +++ b/src/socket.io/user/ban.js @@ -121,11 +121,11 @@ module.exports = function (SocketUser) { function (next) { if (!reason) { return translator.translate('[[user:info.banned-no-reason]]', function (translated) { - next(false, translated); + next(null, translated); }); } - next(false, reason); + next(null, reason); }, function (_reason, next) { websockets.in('uid_' + uid).emit('event:banned', { diff --git a/src/socket.io/user/profile.js b/src/socket.io/user/profile.js index 7f6a9de2f9..792b55200d 100644 --- a/src/socket.io/user/profile.js +++ b/src/socket.io/user/profile.js @@ -67,32 +67,34 @@ module.exports = function (SocketUser) { }; function isAdminOrSelfAndPasswordMatch(uid, data, callback) { - async.parallel({ - isAdmin: async.apply(user.isAdministrator, uid), - hasPassword: async.apply(user.hasPassword, data.uid), - passwordMatch: function (next) { - if (data.password) { - user.isPasswordCorrect(data.uid, data.password, next); - } else { - next(null, false); - } + async.waterfall([ + function (next) { + async.parallel({ + isAdmin: async.apply(user.isAdministrator, uid), + hasPassword: async.apply(user.hasPassword, data.uid), + passwordMatch: function (next) { + if (data.password) { + user.isPasswordCorrect(data.uid, data.password, next); + } else { + next(null, false); + } + }, + }, next); }, - }, function (err, results) { - if (err) { - return callback(err); - } - var isSelf = parseInt(uid, 10) === parseInt(data.uid, 10); + function (results, next) { + var isSelf = parseInt(uid, 10) === parseInt(data.uid, 10); - if (!results.isAdmin && !isSelf) { - return callback(new Error('[[error:no-privileges]]')); - } + if (!results.isAdmin && !isSelf) { + return next(new Error('[[error:no-privileges]]')); + } - if (isSelf && results.hasPassword && !results.passwordMatch) { - return callback(new Error('[[error:invalid-password]]')); - } + if (isSelf && results.hasPassword && !results.passwordMatch) { + return next(new Error('[[error:invalid-password]]')); + } - callback(); - }); + next(); + }, + ], callback); } SocketUser.changePassword = function (socket, data, callback) { @@ -103,20 +105,20 @@ module.exports = function (SocketUser) { if (!data || !data.uid) { return callback(new Error('[[error:invalid-data]]')); } - - user.changePassword(socket.uid, data, function (err) { - if (err) { - return callback(err); - } - - events.log({ - type: 'password-change', - uid: socket.uid, - targetUid: data.uid, - ip: socket.ip, - }); - callback(); - }); + async.waterfall([ + function (next) { + user.changePassword(socket.uid, data, next); + }, + function (next) { + events.log({ + type: 'password-change', + uid: socket.uid, + targetUid: data.uid, + ip: socket.ip, + }); + next(); + }, + ], callback); }; SocketUser.updateProfile = function (socket, data, callback) { diff --git a/src/socket.io/user/search.js b/src/socket.io/user/search.js index 7d51ead4cf..83f380a8c8 100644 --- a/src/socket.io/user/search.js +++ b/src/socket.io/user/search.js @@ -1,5 +1,7 @@ 'use strict'; +var async = require('async'); + var user = require('../../user'); var meta = require('../../meta'); var pagination = require('../../pagination'); @@ -9,25 +11,29 @@ module.exports = function (SocketUser) { if (!data) { return callback(new Error('[[error:invalid-data]]')); } + if (!socket.uid && parseInt(meta.config.allowGuestUserSearching, 10) !== 1) { return callback(new Error('[[error:not-logged-in]]')); } - user.search({ - query: data.query, - page: data.page, - searchBy: data.searchBy, - sortBy: data.sortBy, - onlineOnly: data.onlineOnly, - bannedOnly: data.bannedOnly, - flaggedOnly: data.flaggedOnly, - uid: socket.uid, - }, function (err, result) { - if (err) { - return callback(err); - } - result.pagination = pagination.create(data.page, result.pageCount); - result['route_users:' + data.sortBy] = true; - callback(null, result); - }); + + async.waterfall([ + function (next) { + user.search({ + query: data.query, + page: data.page, + searchBy: data.searchBy, + sortBy: data.sortBy, + onlineOnly: data.onlineOnly, + bannedOnly: data.bannedOnly, + flaggedOnly: data.flaggedOnly, + uid: socket.uid, + }, next); + }, + function (result, next) { + result.pagination = pagination.create(data.page, result.pageCount); + result['route_users:' + data.sortBy] = true; + next(null, result); + }, + ], callback); }; }; diff --git a/src/topics/data.js b/src/topics/data.js index d0a6208632..29ba01a9ef 100644 --- a/src/topics/data.js +++ b/src/topics/data.js @@ -1,5 +1,6 @@ 'use strict'; +var async = require('async'); var validator = require('validator'); var db = require('../database'); @@ -21,27 +22,29 @@ function escapeTitle(topicData) { module.exports = function (Topics) { Topics.getTopicField = function (tid, field, callback) { - db.getObjectField('topic:' + tid, field, function (err, value) { - if (err) { - return callback(err); - } - - if (field === 'title') { - value = translator.escape(validator.escape(String(value))); - } - callback(null, value); - }); + async.waterfall([ + function (next) { + db.getObjectField('topic:' + tid, field, next); + }, + function (value, next) { + if (field === 'title') { + value = translator.escape(validator.escape(String(value))); + } + next(null, value); + }, + ], callback); }; Topics.getTopicFields = function (tid, fields, callback) { - db.getObjectFields('topic:' + tid, fields, function (err, topic) { - if (err) { - return callback(err); - } - - escapeTitle(topic); - callback(null, topic); - }); + async.waterfall([ + function (next) { + db.getObjectFields('topic:' + tid, fields, next); + }, + function (topic, next) { + escapeTitle(topic); + next(null, topic); + }, + ], callback); }; Topics.getTopicsFields = function (tids, fields, callback) { @@ -51,42 +54,38 @@ module.exports = function (Topics) { var keys = tids.map(function (tid) { return 'topic:' + tid; }); - db.getObjectsFields(keys, fields, function (err, topics) { - if (err) { - return callback(err); - } - - topics.forEach(escapeTitle); - callback(null, topics); - }); + async.waterfall([ + function (next) { + if (fields.length) { + db.getObjectsFields(keys, fields, next); + } else { + db.getObjects(keys, next); + } + }, + function (topics, next) { + topics.forEach(modifyTopic); + next(null, topics); + }, + ], callback); }; Topics.getTopicData = function (tid, callback) { - db.getObject('topic:' + tid, function (err, topic) { - if (err || !topic) { - return callback(err); - } - - modifyTopic(topic); - callback(null, topic); - }); + async.waterfall([ + function (next) { + db.getObject('topic:' + tid, next); + }, + function (topic, next) { + if (!topic) { + return next(null, null); + } + modifyTopic(topic); + next(null, topic); + }, + ], callback); }; Topics.getTopicsData = function (tids, callback) { - var keys = []; - - for (var i = 0; i < tids.length; i += 1) { - keys.push('topic:' + tids[i]); - } - - db.getObjects(keys, function (err, topics) { - if (err) { - return callback(err); - } - - topics.forEach(modifyTopic); - callback(null, topics); - }); + Topics.getTopicsFields(tids, [], callback); }; function modifyTopic(topic) { @@ -102,13 +101,14 @@ module.exports = function (Topics) { } Topics.getCategoryData = function (tid, callback) { - Topics.getTopicField(tid, 'cid', function (err, cid) { - if (err) { - return callback(err); - } - - categories.getCategoryData(cid, callback); - }); + async.waterfall([ + function (next) { + Topics.getTopicField(tid, 'cid', next); + }, + function (cid, next) { + categories.getCategoryData(cid, next); + }, + ], callback); }; Topics.setTopicField = function (tid, field, value, callback) { diff --git a/src/topics/fork.js b/src/topics/fork.js index 5edd9f55f4..75591207a3 100644 --- a/src/topics/fork.js +++ b/src/topics/fork.js @@ -126,33 +126,35 @@ module.exports = function (Topics) { async.parallel([ async.apply(updateRecentTopic, tid), async.apply(updateRecentTopic, postData.tid), - ], next); + ], function (err) { + next(err); + }); }, - ], function (err) { - if (err) { - return callback(err); - } - plugins.fireHook('action:post.move', { post: postData, tid: tid }); - callback(); - }); + function (next) { + plugins.fireHook('action:post.move', { post: postData, tid: tid }); + next(); + }, + ], callback); }; function updateCategoryPostCount(oldTid, tid, callback) { - Topics.getTopicsFields([oldTid, tid], ['cid'], function (err, topicData) { - if (err) { - return callback(err); - } - if (!topicData[0].cid || !topicData[1].cid) { - return callback(); - } - if (parseInt(topicData[0].cid, 10) === parseInt(topicData[1].cid, 10)) { - return callback(); - } - async.parallel([ - async.apply(db.incrObjectFieldBy, 'category:' + topicData[0].cid, 'post_count', -1), - async.apply(db.incrObjectFieldBy, 'category:' + topicData[1].cid, 'post_count', 1), - ], callback); - }); + async.waterfall([ + function (next) { + Topics.getTopicsFields([oldTid, tid], ['cid'], next); + }, + function (topicData, next) { + if (!topicData[0].cid || !topicData[1].cid) { + return callback(); + } + if (parseInt(topicData[0].cid, 10) === parseInt(topicData[1].cid, 10)) { + return callback(); + } + async.parallel([ + async.apply(db.incrObjectFieldBy, 'category:' + topicData[0].cid, 'post_count', -1), + async.apply(db.incrObjectFieldBy, 'category:' + topicData[1].cid, 'post_count', 1), + ], next); + }, + ], callback); } function updateRecentTopic(tid, callback) { diff --git a/src/topics/suggested.js b/src/topics/suggested.js index d69471744f..16548382e3 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -9,33 +9,35 @@ var search = require('../search'); module.exports = function (Topics) { Topics.getSuggestedTopics = function (tid, uid, start, stop, callback) { - async.parallel({ - tagTids: function (next) { - getTidsWithSameTags(tid, next); - }, - searchTids: function (next) { - getSearchTids(tid, next); - }, - categoryTids: function (next) { - getCategoryTids(tid, next); + async.waterfall([ + function (next) { + async.parallel({ + tagTids: function (next) { + getTidsWithSameTags(tid, next); + }, + searchTids: function (next) { + getSearchTids(tid, next); + }, + categoryTids: function (next) { + getCategoryTids(tid, next); + }, + }, next); }, - }, function (err, results) { - if (err) { - return callback(err); - } - var tids = results.tagTids.concat(results.searchTids).concat(results.categoryTids); - tids = tids.filter(function (_tid, index, array) { - return parseInt(_tid, 10) !== parseInt(tid, 10) && array.indexOf(_tid) === index; - }); + function (results, next) { + var tids = results.tagTids.concat(results.searchTids).concat(results.categoryTids); + tids = tids.filter(function (_tid, index, array) { + return parseInt(_tid, 10) !== parseInt(tid, 10) && array.indexOf(_tid) === index; + }); - if (stop === -1) { - tids = tids.slice(start); - } else { - tids = tids.slice(start, stop + 1); - } + if (stop === -1) { + tids = tids.slice(start); + } else { + tids = tids.slice(start, stop + 1); + } - Topics.getTopics(tids, uid, callback); - }); + Topics.getTopics(tids, uid, next); + }, + ], callback); }; function getTidsWithSameTags(tid, callback) { diff --git a/src/topics/tools.js b/src/topics/tools.js index d44f259ba7..a23bfca3fd 100644 --- a/src/topics/tools.js +++ b/src/topics/tools.js @@ -13,7 +13,6 @@ module.exports = function (Topics) { var topicTools = {}; Topics.tools = topicTools; - topicTools.delete = function (tid, uid, callback) { toggleDelete(tid, uid, true, callback); }; @@ -246,6 +245,7 @@ module.exports = function (Topics) { topicTools.move = function (tid, cid, uid, callback) { var topic; + var oldCid; async.waterfall([ function (next) { Topics.exists(tid, next); @@ -276,41 +276,41 @@ module.exports = function (Topics) { topic.postcount = topic.postcount || 0; db.sortedSetAdd('cid:' + cid + ':tids:posts', topic.postcount, tid, next); }, - ], next); + ], function (err) { + next(err); + }); } }, - ], function (err) { - if (err) { - return callback(err); - } - var oldCid = topic.cid; - categories.moveRecentReplies(tid, oldCid, cid); - - async.parallel([ - function (next) { - categories.incrementCategoryFieldBy(oldCid, 'topic_count', -1, next); - }, - function (next) { - categories.incrementCategoryFieldBy(cid, 'topic_count', 1, next); - }, - function (next) { - Topics.setTopicFields(tid, { - cid: cid, - oldCid: oldCid, - }, next); - }, - ], function (err) { - if (err) { - return callback(err); - } + function (next) { + oldCid = topic.cid; + categories.moveRecentReplies(tid, oldCid, cid); + + async.parallel([ + function (next) { + categories.incrementCategoryFieldBy(oldCid, 'topic_count', -1, next); + }, + function (next) { + categories.incrementCategoryFieldBy(cid, 'topic_count', 1, next); + }, + function (next) { + Topics.setTopicFields(tid, { + cid: cid, + oldCid: oldCid, + }, next); + }, + ], function (err) { + next(err); + }); + }, + function (next) { plugins.fireHook('action:topic.move', { tid: tid, fromCid: oldCid, toCid: cid, uid: uid, }); - callback(); - }); - }); + next(); + }, + ], callback); }; }; diff --git a/src/topics/unread.js b/src/topics/unread.js index f76206628f..2cee549ba9 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -326,30 +326,31 @@ module.exports = function (Topics) { })); } - async.parallel({ - recentScores: function (next) { - db.sortedSetScores('topics:recent', tids, next); - }, - userScores: function (next) { - db.sortedSetScores('uid:' + uid + ':tids_read', tids, next); - }, - tids_unread: function (next) { - db.sortedSetScores('uid:' + uid + ':tids_unread', tids, next); + async.waterfall([ + function (next) { + async.parallel({ + recentScores: function (next) { + db.sortedSetScores('topics:recent', tids, next); + }, + userScores: function (next) { + db.sortedSetScores('uid:' + uid + ':tids_read', tids, next); + }, + tids_unread: function (next) { + db.sortedSetScores('uid:' + uid + ':tids_unread', tids, next); + }, + }, next); }, - }, function (err, results) { - if (err) { - return callback(err); - } - - var cutoff = Topics.unreadCutoff(); - var result = tids.map(function (tid, index) { - return !results.tids_unread[index] && - (results.recentScores[index] < cutoff || - !!(results.userScores[index] && results.userScores[index] >= results.recentScores[index])); - }); + function (results, next) { + var cutoff = Topics.unreadCutoff(); + var result = tids.map(function (tid, index) { + return !results.tids_unread[index] && + (results.recentScores[index] < cutoff || + !!(results.userScores[index] && results.userScores[index] >= results.recentScores[index])); + }); - callback(null, result); - }); + next(null, result); + }, + ], callback); }; Topics.hasReadTopic = function (tid, uid, callback) { diff --git a/src/user/categories.js b/src/user/categories.js index 8a4b26199f..dd8afc4f03 100644 --- a/src/user/categories.js +++ b/src/user/categories.js @@ -11,23 +11,24 @@ module.exports = function (User) { }; User.getWatchedCategories = function (uid, callback) { - async.parallel({ - ignored: function (next) { - User.getIgnoredCategories(uid, next); + async.waterfall([ + function (next) { + async.parallel({ + ignored: function (next) { + User.getIgnoredCategories(uid, next); + }, + all: function (next) { + db.getSortedSetRange('categories:cid', 0, -1, next); + }, + }, next); }, - all: function (next) { - db.getSortedSetRange('categories:cid', 0, -1, next); + function (results, next) { + var watched = results.all.filter(function (cid) { + return cid && results.ignored.indexOf(cid) === -1; + }); + next(null, watched); }, - }, function (err, results) { - if (err) { - return callback(err); - } - - var watched = results.all.filter(function (cid) { - return cid && results.ignored.indexOf(cid) === -1; - }); - callback(null, watched); - }); + ], callback); }; User.ignoreCategory = function (uid, cid, callback) { diff --git a/src/user/create.js b/src/user/create.js index 99cffc397f..812e3c0a4a 100644 --- a/src/user/create.js +++ b/src/user/create.js @@ -15,137 +15,129 @@ module.exports = function (User) { if (data.email !== undefined) { data.email = validator.escape(String(data.email).trim()); } + var timestamp = data.timestamp || Date.now(); + var userData; + var userNameChanged = false; - User.isDataValid(data, function (err) { - if (err) { - return callback(err); - } - var timestamp = data.timestamp || Date.now(); - - var userData = { - username: data.username, - userslug: data.userslug, - email: data.email || '', - joindate: timestamp, - lastonline: timestamp, - picture: data.picture || '', - fullname: data.fullname || '', - location: data.location || '', - birthday: data.birthday || '', - website: '', - signature: '', - uploadedpicture: '', - profileviews: 0, - reputation: 0, - postcount: 0, - topiccount: 0, - lastposttime: 0, - banned: 0, - status: 'online', - }; - - async.parallel({ - renamedUsername: function (next) { - User.uniqueUsername(userData, next); - }, - userData: function (next) { - plugins.fireHook('filter:user.create', { user: userData, data: data }, next); - }, - }, function (err, results) { - if (err) { - return callback(err); - } - - var userNameChanged = !!results.renamedUsername; + async.waterfall([ + function (next) { + User.isDataValid(data, next); + }, + function (next) { + userData = { + username: data.username, + userslug: data.userslug, + email: data.email || '', + joindate: timestamp, + lastonline: timestamp, + picture: data.picture || '', + fullname: data.fullname || '', + location: data.location || '', + birthday: data.birthday || '', + website: '', + signature: '', + uploadedpicture: '', + profileviews: 0, + reputation: 0, + postcount: 0, + topiccount: 0, + lastposttime: 0, + banned: 0, + status: 'online', + }; + + User.uniqueUsername(userData, next); + }, + function (renamedUsername, next) { + userNameChanged = !!renamedUsername; if (userNameChanged) { - userData.username = results.renamedUsername; - userData.userslug = utils.slugify(results.renamedUsername); + userData.username = renamedUsername; + userData.userslug = utils.slugify(renamedUsername); } - - async.waterfall([ + plugins.fireHook('filter:user.create', { user: userData, data: data }, next); + }, + function (results, next) { + userData = results.user; + db.incrObjectField('global', 'nextUid', next); + }, + function (uid, next) { + userData.uid = uid; + db.setObject('user:' + uid, userData, next); + }, + function (next) { + async.parallel([ function (next) { - db.incrObjectField('global', 'nextUid', next); + db.incrObjectField('global', 'userCount', next); }, - function (uid, next) { - userData.uid = uid; - db.setObject('user:' + uid, userData, next); + function (next) { + db.sortedSetAdd('username:uid', userData.uid, userData.username, next); }, function (next) { - async.parallel([ - function (next) { - db.incrObjectField('global', 'userCount', next); - }, - function (next) { - db.sortedSetAdd('username:uid', userData.uid, userData.username, next); - }, - function (next) { - db.sortedSetAdd('username:sorted', 0, userData.username.toLowerCase() + ':' + userData.uid, next); - }, - function (next) { - db.sortedSetAdd('userslug:uid', userData.uid, userData.userslug, next); - }, - function (next) { - var sets = ['users:joindate', 'users:online']; - if (parseInt(userData.uid, 10) !== 1) { - sets.push('users:notvalidated'); - } - db.sortedSetsAdd(sets, timestamp, userData.uid, next); - }, - function (next) { - db.sortedSetsAdd(['users:postcount', 'users:reputation'], 0, userData.uid, next); - }, - function (next) { - groups.join('registered-users', userData.uid, next); - }, - function (next) { - User.notifications.sendWelcomeNotification(userData.uid, next); - }, - function (next) { - if (userData.email) { - async.parallel([ - async.apply(db.sortedSetAdd, 'email:uid', userData.uid, userData.email.toLowerCase()), - async.apply(db.sortedSetAdd, 'email:sorted', 0, userData.email.toLowerCase() + ':' + userData.uid), - ], next); - - if (parseInt(userData.uid, 10) !== 1 && parseInt(meta.config.requireEmailConfirmation, 10) === 1) { - User.email.sendValidationEmail(userData.uid, userData.email); - } - } else { - next(); - } - }, - function (next) { - if (!data.password) { - return next(); - } + db.sortedSetAdd('username:sorted', 0, userData.username.toLowerCase() + ':' + userData.uid, next); + }, + function (next) { + db.sortedSetAdd('userslug:uid', userData.uid, userData.userslug, next); + }, + function (next) { + var sets = ['users:joindate', 'users:online']; + if (parseInt(userData.uid, 10) !== 1) { + sets.push('users:notvalidated'); + } + db.sortedSetsAdd(sets, timestamp, userData.uid, next); + }, + function (next) { + db.sortedSetsAdd(['users:postcount', 'users:reputation'], 0, userData.uid, next); + }, + function (next) { + groups.join('registered-users', userData.uid, next); + }, + function (next) { + User.notifications.sendWelcomeNotification(userData.uid, next); + }, + function (next) { + if (userData.email) { + async.parallel([ + async.apply(db.sortedSetAdd, 'email:uid', userData.uid, userData.email.toLowerCase()), + async.apply(db.sortedSetAdd, 'email:sorted', 0, userData.email.toLowerCase() + ':' + userData.uid), + ], next); + + if (parseInt(userData.uid, 10) !== 1 && parseInt(meta.config.requireEmailConfirmation, 10) === 1) { + User.email.sendValidationEmail(userData.uid, userData.email); + } + } else { + next(); + } + }, + function (next) { + if (!data.password) { + return next(); + } - User.hashPassword(data.password, function (err, hash) { - if (err) { - return next(err); - } + User.hashPassword(data.password, function (err, hash) { + if (err) { + return next(err); + } - async.parallel([ - async.apply(User.setUserField, userData.uid, 'password', hash), - async.apply(User.reset.updateExpiry, userData.uid), - ], next); - }); - }, - function (next) { - User.updateDigestSetting(userData.uid, meta.config.dailyDigestFreq, next); - }, - ], next); + async.parallel([ + async.apply(User.setUserField, userData.uid, 'password', hash), + async.apply(User.reset.updateExpiry, userData.uid), + ], next); + }); }, - function (results, next) { - if (userNameChanged) { - User.notifications.sendNameChangeNotification(userData.uid, userData.username); - } - plugins.fireHook('action:user.create', { user: userData }); - next(null, userData.uid); + function (next) { + User.updateDigestSetting(userData.uid, meta.config.dailyDigestFreq, next); }, - ], callback); - }); - }); + ], next); + }, + function (results, next) { + if (userNameChanged) { + User.notifications.sendNameChangeNotification(userData.uid, userData.username); + } + plugins.fireHook('action:user.create', { user: userData }); + next(null, userData.uid); + }, + ], callback); }; User.isDataValid = function (userData, callback) { @@ -201,26 +193,23 @@ module.exports = function (User) { }; User.uniqueUsername = function (userData, callback) { - meta.userOrGroupExists(userData.userslug, function (err, exists) { - if (err || !exists) { - return callback(err); - } - - var num = 0; - - function go() { - var username = userData.username + ' ' + num.toString(32); - meta.userOrGroupExists(username, function (err, exists) { - if (err || !exists) { - return callback(err, username); + var numTries = 0; + function go(username) { + async.waterfall([ + function (next) { + meta.userOrGroupExists(username, next); + }, + function (exists) { + if (!exists) { + return callback(null, numTries ? username : null); } + username = userData.username + ' ' + numTries.toString(32); + numTries += 1; + go(username); + }, + ], callback); + } - num += 1; - go(); - }); - } - - go(); - }); + go(userData.userslug); }; }; diff --git a/src/user/notifications.js b/src/user/notifications.js index 953caeb2c2..1eedf6a58c 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -191,7 +191,6 @@ UserNotifications.getUnreadCount = function (uid, callback) { return callback(null, 0); } - async.waterfall([ function (next) { db.getSortedSetRevRange('uid:' + uid + ':notifications:unread', 0, 99, next); diff --git a/src/user/password.js b/src/user/password.js index 6cf5d8e5d5..7c9e927275 100644 --- a/src/user/password.js +++ b/src/user/password.js @@ -17,22 +17,21 @@ module.exports = function (User) { User.isPasswordCorrect = function (uid, password, callback) { password = password || ''; + var hashedPassword; async.waterfall([ function (next) { db.getObjectField('user:' + uid, 'password', next); }, - function (hashedPassword, next) { + function (_hashedPassword, next) { + hashedPassword = _hashedPassword; if (!hashedPassword) { return callback(null, true); } - User.isPasswordValid(password, function (err) { - if (err) { - return next(err); - } - - Password.compare(password, hashedPassword, next); - }); + User.isPasswordValid(password, next); + }, + function (next) { + Password.compare(password, hashedPassword, next); }, ], callback); }; diff --git a/src/user/picture.js b/src/user/picture.js index 78915691d2..817073163b 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -183,14 +183,15 @@ module.exports = function (User) { if (!convertToPNG) { return setImmediate(callback, null, path); } - - image.normalise(path, extension, function (err, newPath) { - if (err) { - return callback(err); - } - file.delete(path); - callback(null, newPath); - }); + async.waterfall([ + function (next) { + image.normalise(path, extension, next); + }, + function (newPath, next) { + file.delete(path); + next(null, newPath); + }, + ], callback); } function uploadProfileOrCover(filename, image, callback) { diff --git a/src/user/posts.js b/src/user/posts.js index 3f2d608ee1..cba8c31008 100644 --- a/src/user/posts.js +++ b/src/user/posts.js @@ -10,55 +10,55 @@ module.exports = function (User) { if (parseInt(uid, 10) === 0) { return callback(); } - - async.parallel({ - userData: function (next) { - User.getUserFields(uid, ['banned', 'lastposttime', 'joindate', 'email', 'email:confirmed', 'reputation'], next); - }, - exists: function (next) { - db.exists('user:' + uid, next); - }, - isAdminOrMod: function (next) { - privileges.categories.isAdminOrMod(cid, uid, next); + async.waterfall([ + function (next) { + async.parallel({ + userData: function (next) { + User.getUserFields(uid, ['banned', 'lastposttime', 'joindate', 'email', 'email:confirmed', 'reputation'], next); + }, + exists: function (next) { + db.exists('user:' + uid, next); + }, + isAdminOrMod: function (next) { + privileges.categories.isAdminOrMod(cid, uid, next); + }, + }, next); }, - }, function (err, results) { - if (err) { - return callback(err); - } + function (results, next) { + if (!results.exists) { + return next(new Error('[[error:no-user]]')); + } - if (!results.exists) { - return callback(new Error('[[error:no-user]]')); - } + if (results.isAdminOrMod) { + return next(); + } - if (results.isAdminOrMod) { - return callback(); - } + var userData = results.userData; - var userData = results.userData; + if (parseInt(userData.banned, 10) === 1) { + return next(new Error('[[error:user-banned]]')); + } - if (parseInt(userData.banned, 10) === 1) { - return callback(new Error('[[error:user-banned]]')); - } + if (parseInt(meta.config.requireEmailConfirmation, 10) === 1 && parseInt(userData['email:confirmed'], 10) !== 1) { + return next(new Error('[[error:email-not-confirmed]]')); + } - if (parseInt(meta.config.requireEmailConfirmation, 10) === 1 && parseInt(userData['email:confirmed'], 10) !== 1) { - return callback(new Error('[[error:email-not-confirmed]]')); - } + var now = Date.now(); + if (now - parseInt(userData.joindate, 10) < parseInt(meta.config.initialPostDelay, 10) * 1000) { + return next(new Error('[[error:user-too-new, ' + meta.config.initialPostDelay + ']]')); + } - var now = Date.now(); - if (now - parseInt(userData.joindate, 10) < parseInt(meta.config.initialPostDelay, 10) * 1000) { - return callback(new Error('[[error:user-too-new, ' + meta.config.initialPostDelay + ']]')); - } + var lastposttime = userData.lastposttime || 0; - var lastposttime = userData.lastposttime || 0; + if (parseInt(meta.config.newbiePostDelay, 10) > 0 && parseInt(meta.config.newbiePostDelayThreshold, 10) > parseInt(userData.reputation, 10) && now - parseInt(lastposttime, 10) < parseInt(meta.config.newbiePostDelay, 10) * 1000) { + return next(new Error('[[error:too-many-posts-newbie, ' + meta.config.newbiePostDelay + ', ' + meta.config.newbiePostDelayThreshold + ']]')); + } else if (now - parseInt(lastposttime, 10) < parseInt(meta.config.postDelay, 10) * 1000) { + return next(new Error('[[error:too-many-posts, ' + meta.config.postDelay + ']]')); + } - if (parseInt(meta.config.newbiePostDelay, 10) > 0 && parseInt(meta.config.newbiePostDelayThreshold, 10) > parseInt(userData.reputation, 10) && now - parseInt(lastposttime, 10) < parseInt(meta.config.newbiePostDelay, 10) * 1000) { - return callback(new Error('[[error:too-many-posts-newbie, ' + meta.config.newbiePostDelay + ', ' + meta.config.newbiePostDelayThreshold + ']]')); - } else if (now - parseInt(lastposttime, 10) < parseInt(meta.config.postDelay, 10) * 1000) { - return callback(new Error('[[error:too-many-posts, ' + meta.config.postDelay + ']]')); - } - - callback(); - }); + next(); + }, + ], callback); }; User.onNewPostMade = function (postData, callback) { @@ -84,15 +84,17 @@ module.exports = function (User) { User.incrementUserPostCountBy = function (uid, value, callback) { callback = callback || function () {}; - User.incrementUserFieldBy(uid, 'postcount', value, function (err, newpostcount) { - if (err) { - return callback(err); - } - if (!parseInt(uid, 10)) { - return callback(); - } - db.sortedSetAdd('users:postcount', newpostcount, uid, callback); - }); + async.waterfall([ + function (next) { + User.incrementUserFieldBy(uid, 'postcount', value, next); + }, + function (newpostcount, next) { + if (!parseInt(uid, 10)) { + return next(); + } + db.sortedSetAdd('users:postcount', newpostcount, uid, next); + }, + ], callback); }; User.getPostIds = function (uid, start, stop, callback) { diff --git a/src/webserver.js b/src/webserver.js index 868eb4429c..2d26045b8b 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -63,9 +63,9 @@ module.exports.listen = function (callback) { helpers.register(); logger.init(app); - next(); + + initializeNodeBB(next); }, - initializeNodeBB, function (next) { winston.info('NodeBB Ready'); diff --git a/test/user.js b/test/user.js index f027543099..495caf17fb 100644 --- a/test/user.js +++ b/test/user.js @@ -69,6 +69,31 @@ describe('User', function () { done(); }); }); + + it('should error with invalid password', function (done) { + User.create({ username: 'test', password: '1' }, function (err) { + assert.equal(err.message, '[[user:change_password_error_length]]'); + done(); + }); + }); + + it('should error with invalid password', function (done) { + User.create({ username: 'test', password: {} }, function (err) { + assert.equal(err.message, '[[error:invalid-password]]'); + done(); + }); + }); + + it('should error with a too long password', function (done) { + var toolong = ''; + for (var i = 0; i < 5000; i++) { + toolong += 'a'; + } + User.create({ username: 'test', password: toolong }, function (err) { + assert.equal(err.message, '[[error:password-too-long]]'); + done(); + }); + }); }); describe('.uniqueUsername()', function () { @@ -77,7 +102,6 @@ describe('User', function () { for (var i = 0; i < 10; i += 1) { users.push({ username: 'Jane Doe', - password: 'abcdefghi', email: 'jane.doe' + i + '@example.com', }); }