diff --git a/src/controllers/api.js b/src/controllers/api.js index 66392e6160..ab52da69cd 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -13,9 +13,8 @@ var privileges = require('../privileges'); var plugins = require('../plugins'); var widgets = require('../widgets'); var translator = require('../../public/src/modules/translator'); -var accountHelpers = require('../controllers/accounts/helpers'); -var apiController = {}; +var apiController = module.exports; apiController.getConfig = function (req, res, next) { var config = {}; @@ -220,92 +219,6 @@ apiController.getObject = function (req, res, next) { }); }; -apiController.getCurrentUser = function (req, res, next) { - if (!req.uid) { - return res.status(401).json('not-authorized'); - } - async.waterfall([ - function (next) { - user.getUserField(req.uid, 'userslug', next); - }, - function (userslug, next) { - accountHelpers.getUserDataByUserSlug(userslug, req.uid, next); - }, - ], function (err, userData) { - if (err) { - return next(err); - } - res.json(userData); - }); -}; - -apiController.getUserByUID = function (req, res, next) { - byType('uid', req, res, next); -}; - -apiController.getUserByUsername = function (req, res, next) { - byType('username', req, res, next); -}; - -apiController.getUserByEmail = function (req, res, next) { - byType('email', req, res, next); -}; - -function byType(type, req, res, next) { - apiController.getUserDataByField(req.uid, type, req.params[type], function (err, data) { - if (err || !data) { - return next(err); - } - res.json(data); - }); -} - -apiController.getUserDataByField = function (callerUid, field, fieldValue, callback) { - async.waterfall([ - function (next) { - if (field === 'uid') { - next(null, fieldValue); - } else if (field === 'username') { - user.getUidByUsername(fieldValue, next); - } else if (field === 'email') { - user.getUidByEmail(fieldValue, next); - } else { - next(); - } - }, - function (uid, next) { - if (!uid) { - return next(); - } - apiController.getUserDataByUID(callerUid, uid, next); - }, - ], callback); -}; - -apiController.getUserDataByUID = function (callerUid, uid, callback) { - if (!parseInt(callerUid, 10) && parseInt(meta.config.privateUserInfo, 10) === 1) { - return callback(new Error('[[error:no-privileges]]')); - } - - if (!parseInt(uid, 10)) { - return callback(new Error('[[error:no-user]]')); - } - - async.parallel({ - userData: async.apply(user.getUserData, uid), - settings: async.apply(user.getSettings, uid), - }, function (err, results) { - if (err || !results.userData) { - return callback(err || new Error('[[error:no-user]]')); - } - - results.userData.email = results.settings.showemail ? results.userData.email : undefined; - results.userData.fullname = results.settings.showfullname ? results.userData.fullname : undefined; - - callback(null, results.userData); - }); -}; - apiController.getModerators = function (req, res, next) { categories.getModerators(req.params.cid, function (err, moderators) { if (err) { @@ -314,16 +227,3 @@ apiController.getModerators = function (req, res, next) { res.json({ moderators: moderators }); }); }; - - -apiController.getRecentPosts = function (req, res, next) { - posts.getRecentPosts(req.uid, 0, 19, req.params.term, function (err, data) { - if (err) { - return next(err); - } - - res.json(data); - }); -}; - -module.exports = apiController; diff --git a/src/controllers/index.js b/src/controllers/index.js index 00059dd825..49c1c4c2c2 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -20,6 +20,7 @@ Controllers.recent = require('./recent'); Controllers.popular = require('./popular'); Controllers.tags = require('./tags'); Controllers.search = require('./search'); +Controllers.user = require('./user'); Controllers.users = require('./users'); Controllers.groups = require('./groups'); Controllers.accounts = require('./accounts'); diff --git a/src/controllers/posts.js b/src/controllers/posts.js index 90596d5b34..8afb3f5729 100644 --- a/src/controllers/posts.js +++ b/src/controllers/posts.js @@ -1,24 +1,38 @@ 'use strict'; +var async = require('async'); + var posts = require('../posts'); var helpers = require('./helpers'); -var postsController = {}; +var postsController = module.exports; -postsController.redirectToPost = function (req, res, callback) { +postsController.redirectToPost = function (req, res, next) { var pid = parseInt(req.params.pid, 10); if (!pid) { - return callback(); + return next(); } - posts.generatePostPath(pid, req.uid, function (err, path) { - if (err || !path) { - return callback(err); - } - - helpers.redirect(res, path); - }); + async.waterfall([ + function (next) { + posts.generatePostPath(pid, req.uid, next); + }, + function (path, next) { + if (!path) { + return next(); + } + helpers.redirect(res, path); + }, + ], next); }; - -module.exports = postsController; +postsController.getRecentPosts = function (req, res, next) { + async.waterfall([ + function (next) { + posts.getRecentPosts(req.uid, 0, 19, req.params.term, next); + }, + function (data) { + res.json(data); + }, + ], next); +}; diff --git a/src/controllers/user.js b/src/controllers/user.js new file mode 100644 index 0000000000..c1049adffe --- /dev/null +++ b/src/controllers/user.js @@ -0,0 +1,94 @@ +'use strict'; + +var async = require('async'); + +var user = require('../user'); +var meta = require('../meta'); +var accountHelpers = require('./accounts/helpers'); + +var userController = module.exports; + +userController.getCurrentUser = function (req, res, next) { + if (!req.uid) { + return res.status(401).json('not-authorized'); + } + async.waterfall([ + function (next) { + user.getUserField(req.uid, 'userslug', next); + }, + function (userslug, next) { + accountHelpers.getUserDataByUserSlug(userslug, req.uid, next); + }, + function (userData) { + res.json(userData); + }, + ], next); +}; + + +userController.getUserByUID = function (req, res, next) { + byType('uid', req, res, next); +}; + +userController.getUserByUsername = function (req, res, next) { + byType('username', req, res, next); +}; + +userController.getUserByEmail = function (req, res, next) { + byType('email', req, res, next); +}; + +function byType(type, req, res, next) { + userController.getUserDataByField(req.uid, type, req.params[type], function (err, data) { + if (err || !data) { + return next(err); + } + res.json(data); + }); +} + +userController.getUserDataByField = function (callerUid, field, fieldValue, callback) { + async.waterfall([ + function (next) { + if (field === 'uid') { + next(null, fieldValue); + } else if (field === 'username') { + user.getUidByUsername(fieldValue, next); + } else if (field === 'email') { + user.getUidByEmail(fieldValue, next); + } else { + next(); + } + }, + function (uid, next) { + if (!uid) { + return next(); + } + userController.getUserDataByUID(callerUid, uid, next); + }, + ], callback); +}; + +userController.getUserDataByUID = function (callerUid, uid, callback) { + if (!parseInt(callerUid, 10) && parseInt(meta.config.privateUserInfo, 10) === 1) { + return callback(new Error('[[error:no-privileges]]')); + } + + if (!parseInt(uid, 10)) { + return callback(new Error('[[error:no-user]]')); + } + + async.parallel({ + userData: async.apply(user.getUserData, uid), + settings: async.apply(user.getSettings, uid), + }, function (err, results) { + if (err || !results.userData) { + return callback(err || new Error('[[error:no-user]]')); + } + + results.userData.email = results.settings.showemail ? results.userData.email : undefined; + results.userData.fullname = results.settings.showfullname ? results.userData.fullname : undefined; + + callback(null, results.userData); + }); +}; diff --git a/src/routes/api.js b/src/routes/api.js index 16ead5c588..9b5a7f77c7 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -11,17 +11,17 @@ module.exports = function (app, middleware, controllers) { router.get('/config', middleware.applyCSRF, controllers.api.getConfig); router.get('/widgets/render', controllers.api.renderWidgets); - router.get('/me', middleware.checkGlobalPrivacySettings, controllers.api.getCurrentUser); - router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.api.getUserByUID); - router.get('/user/username/:username', middleware.checkGlobalPrivacySettings, controllers.api.getUserByUsername); - router.get('/user/email/:email', middleware.checkGlobalPrivacySettings, controllers.api.getUserByEmail); + router.get('/me', middleware.checkGlobalPrivacySettings, controllers.user.getCurrentUser); + router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.user.getUserByUID); + router.get('/user/username/:username', middleware.checkGlobalPrivacySettings, controllers.user.getUserByUsername); + router.get('/user/email/:email', middleware.checkGlobalPrivacySettings, controllers.user.getUserByEmail); router.get('/:type/pid/:id', controllers.api.getObject); router.get('/:type/tid/:id', controllers.api.getObject); router.get('/:type/cid/:id', controllers.api.getObject); router.get('/categories/:cid/moderators', controllers.api.getModerators); - router.get('/recent/posts/:term?', controllers.api.getRecentPosts); + router.get('/recent/posts/:term?', controllers.posts.getRecentPosts); router.get('/unread/:filter?/total', middleware.authenticate, controllers.unread.unreadTotal); router.get('/topic/teaser/:topic_id', controllers.topics.teaser); router.get('/topic/pagination/:topic_id', controllers.topics.pagination); diff --git a/src/socket.io/user.js b/src/socket.io/user.js index f7208b116a..78f696a19b 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -12,7 +12,7 @@ var meta = require('../meta'); var events = require('../events'); var emailer = require('../emailer'); var db = require('../database'); -var apiController = require('../controllers/api'); +var userController = require('../controllers/user'); var privileges = require('../privileges'); var SocketUser = {}; @@ -303,15 +303,15 @@ SocketUser.invite = function (socket, email, callback) { }; SocketUser.getUserByUID = function (socket, uid, callback) { - apiController.getUserDataByField(socket.uid, 'uid', uid, callback); + userController.getUserDataByField(socket.uid, 'uid', uid, callback); }; SocketUser.getUserByUsername = function (socket, username, callback) { - apiController.getUserDataByField(socket.uid, 'username', username, callback); + userController.getUserDataByField(socket.uid, 'username', username, callback); }; SocketUser.getUserByEmail = function (socket, email, callback) { - apiController.getUserDataByField(socket.uid, 'email', email, callback); + userController.getUserDataByField(socket.uid, 'email', email, callback); }; SocketUser.setModerationNote = function (socket, data, callback) { diff --git a/src/user.js b/src/user.js index 968417f816..48098feadf 100644 --- a/src/user.js +++ b/src/user.js @@ -6,378 +6,324 @@ var _ = require('underscore'); var groups = require('./groups'); var plugins = require('./plugins'); var db = require('./database'); -var topics = require('./topics'); var privileges = require('./privileges'); var meta = require('./meta'); -(function (User) { - User.email = require('./user/email'); - User.notifications = require('./user/notifications'); - User.reset = require('./user/reset'); - User.digest = require('./user/digest'); - - require('./user/data')(User); - require('./user/auth')(User); - require('./user/bans')(User); - require('./user/create')(User); - require('./user/posts')(User); - require('./user/topics')(User); - require('./user/categories')(User); - require('./user/follow')(User); - require('./user/profile')(User); - require('./user/admin')(User); - require('./user/delete')(User); - require('./user/settings')(User); - require('./user/search')(User); - require('./user/jobs')(User); - require('./user/picture')(User); - require('./user/approval')(User); - require('./user/invite')(User); - require('./user/password')(User); - require('./user/info')(User); - - User.updateLastOnlineTime = function (uid, callback) { - callback = callback || function () {}; - db.getObjectFields('user:' + uid, ['status', 'lastonline'], function (err, userData) { - var now = Date.now(); - if (err || userData.status === 'offline' || now - parseInt(userData.lastonline, 10) < 300000) { - return callback(err); - } - User.setUserField(uid, 'lastonline', now, callback); - }); - }; - - User.updateOnlineUsers = function (uid, callback) { - callback = callback || function () {}; - +var User = module.exports; + +User.email = require('./user/email'); +User.notifications = require('./user/notifications'); +User.reset = require('./user/reset'); +User.digest = require('./user/digest'); + +require('./user/data')(User); +require('./user/auth')(User); +require('./user/bans')(User); +require('./user/create')(User); +require('./user/posts')(User); +require('./user/topics')(User); +require('./user/categories')(User); +require('./user/follow')(User); +require('./user/profile')(User); +require('./user/admin')(User); +require('./user/delete')(User); +require('./user/settings')(User); +require('./user/search')(User); +require('./user/jobs')(User); +require('./user/picture')(User); +require('./user/approval')(User); +require('./user/invite')(User); +require('./user/password')(User); +require('./user/info')(User); +require('./user/online')(User); + +User.getUidsFromSet = function (set, start, stop, callback) { + if (set === 'users:online') { + var count = parseInt(stop, 10) === -1 ? stop : stop - start + 1; var now = Date.now(); - async.waterfall([ - function (next) { - db.sortedSetScore('users:online', uid, next); - }, - function (userOnlineTime, next) { - if (now - parseInt(userOnlineTime, 10) < 300000) { - return callback(); - } - db.sortedSetAdd('users:online', now, uid, next); - }, - function (next) { - topics.pushUnreadCount(uid); - plugins.fireHook('action:user.online', { uid: uid, timestamp: now }); - next(); - }, - ], callback); - }; - - User.getUidsFromSet = function (set, start, stop, callback) { - if (set === 'users:online') { - var count = parseInt(stop, 10) === -1 ? stop : stop - start + 1; - var now = Date.now(); - db.getSortedSetRevRangeByScore(set, start, count, '+inf', now - 300000, callback); - } else { - db.getSortedSetRevRange(set, start, stop, callback); - } - }; - - User.getUsersFromSet = function (set, uid, start, stop, callback) { - async.waterfall([ - function (next) { - User.getUidsFromSet(set, start, stop, next); - }, - function (uids, next) { - User.getUsers(uids, uid, next); - }, - ], callback); - }; - - User.getUsersWithFields = function (uids, fields, uid, callback) { - async.waterfall([ - function (next) { - plugins.fireHook('filter:users.addFields', { fields: fields }, next); - }, - function (data, next) { - data.fields = data.fields.filter(function (field, index, array) { - return array.indexOf(field) === index; - }); - - async.parallel({ - userData: function (next) { - User.getUsersFields(uids, data.fields, next); - }, - isAdmin: function (next) { - User.isAdministrator(uids, next); - }, - }, next); - }, - function (results, next) { - results.userData.forEach(function (user, index) { - if (user) { - user.status = User.getStatus(user); - user.administrator = results.isAdmin[index]; - user.banned = parseInt(user.banned, 10) === 1; - user.banned_until = parseInt(user['banned:expire'], 10) || 0; - user.banned_until_readable = user.banned_until ? new Date(user.banned_until).toString() : 'Not Banned'; - user['email:confirmed'] = parseInt(user['email:confirmed'], 10) === 1; - } - }); - plugins.fireHook('filter:userlist.get', { users: results.userData, uid: uid }, next); - }, - function (data, next) { - next(null, data.users); - }, - ], callback); - }; - - User.getUsers = function (uids, uid, callback) { - var fields = ['uid', 'username', 'userslug', 'picture', 'status', 'flags', - 'banned', 'banned:expire', 'joindate', 'postcount', 'reputation', 'email:confirmed', 'lastonline']; - - User.getUsersWithFields(uids, fields, uid, callback); - }; - - User.getStatus = function (userData) { - var isOnline = (Date.now() - parseInt(userData.lastonline, 10)) < 300000; - return isOnline ? (userData.status || 'online') : 'offline'; - }; - - User.isOnline = function (uid, callback) { - if (Array.isArray(uid)) { - db.sortedSetScores('users:online', uid, function (err, lastonline) { - if (err) { - return callback(err); - } - var now = Date.now(); - var isOnline = uid.map(function (uid, index) { - return now - lastonline[index] < 300000; - }); - callback(null, isOnline); + db.getSortedSetRevRangeByScore(set, start, count, '+inf', now - 300000, callback); + } else { + db.getSortedSetRevRange(set, start, stop, callback); + } +}; + +User.getUsersFromSet = function (set, uid, start, stop, callback) { + async.waterfall([ + function (next) { + User.getUidsFromSet(set, start, stop, next); + }, + function (uids, next) { + User.getUsers(uids, uid, next); + }, + ], callback); +}; + +User.getUsersWithFields = function (uids, fields, uid, callback) { + async.waterfall([ + function (next) { + plugins.fireHook('filter:users.addFields', { fields: fields }, next); + }, + function (data, next) { + data.fields = data.fields.filter(function (field, index, array) { + return array.indexOf(field) === index; }); - } else { - db.sortedSetScore('users:online', uid, function (err, lastonline) { - if (err) { - return callback(err); + + async.parallel({ + userData: function (next) { + User.getUsersFields(uids, data.fields, next); + }, + isAdmin: function (next) { + User.isAdministrator(uids, next); + }, + }, next); + }, + function (results, next) { + results.userData.forEach(function (user, index) { + if (user) { + user.status = User.getStatus(user); + user.administrator = results.isAdmin[index]; + user.banned = parseInt(user.banned, 10) === 1; + user.banned_until = parseInt(user['banned:expire'], 10) || 0; + user.banned_until_readable = user.banned_until ? new Date(user.banned_until).toString() : 'Not Banned'; + user['email:confirmed'] = parseInt(user['email:confirmed'], 10) === 1; } - var isOnline = Date.now() - parseInt(lastonline, 10) < 300000; - callback(null, isOnline); }); - } - }; - - User.exists = function (uid, callback) { - db.isSortedSetMember('users:joindate', uid, callback); - }; - - User.existsBySlug = function (userslug, callback) { - User.getUidByUserslug(userslug, function (err, exists) { - callback(err, !!exists); - }); - }; - - User.getUidByUsername = function (username, callback) { - if (!username) { - return callback(null, 0); - } - db.sortedSetScore('username:uid', username, callback); - }; - - User.getUidsByUsernames = function (usernames, callback) { - db.sortedSetScores('username:uid', usernames, callback); - }; - - User.getUidByUserslug = function (userslug, callback) { - if (!userslug) { - return callback(null, 0); - } - db.sortedSetScore('userslug:uid', userslug, callback); - }; - - User.getUsernamesByUids = function (uids, callback) { - User.getUsersFields(uids, ['username'], function (err, users) { - if (err) { - return callback(err); - } - + plugins.fireHook('filter:userlist.get', { users: results.userData, uid: uid }, next); + }, + function (data, next) { + next(null, data.users); + }, + ], callback); +}; + +User.getUsers = function (uids, uid, callback) { + var fields = ['uid', 'username', 'userslug', 'picture', 'status', 'flags', + 'banned', 'banned:expire', 'joindate', 'postcount', 'reputation', 'email:confirmed', 'lastonline']; + + User.getUsersWithFields(uids, fields, uid, callback); +}; + +User.getStatus = function (userData) { + var isOnline = (Date.now() - parseInt(userData.lastonline, 10)) < 300000; + return isOnline ? (userData.status || 'online') : 'offline'; +}; + +User.exists = function (uid, callback) { + db.isSortedSetMember('users:joindate', uid, callback); +}; + +User.existsBySlug = function (userslug, callback) { + User.getUidByUserslug(userslug, function (err, exists) { + callback(err, !!exists); + }); +}; + +User.getUidByUsername = function (username, callback) { + if (!username) { + return callback(null, 0); + } + db.sortedSetScore('username:uid', username, callback); +}; + +User.getUidsByUsernames = function (usernames, callback) { + db.sortedSetScores('username:uid', usernames, callback); +}; + +User.getUidByUserslug = function (userslug, callback) { + if (!userslug) { + return callback(null, 0); + } + db.sortedSetScore('userslug:uid', userslug, callback); +}; + +User.getUsernamesByUids = function (uids, callback) { + async.waterfall([ + function (next) { + User.getUsersFields(uids, ['username'], next); + }, + function (users, next) { users = users.map(function (user) { return user.username; }); - callback(null, users); - }); - }; - - User.getUsernameByUserslug = function (slug, callback) { - async.waterfall([ - function (next) { - User.getUidByUserslug(slug, next); - }, - function (uid, next) { - User.getUserField(uid, 'username', next); - }, - ], callback); - }; - - User.getUidByEmail = function (email, callback) { - db.sortedSetScore('email:uid', email.toLowerCase(), callback); - }; - - User.getUidsByEmails = function (emails, callback) { - emails = emails.map(function (email) { - return email && email.toLowerCase(); - }); - db.sortedSetScores('email:uid', emails, callback); - }; - - User.getUsernameByEmail = function (email, callback) { - db.sortedSetScore('email:uid', email.toLowerCase(), function (err, uid) { - if (err) { - return callback(err); - } - User.getUserField(uid, 'username', callback); - }); - }; - - User.isModerator = function (uid, cid, callback) { - privileges.users.isModerator(uid, cid, callback); - }; - - User.isModeratorOfAnyCategory = function (uid, callback) { - User.getModeratedCids(uid, function (err, cids) { - callback(err, Array.isArray(cids) ? !!cids.length : false); - }); - }; - - User.isAdministrator = function (uid, callback) { - privileges.users.isAdministrator(uid, callback); - }; - - User.isGlobalModerator = function (uid, callback) { - privileges.users.isGlobalModerator(uid, callback); - }; - - User.isAdminOrGlobalMod = function (uid, callback) { - async.parallel({ - isAdmin: async.apply(User.isAdministrator, uid), - isGlobalMod: async.apply(User.isGlobalModerator, uid), - }, function (err, results) { - callback(err, results ? (results.isAdmin || results.isGlobalMod) : false); - }); - }; - - User.isAdminOrSelf = function (callerUid, uid, callback) { - if (parseInt(callerUid, 10) === parseInt(uid, 10)) { - return callback(); - } - User.isAdministrator(callerUid, function (err, isAdmin) { - if (err || !isAdmin) { - return callback(err || new Error('[[error:no-privileges]]')); - } - callback(); - }); - }; - - User.isAdminOrGlobalModOrSelf = function (callerUid, uid, callback) { - if (parseInt(callerUid, 10) === parseInt(uid, 10)) { - return callback(); - } - User.isAdminOrGlobalMod(callerUid, function (err, isAdminOrGlobalMod) { - if (err || !isAdminOrGlobalMod) { - return callback(err || new Error('[[error:no-privileges]]')); - } - callback(); - }); - }; - - User.getAdminsandGlobalMods = function (callback) { - async.parallel({ - admins: async.apply(groups.getMembers, 'administrators', 0, -1), - mods: async.apply(groups.getMembers, 'Global Moderators', 0, -1), - }, function (err, results) { - if (err) { - return callback(err); + next(null, users); + }, + ], callback); +}; + +User.getUsernameByUserslug = function (slug, callback) { + async.waterfall([ + function (next) { + User.getUidByUserslug(slug, next); + }, + function (uid, next) { + User.getUserField(uid, 'username', next); + }, + ], callback); +}; + +User.getUidByEmail = function (email, callback) { + db.sortedSetScore('email:uid', email.toLowerCase(), callback); +}; + +User.getUidsByEmails = function (emails, callback) { + emails = emails.map(function (email) { + return email && email.toLowerCase(); + }); + db.sortedSetScores('email:uid', emails, callback); +}; + +User.getUsernameByEmail = function (email, callback) { + async.waterfall([ + function (next) { + db.sortedSetScore('email:uid', email.toLowerCase(), next); + }, + function (uid, next) { + User.getUserField(uid, 'username', next); + }, + ], callback); +}; + +User.isModerator = function (uid, cid, callback) { + privileges.users.isModerator(uid, cid, callback); +}; + +User.isModeratorOfAnyCategory = function (uid, callback) { + User.getModeratedCids(uid, function (err, cids) { + callback(err, Array.isArray(cids) ? !!cids.length : false); + }); +}; + +User.isAdministrator = function (uid, callback) { + privileges.users.isAdministrator(uid, callback); +}; + +User.isGlobalModerator = function (uid, callback) { + privileges.users.isGlobalModerator(uid, callback); +}; + +User.isAdminOrGlobalMod = function (uid, callback) { + async.parallel({ + isAdmin: async.apply(User.isAdministrator, uid), + isGlobalMod: async.apply(User.isGlobalModerator, uid), + }, function (err, results) { + callback(err, results ? (results.isAdmin || results.isGlobalMod) : false); + }); +}; + +User.isAdminOrSelf = function (callerUid, uid, callback) { + isSelfOrMethod(callerUid, uid, User.isAdministrator, callback); +}; + +User.isAdminOrGlobalModOrSelf = function (callerUid, uid, callback) { + isSelfOrMethod(callerUid, uid, User.isAdminOrGlobalMod, callback); +}; + +function isSelfOrMethod(callerUid, uid, method, callback) { + if (parseInt(callerUid, 10) === parseInt(uid, 10)) { + return callback(); + } + async.waterfall([ + function (next) { + method(callerUid, next); + }, + function (isPass, next) { + if (!isPass) { + return next(new Error('[[error:no-privileges]]')); } - var uids = results.admins.concat(results.mods).filter(function (uid, index, array) { - return uid && array.indexOf(uid) === index; + next(); + }, + ], callback); +} + +User.getAdminsandGlobalMods = function (callback) { + async.waterfall([ + function (next) { + async.parallel([ + async.apply(groups.getMembers, 'administrators', 0, -1), + async.apply(groups.getMembers, 'Global Moderators', 0, -1), + ], next); + }, + function (results, next) { + User.getUsersData(_.union(results), next); + }, + ], callback); +}; + +User.getAdminsandGlobalModsandModerators = function (callback) { + async.waterfall([ + function (next) { + async.parallel([ + async.apply(groups.getMembers, 'administrators', 0, -1), + async.apply(groups.getMembers, 'Global Moderators', 0, -1), + async.apply(User.getModeratorUids), + ], next); + }, + function (results, next) { + User.getUsersData(_.union.apply(_, results), next); + }, + ], callback); +}; + +User.getModeratorUids = function (callback) { + async.waterfall([ + async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), + function (cids, next) { + var groupNames = cids.map(function (cid) { + return 'cid:' + cid + ':privileges:mods'; }); - User.getUsersData(uids, callback); - }); - }; - - User.getAdminsandGlobalModsandModerators = function (callback) { - async.parallel([ - async.apply(groups.getMembers, 'administrators', 0, -1), - async.apply(groups.getMembers, 'Global Moderators', 0, -1), - async.apply(User.getModeratorUids), - ], function (err, results) { - if (err) { - return callback(err); - } - User.getUsersData(_.union.apply(_, results), callback); - }); - }; + groups.getMembersOfGroups(groupNames, next); + }, + function (memberSets, next) { + next(null, _.union.apply(_, memberSets)); + }, + ], callback); +}; + +User.getModeratedCids = function (uid, callback) { + var cids; + async.waterfall([ + function (next) { + db.getSortedSetRange('categories:cid', 0, -1, next); + }, + function (_cids, next) { + cids = _cids; + User.isModerator(uid, cids, next); + }, + function (isMods, next) { + cids = cids.filter(function (cid, index) { + return cid && isMods[index]; + }); + next(null, cids); + }, + ], callback); +}; + +User.addInterstitials = function (callback) { + plugins.registerHook('core', { + hook: 'filter:register.interstitial', + method: function (data, callback) { + if (meta.config.termsOfUse && !data.userData.acceptTos) { + data.interstitials.push({ + template: 'partials/acceptTos', + data: { + termsOfUse: meta.config.termsOfUse, + }, + callback: function (userData, formData, next) { + if (formData['agree-terms'] === 'on') { + userData.acceptTos = true; + } - User.getModeratorUids = function (callback) { - async.waterfall([ - async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), - function (cids, next) { - var groupNames = cids.map(function (cid) { - return 'cid:' + cid + ':privileges:mods'; + next(userData.acceptTos ? null : new Error('[[register:terms_of_use_error]]')); + }, }); + } - groups.getMembersOfGroups(groupNames, function (err, memberSets) { - if (err) { - return next(err); - } - - next(null, _.union.apply(_, memberSets)); - }); - }, - ], callback); - }; - - User.getModeratedCids = function (uid, callback) { - var cids; - async.waterfall([ - function (next) { - db.getSortedSetRange('categories:cid', 0, -1, next); - }, - function (_cids, next) { - cids = _cids; - User.isModerator(uid, cids, next); - }, - function (isMods, next) { - cids = cids.filter(function (cid, index) { - return cid && isMods[index]; - }); - next(null, cids); - }, - ], callback); - }; - - User.addInterstitials = function (callback) { - plugins.registerHook('core', { - hook: 'filter:register.interstitial', - method: function (data, callback) { - if (meta.config.termsOfUse && !data.userData.acceptTos) { - data.interstitials.push({ - template: 'partials/acceptTos', - data: { - termsOfUse: meta.config.termsOfUse, - }, - callback: function (userData, formData, next) { - if (formData['agree-terms'] === 'on') { - userData.acceptTos = true; - } - - next(userData.acceptTos ? null : new Error('[[register:terms_of_use_error]]')); - }, - }); - } + callback(null, data); + }, + }); - callback(null, data); - }, - }); + callback(); +}; - callback(); - }; -}(exports)); diff --git a/src/user/admin.js b/src/user/admin.js index 7ef6c0dda7..1d6cd8c7ad 100644 --- a/src/user/admin.js +++ b/src/user/admin.js @@ -17,13 +17,7 @@ module.exports = function (User) { }; User.getIPs = function (uid, stop, callback) { - db.getSortedSetRevRange('uid:' + uid + ':ip', 0, stop, function (err, ips) { - if (err) { - return callback(err); - } - - callback(null, ips); - }); + db.getSortedSetRevRange('uid:' + uid + ':ip', 0, stop, callback); }; User.getUsersCSV = function (callback) { diff --git a/src/user/data.js b/src/user/data.js index 443de8e7aa..120da7e3a2 100644 --- a/src/user/data.js +++ b/src/user/data.js @@ -1,5 +1,6 @@ 'use strict'; +var async = require('async'); var validator = require('validator'); var nconf = require('nconf'); var winston = require('winston'); @@ -54,13 +55,14 @@ module.exports = function (User) { addField('lastonline'); } - db.getObjectsFields(keys, fields, function (err, users) { - if (err) { - return callback(err); - } - - modifyUserData(users, fieldsToRemove, callback); - }); + async.waterfall([ + function (next) { + db.getObjectsFields(keys, fields, next); + }, + function (users, next) { + modifyUserData(users, fieldsToRemove, next); + }, + ], callback); }; User.getMultipleUserFields = function (uids, fields, callback) { @@ -83,13 +85,14 @@ module.exports = function (User) { return 'user:' + uid; }); - db.getObjects(keys, function (err, users) { - if (err) { - return callback(err); - } - - modifyUserData(users, [], callback); - }); + async.waterfall([ + function (next) { + db.getObjects(keys, next); + }, + function (users, next) { + modifyUserData(users, [], next); + }, + ], callback); }; function modifyUserData(users, fieldsToRemove, callback) { @@ -152,51 +155,53 @@ module.exports = function (User) { User.setUserField = function (uid, field, value, callback) { callback = callback || function () {}; - db.setObjectField('user:' + uid, field, value, function (err) { - if (err) { - return callback(err); - } - plugins.fireHook('action:user.set', { uid: uid, field: field, value: value, type: 'set' }); - callback(); - }); + async.waterfall([ + function (next) { + db.setObjectField('user:' + uid, field, value, next); + }, + function (next) { + plugins.fireHook('action:user.set', { uid: uid, field: field, value: value, type: 'set' }); + next(); + }, + ], callback); }; User.setUserFields = function (uid, data, callback) { callback = callback || function () {}; - db.setObject('user:' + uid, data, function (err) { - if (err) { - return callback(err); - } - for (var field in data) { - if (data.hasOwnProperty(field)) { - plugins.fireHook('action:user.set', { uid: uid, field: field, value: data[field], type: 'set' }); + async.waterfall([ + function (next) { + db.setObject('user:' + uid, data, next); + }, + function (next) { + for (var field in data) { + if (data.hasOwnProperty(field)) { + plugins.fireHook('action:user.set', { uid: uid, field: field, value: data[field], type: 'set' }); + } } - } - callback(); - }); + next(); + }, + ], callback); }; User.incrementUserFieldBy = function (uid, field, value, callback) { - callback = callback || function () {}; - db.incrObjectFieldBy('user:' + uid, field, value, function (err, value) { - if (err) { - return callback(err); - } - plugins.fireHook('action:user.set', { uid: uid, field: field, value: value, type: 'increment' }); - - callback(null, value); - }); + incrDecrUserFieldBy(uid, field, value, 'increment', callback); }; User.decrementUserFieldBy = function (uid, field, value, callback) { - callback = callback || function () {}; - db.incrObjectFieldBy('user:' + uid, field, -value, function (err, value) { - if (err) { - return callback(err); - } - plugins.fireHook('action:user.set', { uid: uid, field: field, value: value, type: 'decrement' }); - - callback(null, value); - }); + incrDecrUserFieldBy(uid, field, -value, 'decrement', callback); }; + + function incrDecrUserFieldBy(uid, field, value, type, callback) { + callback = callback || function () {}; + async.waterfall([ + function (next) { + db.incrObjectFieldBy('user:' + uid, field, value, next); + }, + function (value, next) { + plugins.fireHook('action:user.set', { uid: uid, field: field, value: value, type: type }); + + next(null, value); + }, + ], callback); + } }; diff --git a/src/user/online.js b/src/user/online.js new file mode 100644 index 0000000000..6cb19cd22f --- /dev/null +++ b/src/user/online.js @@ -0,0 +1,70 @@ +'use strict'; + +var async = require('async'); + +var db = require('../database'); +var topics = require('../topics'); +var plugins = require('../plugins'); + +module.exports = function (User) { + User.updateLastOnlineTime = function (uid, callback) { + callback = callback || function () {}; + db.getObjectFields('user:' + uid, ['status', 'lastonline'], function (err, userData) { + var now = Date.now(); + if (err || userData.status === 'offline' || now - parseInt(userData.lastonline, 10) < 300000) { + return callback(err); + } + User.setUserField(uid, 'lastonline', now, callback); + }); + }; + + User.updateOnlineUsers = function (uid, callback) { + callback = callback || function () {}; + + var now = Date.now(); + async.waterfall([ + function (next) { + db.sortedSetScore('users:online', uid, next); + }, + function (userOnlineTime, next) { + if (now - parseInt(userOnlineTime, 10) < 300000) { + return callback(); + } + db.sortedSetAdd('users:online', now, uid, next); + }, + function (next) { + topics.pushUnreadCount(uid); + plugins.fireHook('action:user.online', { uid: uid, timestamp: now }); + next(); + }, + ], callback); + }; + + User.isOnline = function (uid, callback) { + var now = Date.now(); + async.waterfall([ + function (next) { + if (Array.isArray(uid)) { + db.sortedSetScores('users:online', uid, next); + } else { + db.sortedSetScore('users:online', uid, next); + } + }, + function (lastonline, next) { + function checkOnline(lastonline) { + return now - lastonline < 300000; + } + + var isOnline; + if (Array.isArray(uid)) { + isOnline = uid.map(function (uid, index) { + return checkOnline(lastonline[index]); + }); + } else { + isOnline = checkOnline(lastonline); + } + next(null, isOnline); + }, + ], callback); + }; +};