From 3d68c7c6b645f80c2bd74c0c09af4234653b4fc5 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 11 Mar 2014 03:39:41 -0400 Subject: [PATCH 1/4] added getObjectsFields methods to db class, changed getUsers methods to use the new method, refactor to user.js and mongo.js --- public/src/forum/users.js | 2 +- src/controllers/accounts.js | 16 ++- src/controllers/topics.js | 2 +- src/database/mongo.js | 163 ++++++++++++------------ src/database/redis.js | 36 ++++-- src/routes/debug.js | 4 + src/socket.io/posts.js | 8 +- src/user.js | 248 ++++++++++++++++-------------------- 8 files changed, 238 insertions(+), 241 deletions(-) diff --git a/public/src/forum/users.js b/public/src/forum/users.js index 4106ebde34..f10c739918 100644 --- a/public/src/forum/users.js +++ b/public/src/forum/users.js @@ -111,7 +111,7 @@ define(function() { function onUsersLoaded(users, emptyContainer) { templates.preload_template('users', function() { - templates['useres'].parse({users:[]}); + templates['users'].parse({users:[]}); var html = templates.prepare(templates['users'].blocks['users']).parse({ users: users }); diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 80bf88baa9..ad12fb64e2 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -130,7 +130,11 @@ accountsController.getAccount = function(req, res, next) { }); } - user.isFollowing(callerUID, userData.theirid, function (isFollowing) { + user.isFollowing(callerUID, userData.theirid, function (err, isFollowing) { + if(err) { + return next(err); + } + posts.getPostsByUid(callerUID, userData.theirid, 0, 9, function (err, userPosts) { if(err) { return next(err); @@ -175,7 +179,7 @@ accountsController.getFollowing = function(req, res, next) { } userData.following = followingData; userData.followingCount = followingData.length; - + res.render('following', userData); }); @@ -200,7 +204,7 @@ accountsController.getFollowers = function(req, res, next) { } userData.followers = followersData; userData.followersCount = followersData.length; - + res.render('followers', userData); }); } else { @@ -286,7 +290,7 @@ accountsController.accountEdit = function(req, res, next) { if(err) { return next(err); } - + res.render('accountedit', userData); }); }; @@ -323,12 +327,12 @@ accountsController.accountSettings = function(req, res, next) { userData.yourid = req.user.uid; userData.theirid = uid; userData.settings = settings; - + res.render('accountsettings', userData); }); }); - }); + }); }; accountsController.uploadPicture = function (req, res, next) { diff --git a/src/controllers/topics.js b/src/controllers/topics.js index b6fe70caac..8edf274e15 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -47,8 +47,8 @@ topicsController.get = function(req, res, next) { if (parseInt(topicData.deleted, 10) === 1 && parseInt(topicData.expose_tools, 10) === 0) { return next(new Error('Topic deleted'), null); } + topicData.currentPage = page; } - topicData.currentPage = page; next(err, topicData); }); }); diff --git a/src/database/mongo.js b/src/database/mongo.js index 78b3914cc2..92a80cebf7 100644 --- a/src/database/mongo.js +++ b/src/database/mongo.js @@ -100,6 +100,26 @@ return null; } + function fieldToString(field) { + if(field === null || field === undefined) { + return field; + } + + if(typeof field !== 'string') { + field = field.toString(); + } + // if there is a '.' in the field name it inserts subdocument in mongo, replace '.'s with \uff0E + field = field.replace(/\./g, '\uff0E'); + return field; + } + + function toString(value) { + if(value === null || value === undefined) { + return value; + } + + return value.toString(); + } // // Exported functions @@ -235,11 +255,7 @@ module.setObjectField = function(key, field, value, callback) { var data = {}; - if(typeof field !== 'string') { - field = field.toString(); - } - // if there is a '.' in the field name it inserts subdocument in mongo, replace '.'s with \uff0E - field = field.replace(/\./g, '\uff0E'); + field = fieldToString(field); data[field] = value; db.collection('objects').update({_key:key}, {$set:data}, {upsert:true, w: 1}, function(err, result) { if(typeof callback === 'function') { @@ -271,51 +287,69 @@ }; module.getObjectField = function(key, field, callback) { - if(typeof field !== 'string') { - field = field.toString(); - } - field = field.replace(/\./g, '\uff0E'); + field = fieldToString(field); module.getObjectFields(key, [field], function(err, data) { if(err) { return callback(err); } - callback(null, data[field]); + callback(null, data ? data[field] : null); }); }; module.getObjectFields = function(key, fields, callback) { + module.getObjectsFields([key], fields, function(err, items) { + callback(err, items ? items[0] : null); + }); + }; + + module.getObjectsFields = function(keys, fields, callback) { var _fields = { - _id: 0 + _id: 0, + _key: 1 }; - for(var i=0; i 0 + finalText = usernames.join(', ') + (rest_amount > 0 ? " and " + rest_amount + (rest_amount > 1 ? " others" : " other") : ""); - callback(null, usernames); + callback(null, finalText); }); }); }; diff --git a/src/user.js b/src/user.js index 4edf9a77cf..0bb7bbbaac 100644 --- a/src/user.js +++ b/src/user.js @@ -168,32 +168,51 @@ var bcrypt = require('bcryptjs'), }; User.getMultipleUserFields = function(uids, fields, callback) { - if (uids.length === 0) { + + if (!Array.isArray(uids) || !uids.length) { return callback(null, []); } - function getFields(uid, next) { - User.getUserFields(uid, fields, next); - } + var keys = uids.map(function(uid) { + return 'user:' + uid; + }); - async.map(uids, getFields, callback); + db.getObjectsFields(keys, fields, callback); }; User.getUserData = function(uid, callback) { - db.getObject('user:' + uid, function(err, data) { - if(err) { + User.getUsersData([uid], function(err, users) { + callback(err, users ? users[0] : null); + }); + }; + + User.getUsersData = function(uids, callback) { + + if (!Array.isArray(uids) || !uids.length) { + return callback(null, []); + } + + var keys = uids.map(function(uid) { + return 'user:' + uid; + }); + + db.getObjects(keys, function(err, users) { + if (err) { return callback(err); } - if (data) { - if (data.password) { - data.password = null; - data.hasPassword = true; - } else { - data.hasPassword = false; + users.forEach(function(user) { + if (user) { + if (user.password) { + user.password = null; + user.hasPassword = true; + } else { + user.hasPassword = false; + } } - } - callback(err, data); + }); + + callback(null, users); }); }; @@ -508,36 +527,48 @@ var bcrypt = require('bcryptjs'), db.getSortedSetRevRange(set, start, stop, function(err, uids) { if (err) { - return callback(err, null); + return callback(err); } - function getUserData(uid, callback) { - User.getUserData(uid, function(err, userData) { - if(!userData.status) { - userData.status = 'online'; + User.getUsersData(uids, function(err, users) { + if (err) { + return callback(err); + } + + async.map(users, function(user, next) { + if (!user) { + return next(null, user); } - User.isAdministrator(uid, function(err, isAdmin) { - if (userData) { - userData.administrator = isAdmin ? '1':'0'; + if (!user.status) { + user.status = 'online'; + } + + User.isAdministrator(user.uid, function(err, isAdmin) { + if (err) { + return next(err); } + user.administrator = isAdmin ? '1':'0'; + if(set === 'users:online') { - return callback(null, userData); + return next(null, user); } - db.sortedSetScore('users:online', uid, function(err, score) { + db.sortedSetScore('users:online', user.uid, function(err, score) { + if (err) { + return next(err); + } + if(!score) { - userData.status = 'offline'; + user.status = 'offline'; } - callback(null, userData); + next(null, user); }); }); - }); - } - - async.map(uids, getUserData, callback); + }, callback); + }); }); }; @@ -568,24 +599,25 @@ var bcrypt = require('bcryptjs'), }; User.getUsersCSV = function(callback) { - var csvContent = ""; + var csvContent = ''; db.getObjectValues('username:uid', function(err, uids) { - if(err) { + if (err) { return callback(err); } - async.each(uids, function(uid, next) { - User.getUserFields(uid, ['email', 'username'], function(err, userData) { - if(err) { - return next(err); - } + User.getMultipleUserFields(uids, ['email', 'username'], function(err, usersData) { + if (err) { + return callback(err); + } - csvContent += userData.email + ',' + userData.username + ',' + uid + '\n'; - next(); + usersData.forEach(function(user, index) { + if (user) { + csvContent += user.email + ',' + user.username + ',' + uids[index] + '\n'; + } }); - }, function(err) { - callback(err, csvContent); + + callback(null, csvContent); }); }); }; @@ -604,9 +636,9 @@ var bcrypt = require('bcryptjs'), query = query.toLowerCase(); var usernames = Object.keys(usernamesHash), - results = []; + uids = []; - results = usernames.filter(function(username) { + uids = usernames.filter(function(username) { return username.toLowerCase().indexOf(query) === 0; }) .slice(0, 10) @@ -617,7 +649,10 @@ var bcrypt = require('bcryptjs'), return usernamesHash[username]; }); - User.getDataForUsers(results, function(err, userdata) { + User.getUsersData(uids, function(err, userdata) { + if (err) { + return callback(err); + } var diff = process.hrtime(start); var timing = (diff[0] * 1e3 + diff[1] / 1e6).toFixed(1); callback(null, {timing: timing, users: userdata}); @@ -657,70 +692,48 @@ var bcrypt = require('bcryptjs'), }); }; - User.follow = function(uid, followid, callback) { - db.setAdd('following:' + uid, followid, function(err, data) { - if(err) { - return callback(err); - } + User.follow = function(uid, followuid, callback) { + toggleFollow('follow', uid, followuid, callback); + }; - db.setAdd('followers:' + followid, uid, callback); - }); + User.unfollow = function(uid, unfollowuid, callback) { + toggleFollow('unfollow', uid, unfollowuid, callback); }; - User.unfollow = function(uid, unfollowid, callback) { - db.setRemove('following:' + uid, unfollowid, function(err, data) { + function toggleFollow(type, uid, theiruid, callback) { + var command = type === 'follow' ? 'setAdd' : 'setRemove'; + db[command]('following:' + uid, theiruid, function(err) { if(err) { return callback(err); } - - db.setRemove('followers:' + unfollowid, uid, callback); + db[command]('followers:' + theiruid, uid, callback); }); - }; + } User.getFollowing = function(uid, callback) { - db.getSetMembers('following:' + uid, function(err, userIds) { - if(err) { - return callback(err); - } - - User.getDataForUsers(userIds, callback); - }); + getFollow('following:' + uid, callback); }; User.getFollowers = function(uid, callback) { - db.getSetMembers('followers:' + uid, function(err, userIds) { + getFollow('followers:' + uid, callback); + }; + + function getFollow(set, callback) { + db.getSetMembers(set, function(err, uids) { if(err) { return callback(err); } - User.getDataForUsers(userIds, callback); + User.getUsersData(uids, callback); }); - }; + } User.getFollowingCount = function(uid, callback) { - db.getSetMembers('following:' + uid, function(err, userIds) { - if (err) { - return callback(err); - } - - userIds = userIds.filter(function(value) { - return parseInt(value, 10) !== 0; - }); - callback(null, userIds.length); - }); + db.setCount('following:' + uid, callback); }; User.getFollowerCount = function(uid, callback) { - db.getSetMembers('followers:' + uid, function(err, userIds) { - if(err) { - return callback(err); - } - - userIds = userIds.filter(function(value) { - return parseInt(value, 10) !== 0; - }); - callback(null, userIds.length); - }); + db.setCount('followers:' + uid, callback); }; User.getFollowStats = function (uid, callback) { @@ -734,22 +747,6 @@ var bcrypt = require('bcryptjs'), }, callback); }; - User.getDataForUsers = function(uids, callback) { - - if (!uids || !Array.isArray(uids) || uids.length === 0) { - return callback(null, []); - } - - function getUserData(uid, next) { - if(parseInt(uid, 10) === 0) { - return next(null, null); - } - - User.getUserData(uid, next); - } - - async.map(uids, getUserData, callback); - }; User.sendPostNotificationToFollowers = function(uid, tid, pid) { User.getUserField(uid, 'username', function(err, username) { @@ -773,13 +770,7 @@ var bcrypt = require('bcryptjs'), }; User.isFollowing = function(uid, theirid, callback) { - db.isSetMember('following:' + uid, theirid, function(err, isMember) { - if (!err) { - callback(isMember); - } else { - console.log(err); - } - }); + db.isSetMember('following:' + uid, theirid, callback); }; User.exists = function(userslug, callback) { @@ -809,29 +800,17 @@ var bcrypt = require('bcryptjs'), }; User.getUsernamesByUids = function(uids, callback) { + User.getMultipleUserFields(uids, ['username'], function(err, users) { + if (err) { + return callback(err); + } - if (!Array.isArray(uids)) { - return callback(null, []); - } - - function getUserName(uid, next) { - User.getUserField(uid, 'username', next); - } - - async.map(uids, getUserName, callback); - }; - - User.getUserSlugsByUids = function(uids, callback) { - - if (!Array.isArray(uids)) { - return callback(null, []); - } - - function getUserSlug(uid, next) { - User.getUserField(uid, 'userslug', next); - } + users = users.map(function(user) { + return user.username; + }); - async.map(uids, getUserSlug, callback); + callback(null, users); + }); }; User.getUsernameByUserslug = function(slug, callback) { @@ -846,12 +825,7 @@ var bcrypt = require('bcryptjs'), }; User.getUidByEmail = function(email, callback) { - db.getObjectField('email:uid', email, function(err, data) { - if (err) { - return callback(err); - } - callback(null, data); - }); + db.getObjectField('email:uid', email, callback); }; User.isModerator = function(uid, cid, callback) { From 9564b6fda2064350891e71722811b2823c23e0e4 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 11 Mar 2014 04:10:00 -0400 Subject: [PATCH 2/4] closes #1165 --- src/controllers/index.js | 7 ++++++- src/middleware/middleware.js | 13 ++++++++++++- src/routes/index.js | 8 ++++---- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/controllers/index.js b/src/controllers/index.js index e43d08a9c1..3e94107268 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -183,6 +183,11 @@ Controllers.login = function(req, res, next) { }; Controllers.register = function(req, res, next) { + + if (req.user) { + res.redirect('/'); + } + var data = {}, login_strategies = auth.get_login_strategies(), num_strategies = login_strategies.length; @@ -206,7 +211,7 @@ Controllers.register = function(req, res, next) { data.maximumUsernameLength = meta.config.maximumUsernameLength; data.minimumPasswordLength = meta.config.minimumPasswordLength; data.termsOfUse = meta.config.termsOfUse; - + res.render('register', data); }; diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 2992d87fc7..c964533b33 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -22,7 +22,7 @@ var app, middleware.authenticate = function(req, res, next) { if(!req.user) { if (res.locals.isAPI) { - return res.json(403, 'not-allowed'); + return res.json(403, 'not-allowed'); } else { return res.redirect('403'); } @@ -41,6 +41,17 @@ middleware.updateLastOnlineTime = function(req, res, next) { next(); }; +middleware.redirectToAccountIfLoggedIn = function(req, res, next) { + if (req.user) { + user.getUserField(req.user.uid, 'userslug', function (err, userslug) { + res.redirect('/user/' + userslug); + }); + } else { + next(); + } + +} + middleware.prepareAPI = function(req, res, next) { res.locals.isAPI = true; next(); diff --git a/src/routes/index.js b/src/routes/index.js index 72bc3cbfa5..c54053d4f5 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -28,11 +28,11 @@ module.exports = function(app, middleware) { app.get('/', middleware.buildHeader, controllers.home); app.get('/api/home', controllers.home); - app.get('/login', middleware.buildHeader, controllers.login); - app.get('/api/login', controllers.login); + app.get('/login', middleware.redirectToAccountIfLoggedIn, middleware.buildHeader, controllers.login); + app.get('/api/login', middleware.redirectToAccountIfLoggedIn, controllers.login); - app.get('/register', middleware.buildHeader, controllers.register); - app.get('/api/register', controllers.register); + app.get('/register', middleware.redirectToAccountIfLoggedIn, middleware.buildHeader, controllers.register); + app.get('/api/register', middleware.redirectToAccountIfLoggedIn, controllers.register); app.get('/confirm/:code', middleware.buildHeader, controllers.confirmEmail); app.get('/api/confirm/:code', controllers.confirmEmail); From 037e8943a859ce534a1a9f139eb8b67534ab0b89 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 11 Mar 2014 04:10:39 -0400 Subject: [PATCH 3/4] removed left over --- src/controllers/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/controllers/index.js b/src/controllers/index.js index 3e94107268..7caec05855 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -184,10 +184,6 @@ Controllers.login = function(req, res, next) { Controllers.register = function(req, res, next) { - if (req.user) { - res.redirect('/'); - } - var data = {}, login_strategies = auth.get_login_strategies(), num_strategies = login_strategies.length; From 88c4b90fc893c445db8dfa6e9ca6df851b53cf88 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 11 Mar 2014 04:33:08 -0400 Subject: [PATCH 4/4] accounts controller removed duplication --- src/controllers/accounts.js | 60 ++++++++++++++----------------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index ad12fb64e2..71e28308cf 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -165,53 +165,39 @@ accountsController.getAccount = function(req, res, next) { }; accountsController.getFollowing = function(req, res, next) { - var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; - - getUserDataByUserSlug(req.params.userslug, callerUID, function (err, userData) { - if(err) { - return next(err); - } - - if (userData) { - user.getFollowing(userData.uid, function (err, followingData) { - if(err) { - return next(err); - } - userData.following = followingData; - userData.followingCount = followingData.length; - - res.render('following', userData); - }); - - } else { - return userNotFound(); - } - }); + getFollow('following', req, res, next); }; accountsController.getFollowers = function(req, res, next) { + getFollow('followers', req, res, next); +}; + +function getFollow(name, req, res, next) { var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; + var userData; - getUserDataByUserSlug(req.params.userslug, callerUID, function (err, userData) { + async.waterfall([ + function(next) { + getUserDataByUserSlug(req.params.userslug, callerUID, next); + }, + function(data, next) { + userData = data; + if (!userData) { + return userNotFound(); + } + var method = name === 'following' ? 'getFollowing' : 'getFollowers'; + user[method](userData.uid, next); + } + ], function(err, users) { if(err) { return next(err); } + userData[name] = users; + userData[name + 'Count'] = users.length; - if (userData) { - user.getFollowers(userData.uid, function (err, followersData) { - if(err) { - return next(err); - } - userData.followers = followersData; - userData.followersCount = followersData.length; - - res.render('followers', userData); - }); - } else { - return userNotFound(); - } + res.render(name, userData); }); -}; +} accountsController.getFavourites = function(req, res, next) { var callerUID = req.user ? parseInt(req.user.uid, 10) : 0;