diff --git a/public/css/style.less b/public/css/style.less
index 5a44a064b0..10d22efd58 100644
--- a/public/css/style.less
+++ b/public/css/style.less
@@ -392,7 +392,7 @@ body .navbar .nodebb-inline-block {
#admin-redis-info {
span {
display:inline-block;
- width:200px;
+ width:220px;
}
}
diff --git a/public/src/forum/admin/users.js b/public/src/forum/admin/users.js
index 37204dfbec..436ff79a40 100644
--- a/public/src/forum/admin/users.js
+++ b/public/src/forum/admin/users.js
@@ -79,8 +79,9 @@
jQuery('document').ready(function() {
- var yourid = templates.get('yourid');
- var timeoutId = 0;
+ var yourid = templates.get('yourid'),
+ timeoutId = 0,
+ loadingMoreUsers = false;
var url = window.location.href,
parts = url.split('/'),
@@ -114,8 +115,7 @@
socket.removeAllListeners('api:admin.user.search');
socket.on('api:admin.user.search', function(data) {
-
- var html = templates.prepare(templates['admin/users'].blocks['users']).parse({
+ var html = templates.prepare(templates['admin/users'].blocks['users']).parse({
users: data
}),
userListEl = document.querySelector('.users');
@@ -139,6 +139,47 @@
initUsers();
});
+ function onUsersLoaded(users) {
+ var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ users: users }),
+ container = $('#users-container');
+
+ container.append(html);
+ }
+
+ function loadMoreUsers() {
+ var set = '';
+ if(active === 'latest') {
+ set = 'users:joindate';
+ } else if(active === 'sort-posts') {
+ set = 'users:postcount';
+ } else if(active === 'sort-reputation') {
+ set = 'users:reputation';
+ }
+
+ if(set) {
+ loadingMoreUsers = true;
+ socket.emit('api:users.loadMore', {
+ set: set,
+ after: $('#users-container').children().length
+ }, function(data) {
+ if(data.users.length) {
+ onUsersLoaded(data.users);
+ }
+ loadingMoreUsers = false;
+ });
+ }
+ }
+
+ $('#load-more-users-btn').on('click', loadMoreUsers);
+
+ $(window).off('scroll').on('scroll', function() {
+ var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
+
+ if (document.body.scrollTop > bottom && !loadingMoreUsers) {
+ loadMoreUsers();
+ }
+ });
+
});
-
+
}());
\ No newline at end of file
diff --git a/public/src/forum/category.js b/public/src/forum/category.js
index 5720988f74..4c94174488 100644
--- a/public/src/forum/category.js
+++ b/public/src/forum/category.js
@@ -122,10 +122,9 @@
}
$(window).off('scroll').on('scroll', function(ev) {
- var windowHeight = document.body.offsetHeight - $(window).height(),
- half = windowHeight / 2;
+ var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
- if (document.body.scrollTop > half && !loadingMoreTopics) {
+ if (document.body.scrollTop > bottom && !loadingMoreTopics) {
loadMoreTopics(cid);
}
});
diff --git a/public/src/forum/recent.js b/public/src/forum/recent.js
index 44a078a278..1a81ac54fd 100644
--- a/public/src/forum/recent.js
+++ b/public/src/forum/recent.js
@@ -69,10 +69,9 @@
}
$(window).off('scroll').on('scroll', function() {
- var windowHeight = document.body.offsetHeight - $(window).height(),
- half = windowHeight / 2;
+ var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
- if (document.body.scrollTop > half && !loadingMoreTopics) {
+ if (document.body.scrollTop > bottom && !loadingMoreTopics) {
loadMoreTopics();
}
});
diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js
index 2b04f4a2d3..b99a10862d 100644
--- a/public/src/forum/topic.js
+++ b/public/src/forum/topic.js
@@ -202,10 +202,9 @@
// Infinite scrolling of posts
$(window).off('scroll').on('scroll', function() {
- var windowHeight = document.body.offsetHeight - $(window).height(),
- half = windowHeight / 2;
+ var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
- if (document.body.scrollTop > half && !app.infiniteLoaderActive && $('#post-container').children().length) {
+ if (document.body.scrollTop > bottom && !app.infiniteLoaderActive && $('#post-container').children().length) {
app.loadMorePosts(tid);
}
});
diff --git a/public/src/forum/unread.js b/public/src/forum/unread.js
index 8b2342df36..1515ba8966 100644
--- a/public/src/forum/unread.js
+++ b/public/src/forum/unread.js
@@ -84,10 +84,9 @@
}
$(window).off('scroll').on('scroll', function() {
- var windowHeight = document.body.offsetHeight - $(window).height(),
- half = windowHeight / 2;
-
- if (document.body.scrollTop > half && !loadingMoreTopics) {
+ var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
+
+ if (document.body.scrollTop > bottom && !loadingMoreTopics) {
loadMoreTopics();
}
});
diff --git a/public/src/forum/users.js b/public/src/forum/users.js
index 8a56698e5d..6f77d4e5f3 100644
--- a/public/src/forum/users.js
+++ b/public/src/forum/users.js
@@ -2,6 +2,7 @@
$(document).ready(function() {
var timeoutId = 0;
+ var loadingMoreUsers = false;
var url = window.location.href,
parts = url.split('/'),
@@ -74,6 +75,46 @@
$(element).html(app.addCommas($(element).html()));
});
+ function onUsersLoaded(users) {
+ var html = templates.prepare(templates['users'].blocks['users']).parse({ users: users }),
+ container = $('#users-container');
+
+ container.append(html);
+ }
+
+ function loadMoreUsers() {
+ var set = '';
+ if(active === 'users-latest' || active === 'users') {
+ set = 'users:joindate';
+ } else if(active === 'users-sort-posts') {
+ set = 'users:postcount';
+ } else if(active === 'users-sort-reputation') {
+ set = 'users:reputation';
+ }
+
+ if(set) {
+ loadingMoreUsers = true;
+ socket.emit('api:users.loadMore', {
+ set: set,
+ after: $('#users-container').children().length
+ }, function(data) {
+ if(data.users.length) {
+ onUsersLoaded(data.users);
+ }
+ loadingMoreUsers = false;
+ });
+ }
+ }
+
+ $('#load-more-users-btn').on('click', loadMoreUsers);
+
+ $(window).off('scroll').on('scroll', function() {
+ var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
+
+ if (document.body.scrollTop > bottom && !loadingMoreUsers) {
+ loadMoreUsers();
+ }
+ });
});
}());
\ No newline at end of file
diff --git a/public/templates/admin/redis.tpl b/public/templates/admin/redis.tpl
index e52f021e02..aa127ef893 100644
--- a/public/templates/admin/redis.tpl
+++ b/public/templates/admin/redis.tpl
@@ -16,6 +16,7 @@
Total Connections Received {total_connections_received}
Total Commands Processed {total_commands_processed}
+ Instantaneous Ops. Per Second {instantaneous_ops_per_sec}
Keyspace Hits {keyspace_hits}
Keyspace Misses {keyspace_misses}
diff --git a/public/templates/admin/users.tpl b/public/templates/admin/users.tpl
index 83fb14d73a..17fa914b12 100644
--- a/public/templates/admin/users.tpl
+++ b/public/templates/admin/users.tpl
@@ -14,7 +14,7 @@
User not found!
-
+
-
+
+
+
+
+
\ No newline at end of file
diff --git a/src/favourites.js b/src/favourites.js
index c2cf33b391..289e7b8fd6 100644
--- a/src/favourites.js
+++ b/src/favourites.js
@@ -28,8 +28,11 @@ var RDB = require('./redis.js'),
RDB.sadd('pid:' + pid + ':users_favourited', uid);
RDB.hincrby('post:' + pid, 'reputation', 1);
- if (uid !== uid_of_poster)
- user.incrementUserFieldBy(uid_of_poster, 'reputation', 1);
+ if (uid !== uid_of_poster) {
+ user.incrementUserFieldBy(uid_of_poster, 'reputation', 1, function(err, newreputation) {
+ RDB.zadd('users:reputation', newreputation, uid_of_poster);
+ });
+ }
if (room_id) {
io.sockets.in(room_id).emit('event:rep_up', {uid: uid !== uid_of_poster ? uid_of_poster : 0, pid: pid});
@@ -63,8 +66,11 @@ var RDB = require('./redis.js'),
RDB.srem('pid:' + pid + ':users_favourited', uid);
RDB.hincrby('post:' + pid, 'reputation', -1);
- if (uid !== uid_of_poster)
- user.incrementUserFieldBy(uid_of_poster, 'reputation', -1);
+ if (uid !== uid_of_poster) {
+ user.incrementUserFieldBy(uid_of_poster, 'reputation', -1, function(err, newreputation) {
+ RDB.zadd('users:reputation', newreputation, uid_of_poster);
+ });
+ }
if (room_id) {
io.sockets.in(room_id).emit('event:rep_down', {uid: uid !== uid_of_poster ? uid_of_poster : 0, pid: pid});
diff --git a/src/postTools.js b/src/postTools.js
index 1340fd7438..3c22fabd61 100644
--- a/src/postTools.js
+++ b/src/postTools.js
@@ -99,7 +99,9 @@ var RDB = require('./redis.js'),
posts.getPostFields(pid, ['tid', 'uid'], function(postData) {
- user.decrementUserFieldBy(postData.uid, 'postcount', 1);
+ user.decrementUserFieldBy(postData.uid, 'postcount', 1, function(err, postcount) {
+ RDB.zadd('users:postcount', postcount, postData.uid);
+ });
io.sockets.in('topic_' + postData.tid).emit('event:post_deleted', {
pid: pid
diff --git a/src/routes/admin.js b/src/routes/admin.js
index 75afd05c66..57efba77af 100644
--- a/src/routes/admin.js
+++ b/src/routes/admin.js
@@ -64,39 +64,30 @@ var user = require('./../user.js'),
});
app.get('/api/admin/users/search', function(req, res) {
- res.json({search_display: 'block', users: []});
+ res.json({search_display: 'block', loadmore_display:'none', users: []});
});
app.get('/api/admin/users/latest', function(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.joindate - a.joindate;
- });
- res.json({search_display: 'none', users:data, yourid:req.user.uid});
+ user.getUsers('users:joindate', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data, yourid:req.user.uid });
});
});
app.get('/api/admin/users/sort-posts', function(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.postcount - a.postcount;
- });
- res.json({search_display: 'none', users:data, yourid:req.user.uid});
+ user.getUsers('users:postcount', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data, yourid:req.user.uid });
});
});
app.get('/api/admin/users/sort-reputation', function(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.reputation - a.reputation;
- });
- res.json({search_display: 'none', users:data, yourid:req.user.uid});
+ user.getUsers('users:reputation', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data, yourid:req.user.uid });
});
});
app.get('/api/admin/users', function(req, res) {
- user.getUserList(function(data) {
- res.json({search_display: 'none', users:data, yourid:req.user.uid});
+ user.getUsers('users:joindate', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', users:data, yourid:req.user.uid });
});
});
@@ -139,7 +130,10 @@ var user = require('./../user.js'),
for(var i in data) {
- try {
+ if(data[i].indexOf(':') == -1 || !data[i])
+ continue;
+
+ try {
data[i] = data[i].replace(/:/,"\":\"");
var json = "{\"" + data[i] + "\"}";
@@ -148,7 +142,7 @@ var user = require('./../user.js'),
finalData[key] = jsonObject[key];
}
} catch(err){
- console.log(err);
+ console.log('invalid redis status', i, data[i], err);
}
}
diff --git a/src/routes/user.js b/src/routes/user.js
index 76d7e7586f..3a1b153c57 100644
--- a/src/routes/user.js
+++ b/src/routes/user.js
@@ -316,49 +316,33 @@ var user = require('./../user.js'),
});
});
- app.get('/api/users', function(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.joindate - a.joindate;
- });
- res.json({ search_display: 'none', users: data });
- });
- });
-
+ app.get('/api/users', getUsersSortedByJoinDate);
app.get('/api/users-sort-posts', getUsersSortedByPosts);
app.get('/api/users-sort-reputation', getUsersSortedByReputation);
app.get('/api/users-latest', getUsersSortedByJoinDate);
app.get('/api/users-search', getUsersForSearch);
- function getUsersSortedByPosts(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.postcount - a.postcount;
- });
- res.json({ search_display: 'none', users:data });
+
+ function getUsersSortedByJoinDate(req, res) {
+ user.getUsers('users:joindate', 0, 49, function(err, data) {
+ res.json({ search_display: 'none',loadmore_display:'block', users:data });
});
}
-
- function getUsersSortedByReputation(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.reputation - a.reputation;
- });
- res.json({ search_display: 'none', users:data });
+
+ function getUsersSortedByPosts(req, res) {
+ user.getUsers('users:postcount', 0, 49, function(err, data) {
+ res.json({ search_display: 'none',loadmore_display:'block', users:data });
});
}
- function getUsersSortedByJoinDate(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.joindate - a.joindate;
- });
- res.json({ search_display: 'none', users:data });
+ function getUsersSortedByReputation(req, res) {
+ user.getUsers('users:reputation', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data });
});
}
function getUsersForSearch(req, res) {
- res.json({ search_display: 'block', users: [] });
+ res.json({ search_display: 'block', loadmore_display:'none', users: [] });
}
function getUserDataByUserSlug(userslug, callerUID, callback) {
diff --git a/src/upgrade.js b/src/upgrade.js
index 7bf8b1abc5..a6285af162 100644
--- a/src/upgrade.js
+++ b/src/upgrade.js
@@ -36,6 +36,19 @@ function upgradeCategory(cid, callback) {
});
}
+function upgradeUser(uid, callback) {
+ RDB.hmgetObject('user:' + uid, ['joindate', 'postcount', 'reputation'], function(err, userData) {
+ if(err)
+ return callback(err);
+
+ RDB.zadd('users:joindate', userData.joindate, uid);
+ RDB.zadd('users:postcount', userData.postcount, uid);
+ RDB.zadd('users:reputation', userData.reputation, uid);
+
+ callback(null);
+ });
+
+}
exports.upgrade = function() {
@@ -58,7 +71,17 @@ exports.upgrade = function() {
function upgradeUsers(next) {
console.log('upgrading users');
- next(null, 'upgraded users');
+
+ RDB.lrange('userlist', 0, -1, function(err, uids) {
+
+ async.each(uids, upgradeUser, function(err) {
+ if(!err)
+ next(null, 'upgraded users');
+ else
+ next(err, null);
+ });
+
+ });
}
];
diff --git a/src/user.js b/src/user.js
index 608115595c..a93870c853 100644
--- a/src/user.js
+++ b/src/user.js
@@ -47,7 +47,8 @@ var utils = require('./../public/src/utils.js'),
RDB.handle(err);
var gravatar = User.createGravatarURLFromEmail(email);
-
+ var timestamp = Date.now();
+
RDB.hmset('user:'+uid, {
'uid': uid,
'username' : username,
@@ -58,7 +59,7 @@ var utils = require('./../public/src/utils.js'),
'website':'',
'email' : email || '',
'signature':'',
- 'joindate' : Date.now(),
+ 'joindate' : timestamp,
'picture': gravatar,
'gravatarpicture' : gravatar,
'uploadedpicture': '',
@@ -83,7 +84,9 @@ var utils = require('./../public/src/utils.js'),
io.sockets.emit('user.count', {count: count});
});
- RDB.lpush('userlist', uid);
+ RDB.zadd('users:joindate', timestamp, uid);
+ RDB.zadd('users:postcount', 0, uid);
+ RDB.zadd('users:reputation', 0, uid);
io.sockets.emit('user.latest', {userslug: userslug, username: username});
@@ -112,7 +115,9 @@ var utils = require('./../public/src/utils.js'),
RDB.del('followers:' + uid);
RDB.del('following:' + uid);
- RDB.lrem('userlist', 1, uid);
+ RDB.zrem('users:joindate', uid);
+ RDB.zrem('users:postcount', uid);
+ RDB.zrem('users:reputation', uid);
callback(true);
});
@@ -312,20 +317,21 @@ var utils = require('./../public/src/utils.js'),
RDB.hmset('user:' + uid, data);
}
- User.incrementUserFieldBy = function(uid, field, value) {
- RDB.hincrby('user:' + uid, field, value);
+ User.incrementUserFieldBy = function(uid, field, value, callback) {
+ RDB.hincrby('user:' + uid, field, value, callback);
}
- User.decrementUserFieldBy = function(uid, field, value) {
- RDB.hincrby('user:' + uid, field, -value);
+ User.decrementUserFieldBy = function(uid, field, value, callback) {
+ RDB.hincrby('user:' + uid, field, -value, callback);
}
- User.getUserList = function(callback) {
+ User.getUsers = function(set, start, stop, callback) {
var data = [];
-
- RDB.lrange('userlist', 0, -1, function(err, uids) {
-
- RDB.handle(err);
+
+ RDB.zrevrange(set, start, stop, function(err, uids) {
+ if(err) {
+ return callback(err, null);
+ }
function iterator(uid, callback) {
User.getUserData(uid, function(userData) {
@@ -336,14 +342,10 @@ var utils = require('./../public/src/utils.js'),
});
}
- async.each(uids, iterator, function(err) {
- if(!err) {
- callback(data);
- } else {
- console.log(err);
- callback(null);
- }
+ async.eachSeries(uids, iterator, function(err) {
+ callback(err, data);
});
+
});
}
@@ -401,7 +403,10 @@ var utils = require('./../public/src/utils.js'),
User.onNewPostMade = function(uid, tid, pid, timestamp) {
User.addPostIdToUser(uid, pid);
- User.incrementUserFieldBy(uid, 'postcount', 1);
+ User.incrementUserFieldBy(uid, 'postcount', 1, function(err, newpostcount) {
+ RDB.zadd('users:postcount', newpostcount, uid);
+ });
+
User.setUserField(uid, 'lastposttime', timestamp);
User.sendPostNotificationToFollowers(uid, tid, pid);
@@ -602,7 +607,7 @@ var utils = require('./../public/src/utils.js'),
};
User.latest = function(socket) {
- RDB.lrange('userlist', 0, 0, function(err, uid) {
+ RDB.zrevrange('users:joindate', 0, 0, function(err, uid) {
RDB.handle(err);
User.getUserFields(uid, ['username', 'userslug'], function(userData) {
diff --git a/src/webserver.js b/src/webserver.js
index 243b7885e0..9e415baa5f 100644
--- a/src/webserver.js
+++ b/src/webserver.js
@@ -401,6 +401,7 @@ var express = require('express'),
}
});
});
+
});
}(WebServer));
diff --git a/src/websockets.js b/src/websockets.js
index 6fa6c2568f..675736e42d 100644
--- a/src/websockets.js
+++ b/src/websockets.js
@@ -657,12 +657,24 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
var start = data.after,
end = start + 9;
- console.log(start, end);
topics.getUnreadTopics(uid, start, end, function(unreadTopics) {
callback(unreadTopics);
});
});
+ socket.on('api:users.loadMore', function(data, callback) {
+ var start = data.after,
+ end = start + 19;
+
+ user.getUsers(data.set, start, end, function(err, data) {
+ if(err) {
+ console.log(err);
+ } else {
+ callback({users:data});
+ }
+ });
+ });
+
socket.on('api:admin.topics.getMore', function(data, callback) {
topics.getAllTopics(data.limit, data.after, function(topics) {
callback(JSON.stringify(topics));