Merge branch 'master' of github.com:designcreateplay/NodeBB

v1.18.x
Julian Lam 11 years ago
commit 720644b964

@ -41,6 +41,11 @@
"favourites.not_logged_in.message": "Please log in in order to favourite this post", "favourites.not_logged_in.message": "Please log in in order to favourite this post",
"favourites.has_no_favourites": "You don't have any favourites, favourite some posts to see them here!", "favourites.has_no_favourites": "You don't have any favourites, favourite some posts to see them here!",
"vote.not_logged_in.title": "Not Logged In",
"vote.not_logged_in.message": "Please log in in order to vote",
"vote.cant_vote_self.title": "Invalid Vote",
"vote.cant_vote_self.message": "You cannot vote for your own post",
"loading_more_posts": "Loading More Posts", "loading_more_posts": "Loading More Posts",
"move_topic": "Move Topic", "move_topic": "Move Topic",
"move_post": "Move Post", "move_post": "Move Post",

@ -442,6 +442,46 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
return false; return false;
}); });
$('#post-container').on('click', '.upvote', function() {
var post = $(this).parents('.post-row'),
pid = post.attr('data-pid'),
upvoted = post.find('.upvoted').length;
if (upvoted) {
socket.emit('posts.unvote', {
pid: pid,
room_id: app.currentRoom
});
} else {
socket.emit('posts.upvote', {
pid: pid,
room_id: app.currentRoom
});
}
return false;
});
$('#post-container').on('click', '.downvote', function() {
var post = $(this).parents('.post-row'),
pid = post.attr('data-pid'),
downvoted = post.find('.downvoted').length;
if (downvoted) {
socket.emit('posts.unvote', {
pid: pid,
room_id: app.currentRoom
});
} else {
socket.emit('posts.downvote', {
pid: pid,
room_id: app.currentRoom
});
}
return false;
});
$('#post-container').on('click', '.flag', function() { $('#post-container').on('click', '.flag', function() {
bootbox.confirm('Are you sure you want to flag this post?', function(confirm) { bootbox.confirm('Are you sure you want to flag this post?', function(confirm) {
if (confirm) { if (confirm) {
@ -572,11 +612,11 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
}); });
ajaxify.register_events([ ajaxify.register_events([
'event:rep_up', 'event:rep_down', 'event:new_post', 'get_users_in_room', 'event:rep_up', 'event:rep_down', 'event:favourited', 'event:unfavourited', 'event:new_post', 'get_users_in_room',
'event:topic_deleted', 'event:topic_restored', 'event:topic:locked', 'event:topic_deleted', 'event:topic_restored', 'event:topic:locked',
'event:topic_unlocked', 'event:topic_pinned', 'event:topic_unpinned', 'event:topic_unlocked', 'event:topic_pinned', 'event:topic_unpinned',
'event:topic_moved', 'event:post_edited', 'event:post_deleted', 'event:post_restored', 'event:topic_moved', 'event:post_edited', 'event:post_deleted', 'event:post_restored',
'posts.favourite', 'user.isOnline' 'posts.favourite', 'user.isOnline', 'posts.upvote', 'posts.downvote'
]); ]);
socket.on('get_users_in_room', function(data) { socket.on('get_users_in_room', function(data) {
@ -674,6 +714,14 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
adjust_rep(-1, data.pid, data.uid); adjust_rep(-1, data.pid, data.uid);
}); });
socket.on('event:favourited', function(data) {
adjust_favourites(1, data.pid, data.uid);
});
socket.on('event:unfavourited', function(data) {
adjust_favourites(-1, data.pid, data.uid);
});
socket.on('event:new_post', function(data) { socket.on('event:new_post', function(data) {
if(config.usePagination) { if(config.usePagination) {
onNewPostPagination(data); onNewPostPagination(data);
@ -759,6 +807,35 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
}); });
}); });
socket.on('posts.upvote', function(data) {
if (data && data.pid) {
var post = $('li[data-pid="' + data.pid + '"]'),
upvote = post.find('.upvote');
upvote.addClass('btn-primary upvoted');
}
});
socket.on('posts.downvote', function(data) {
if (data && data.pid) {
var post = $('li[data-pid="' + data.pid + '"]'),
downvote = post.find('.downvote');
downvote.addClass('btn-primary downvoted');
}
});
socket.on('posts.unvote', function(data) {
if (data && data.pid) {
var post = $('li[data-pid="' + data.pid + '"]'),
upvote = post.find('.upvote'),
downvote = post.find('.downvote');
upvote.removeClass('btn-primary upvoted');
downvote.removeClass('btn-primary downvoted');
}
});
socket.on('posts.favourite', function(data) { socket.on('posts.favourite', function(data) {
if (data && data.pid) { if (data && data.pid) {
var favBtn = $('li[data-pid="' + data.pid + '"] .favourite'); var favBtn = $('li[data-pid="' + data.pid + '"] .favourite');
@ -803,17 +880,25 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
}); });
function adjust_rep(value, pid, uid) { function adjust_rep(value, pid, uid) {
var post_rep = jQuery('.post_rep_' + pid), var votes = $('li[data-pid="' + pid + '"] .votes'),
user_rep = jQuery('.user_rep_' + uid); reputationElements = $('.reputation[data-uid="' + uid + '"]'),
currentVotes = parseInt(votes.attr('data-votes'), 10),
reputation = parseInt(reputationElements.attr('data-reputation'), 10);
currentVotes += value;
reputation += value;
votes.html(currentVotes).attr('data-votes', currentVotes);
reputationElements.html(reputation).attr('data-reputation', reputation);
}
var ptotal = parseInt(post_rep.html(), 10), function adjust_favourites(value, pid, uid) {
utotal = parseInt(user_rep.html(), 10); var favourites = $('li[data-pid="' + pid + '"] .favouriteCount'),
currentFavourites = parseInt(favourites.attr('data-favourites'), 10);
ptotal += value; currentFavourites += value;
utotal += value;
post_rep.html(ptotal + ' '); favourites.html(currentFavourites).attr('data-favourites', currentFavourites);
user_rep.html(utotal + ' ');
} }
function set_locked_state(locked, alert) { function set_locked_state(locked, alert) {

@ -81,19 +81,28 @@ define(function() {
}); });
socket.on('user.isOnline', function(err, data) { socket.on('user.isOnline', function(err, data) {
if(getActiveSection().indexOf('online') === 0 && !loadingMoreUsers) { var section = getActiveSection();
if((section.indexOf('online') === 0 || section.indexOf('users') === 0) && !loadingMoreUsers) {
startLoading('users:online', 0, true); startLoading('users:online', 0, true);
socket.emit('user.getOnlineAnonCount', {} , function(err, anonCount) { updateAnonCount();
if(parseInt(anonCount, 10) > 0) {
$('#users-container .anon-user').removeClass('hide');
$('#online_anon_count').html(anonCount);
} else {
$('#users-container .anon-user').addClass('hide');
}
});
} }
}); });
socket.on('user.anonDisconnect', updateAnonCount);
socket.on('user.anonConnect', updateAnonCount)
function updateAnonCount() {
socket.emit('user.getOnlineAnonCount', {} , function(err, anonCount) {
if(parseInt(anonCount, 10) > 0) {
$('#users-container .anon-user').removeClass('hide');
$('#online_anon_count').html(anonCount);
} else {
$('#users-container .anon-user').addClass('hide');
}
});
}
function onUsersLoaded(users, emptyContainer) { function onUsersLoaded(users, emptyContainer) {
var html = templates.prepare(templates['users'].blocks['users']).parse({ var html = templates.prepare(templates['users'].blocks['users']).parse({
users: users users: users

@ -54,7 +54,7 @@
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" type="button" title="[[topic:posted_by]] {posts.username}"> <button class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" type="button" title="[[topic:posted_by]] {posts.username}">
<i class="fa fa-circle status offline"></i> <i class="fa fa-circle status offline"></i>
<span class="visible-xs visible-sm pull-left"><img class="" src="{posts.picture}" width=18 height=18 />&nbsp;</span> <span class="visible-xs-inline visible-md-inline"><img class="" src="{posts.picture}" width=18 height=18 />&nbsp;</span>
<span class="username-field" href="{relative_path}/user/{posts.userslug}" itemprop="author">{posts.username}&nbsp;</span> <span class="username-field" href="{relative_path}/user/{posts.userslug}" itemprop="author">{posts.username}&nbsp;</span>
<span class="caret"></span> <span class="caret"></span>
</button> </button>
@ -72,7 +72,7 @@
<button class="btn btn-sm btn-default flag" type="button" title="[[topic:flag_title]]"><i class="fa fa-flag-o"></i></button> <button class="btn btn-sm btn-default flag" type="button" title="[[topic:flag_title]]"><i class="fa fa-flag-o"></i></button>
<button data-favourited="{posts.favourited}" class="favourite favourite-tooltip btn btn-sm btn-default <!-- IF posts.favourited --> btn-warning <!-- ENDIF posts.favourited -->" type="button"> <button data-favourited="{posts.favourited}" class="favourite favourite-tooltip btn btn-sm btn-default <!-- IF posts.favourited --> btn-warning <!-- ENDIF posts.favourited -->" type="button">
<span class="favourite-text">[[topic:favourite]]</span> <span class="favourite-text">[[topic:favourite]]</span>
<span class="post_rep_{posts.pid}">{posts.reputation} </span> <span class="favouriteCount" data-favourites="{posts.reputation}">{posts.reputation}</span>&nbsp;
<!-- IF posts.favourited --> <!-- IF posts.favourited -->
<i class="fa fa-star"></i> <i class="fa fa-star"></i>
<!-- ELSE --> <!-- ELSE -->
@ -80,6 +80,17 @@
<!-- ENDIF posts.favourited --> <!-- ENDIF posts.favourited -->
</button> </button>
</div> </div>
<div class="btn-group">
<button class="upvote btn btn-sm btn-default <!-- IF posts.upvoted --> upvoted btn-primary <!-- ENDIF posts.upvoted -->">
<i class="fa fa-chevron-up"></i>
</button>
<button class="votes btn btn-sm btn-default" data-votes="{posts.votes}" disabled>{posts.votes}</button>
<button class="downvote btn btn-sm btn-default <!-- IF posts.downvoted --> downvoted btn-primary <!-- ENDIF posts.downvoted -->">
<i class="fa fa-chevron-down"></i>
</button>
</div>
<!-- IF privileges.write --> <!-- IF privileges.write -->
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-sm btn-default quote" type="button" title="[[topic:quote]]"><i class="fa fa-quote-left"></i></button> <button class="btn btn-sm btn-default quote" type="button" title="[[topic:quote]]"><i class="fa fa-quote-left"></i></button>
@ -129,7 +140,7 @@
<div class="post-info"> <div class="post-info">
<span class="pull-left"> <span class="pull-left">
[[topic:reputation]]: <i class='fa fa-star'></i> <span class='formatted-number post_rep_{posts.uid}'>{posts.user_rep}</span>&nbsp;|&nbsp;[[topic:posts]]: <i class='fa fa-pencil'></i> <span class='formatted-number user_postcount_{posts.uid}'>{posts.user_postcount}</span> [[topic:reputation]]: <i class='fa fa-star'></i> <span data-reputation="{posts.user_rep}" data-uid="{posts.uid}" class='formatted-number reputation'>{posts.user_rep}</span>&nbsp;|&nbsp;[[topic:posts]]: <i class='fa fa-pencil'></i> <span class='formatted-number user_postcount_{posts.uid}'>{posts.user_postcount}</span>
<!-- BEGIN custom_profile_info --> <!-- BEGIN custom_profile_info -->
| {posts.custom_profile_info.content} | {posts.custom_profile_info.content}
<!-- END custom_profile_info --> <!-- END custom_profile_info -->

@ -8,29 +8,178 @@ var async = require('async'),
(function (Favourites) { (function (Favourites) {
"use strict"; "use strict";
Favourites.favourite = function (pid, room_id, uid, socket) { function vote(type, unvote, pid, room_id, uid, socket, callback) {
var websockets = require('./socket.io'); var websockets = require('./socket.io');
if (uid === 0) { if (uid === 0) {
return socket.emit('event:alert', {
alert_id: 'post_vote',
title: '[[topic:vote.not_logged_in.title]]',
message: '[[topic:vote.not_logged_in.message]]',
type: 'danger',
timeout: 5000
});
}
translator.mget(['topic:favourites.not_logged_in.message', 'topic:favourites.not_logged_in.title'], function(err, results) { posts.getPostFields(pid, ['uid', 'timestamp'], function (err, postData) {
if (uid === parseInt(postData.uid, 10)) {
socket.emit('event:alert', { socket.emit('event:alert', {
alert_id: 'post_favourite', alert_id: 'post_vote',
title: results[1], title: '[[topic:vote.cant_vote_self.title]]',
message: results[0], message: '[[topic:vote.cant_vote_self.message]]',
type: 'danger', type: 'danger',
timeout: 5000 timeout: 5000
}); });
if (callback) {
callback(false);
}
return false;
}
db[type === 'upvote' || !unvote ? 'sortedSetAdd' : 'sortedSetRemove']('uid:' + uid + ':upvote', postData.timestamp, pid);
db[type === 'upvote' || unvote ? 'sortedSetRemove' : 'sortedSetAdd']('uid:' + uid + ':downvote', postData.timestamp, pid);
user[type === 'upvote' ? 'incrementUserFieldBy' : 'decrementUserFieldBy'](postData.uid, 'reputation', 1, function (err, newreputation) {
db.sortedSetAdd('users:reputation', newreputation, postData.uid);
});
if (room_id) {
websockets.in(room_id).emit('event:' + (type === 'upvote' ? 'rep_up' : 'rep_down'), {
uid: postData.uid,
pid: pid
});
}
socket.emit('posts.' + (unvote ? 'unvote' : type), {
pid: pid
});
adjustPostVotes(pid, uid, type, unvote, function() {
if (callback) {
callback();
}
});
});
}
function adjustPostVotes(pid, uid, type, unvote, callback) {
var notType = (type === 'upvote' ? 'downvote' : 'upvote');
async.series([
function(next) {
if (unvote) {
db.setRemove('pid:' + pid + ':' + type, uid, function(err) {
next(err);
});
} else {
db.setAdd('pid:' + pid + ':' + type, uid, function(err) {
next(err);
});
}
},
function(next) {
db.setRemove('pid:' + pid + ':' + notType, uid, function(err) {
next(err);
});
}
], function(err) {
async.parallel({
upvotes: function(next) {
db.setCount('pid:' + pid + ':upvote', next);
},
downvotes: function(next) {
db.setCount('pid:' + pid + ':downvote', next);
}
}, function(err, results) {
posts.setPostField(pid, 'votes', parseInt(results.upvotes, 10) - parseInt(results.downvotes, 10));
});
if (callback) {
callback();
}
});
}
Favourites.upvote = function(pid, room_id, uid, socket) {
Favourites.unvote(pid, room_id, uid, socket, function(err) {
vote('upvote', false, pid, room_id, uid, socket);
});
};
Favourites.downvote = function(pid, room_id, uid, socket) {
Favourites.unvote(pid, room_id, uid, socket, function(err) {
vote('downvote', false, pid, room_id, uid, socket);
});
};
Favourites.unvote = function(pid, room_id, uid, socket, callback) {
var websockets = require('./socket.io');
Favourites.hasVoted(pid, uid, function(err, voteStatus) {
if (voteStatus.upvoted || voteStatus.downvoted) {
socket.emit('posts.unvote', {
pid: pid
});
return vote(voteStatus.upvoted ? 'downvote' : 'upvote', true, pid, room_id, uid, socket, function() {
if (callback) {
callback(err);
}
});
}
if (callback) {
callback(err);
}
});
};
Favourites.hasVoted = function(pid, uid, callback) {
async.parallel({
upvoted: function(next) {
db.isSetMember('pid:' + pid + ':upvote', uid, next);
},
downvoted: function(next) {
db.isSetMember('pid:' + pid + ':downvote', uid, next);
}
}, function(err, results) {
callback(err, results)
});
};
Favourites.getVoteStatusByPostIDs = function(pids, uid, callback) {
var data = {};
function iterator(pid, next) {
Favourites.hasVoted(pid, uid, function(err, voteStatus) {
data[pid] = voteStatus;
next()
}); });
return;
} }
posts.getPostFields(pid, ['uid', 'timestamp'], function (err, postData) { async.each(pids, iterator, function(err) {
callback(data);
});
};
Favourites.hasFavourited(pid, uid, function (err, hasFavourited) { Favourites.favourite = function (pid, room_id, uid, socket) {
var websockets = require('./socket.io');
if (!hasFavourited) { if (uid === 0) {
return socket.emit('event:alert', {
alert_id: 'post_favourite',
title: '[[topic:favourites.not_logged_in.title]]',
message: '[[topic:favourites.not_logged_in.message]]',
type: 'danger',
timeout: 5000
});
}
posts.getPostFields(pid, ['uid', 'timestamp'], function (err, postData) {
Favourites.hasFavourited(pid, uid, function (err, hasFavourited) {
if (!hasFavourited) {
db.sortedSetAdd('uid:' + uid + ':favourites', postData.timestamp, pid); db.sortedSetAdd('uid:' + uid + ':favourites', postData.timestamp, pid);
db.setAdd('pid:' + pid + ':users_favourited', uid, function(err) { db.setAdd('pid:' + pid + ':users_favourited', uid, function(err) {
db.setCount('pid:' + pid + ':users_favourited', function(err, count) { db.setCount('pid:' + pid + ':users_favourited', function(err, count) {
@ -38,15 +187,8 @@ var async = require('async'),
}); });
}); });
if (uid !== postData.uid) {
user.incrementUserFieldBy(postData.uid, 'reputation', 1, function (err, newreputation) {
db.sortedSetAdd('users:reputation', newreputation, postData.uid);
});
}
if (room_id) { if (room_id) {
websockets.in(room_id).emit('event:rep_up', { websockets.in(room_id).emit('event:favourited', {
uid: uid !== postData.uid ? postData.uid : 0, uid: uid !== postData.uid ? postData.uid : 0,
pid: pid pid: pid
}); });
@ -60,7 +202,7 @@ var async = require('async'),
}); });
}; };
Favourites.unfavourite = function (pid, room_id, uid, socket) { Favourites.unfavourite = function(pid, room_id, uid, socket) {
var websockets = require('./socket.io'); var websockets = require('./socket.io');
if (uid === 0) { if (uid === 0) {
@ -70,23 +212,15 @@ var async = require('async'),
posts.getPostField(pid, 'uid', function (err, uid_of_poster) { posts.getPostField(pid, 'uid', function (err, uid_of_poster) {
Favourites.hasFavourited(pid, uid, function (err, hasFavourited) { Favourites.hasFavourited(pid, uid, function (err, hasFavourited) {
if (hasFavourited) { if (hasFavourited) {
db.sortedSetRemove('uid:' + uid + ':favourites', pid); db.sortedSetRemove('uid:' + uid + ':favourites', pid);
db.setRemove('pid:' + pid + ':users_favourited', uid, function(err) { db.setRemove('pid:' + pid + ':users_favourited', uid, function(err) {
db.setCount('pid:' + pid + ':users_favourited', function(err, count) { db.setCount('pid:' + pid + ':users_favourited', function(err, count) {
posts.setPostField(pid, 'reputation', count); posts.setPostField(pid, 'reputation', count);
}); });
}); });
if (uid !== uid_of_poster) {
user.incrementUserFieldBy(uid_of_poster, 'reputation', -1, function (err, newreputation) {
db.sortedSetAdd('users:reputation', newreputation, uid_of_poster);
});
}
if (room_id) { if (room_id) {
websockets.in(room_id).emit('event:rep_down', { websockets.in(room_id).emit('event:unfavourited', {
uid: uid !== uid_of_poster ? uid_of_poster : 0, uid: uid !== uid_of_poster ? uid_of_poster : 0,
pid: pid pid: pid
}); });
@ -100,15 +234,15 @@ var async = require('async'),
}); });
}; };
Favourites.hasFavourited = function (pid, uid, callback) { Favourites.hasFavourited = function(pid, uid, callback) {
db.isSetMember('pid:' + pid + ':users_favourited', uid, callback); db.isSetMember('pid:' + pid + ':users_favourited', uid, callback);
}; };
Favourites.getFavouritesByPostIDs = function (pids, uid, callback) { Favourites.getFavouritesByPostIDs = function(pids, uid, callback) {
var data = {}; var data = {};
function iterator(pid, next) { function iterator(pid, next) {
Favourites.hasFavourited(pid, uid, function (err, hasFavourited) { Favourites.hasFavourited(pid, uid, function(err, hasFavourited) {
data[pid] = hasFavourited; data[pid] = hasFavourited;
next() next()
}); });
@ -119,7 +253,7 @@ var async = require('async'),
}); });
}; };
Favourites.getFavouritedUidsByPids = function (pids, callback) { Favourites.getFavouritedUidsByPids = function(pids, callback) {
var data = {}; var data = {};
function getUids(pid, next) { function getUids(pid, next) {

@ -479,8 +479,8 @@ var db = require('./database'),
async.each(pids, reIndex, callback); async.each(pids, reIndex, callback);
} }
// this function should really be called User.getFavouritePosts
Posts.getFavourites = function(uid, start, end, callback) { Posts.getFavourites = function(uid, start, end, callback) {
db.getSortedSetRevRange('uid:' + uid + ':favourites', start, end, function(err, pids) { db.getSortedSetRevRange('uid:' + uid + ':favourites', start, end, function(err, pids) {
if (err) { if (err) {
return callback(err); return callback(err);

@ -490,18 +490,26 @@ var fs = require('fs'),
}); });
} }
function getOnlineUsers(req, res) { function getOnlineUsers(req, res, next) {
var websockets = require('../socket.io'); var websockets = require('../socket.io');
user.getUsers('users:online', 0, 49, function (err, data) { user.getUsers('users:online', 0, 49, function (err, data) {
if(err) {
return next(err);
}
var onlineUsers = []; var onlineUsers = [];
uid = 0; uid = 0;
if (req.user) { if (req.user) {
uid = req.user.uid; uid = req.user.uid;
} }
user.isAdministrator(uid, function (err, isAdministrator) { user.isAdministrator(uid, function (err, isAdministrator) {
if (true != isAdministrator) { if(err) {
return next(err);
}
if (!isAdministrator) {
data = data.filter(function(item) { data = data.filter(function(item) {
return item.status !== 'offline'; return item.status !== 'offline';
}); });

@ -64,11 +64,12 @@ SocketAdmin.user.createUser = function(socket, user, callback) {
SocketAdmin.user.banUser = function(socket, theirid) { SocketAdmin.user.banUser = function(socket, theirid) {
admin.user.banUser(socket.uid, theirid, socket, function(isBanned) { admin.user.banUser(socket.uid, theirid, socket, function(isBanned) {
if(isBanned) { if(isBanned) {
if(index.userSockets[theirid]) { var sockets = index.getUserSockets(theirid);
for(var i=0; i<index.userSockets[theirid].length; ++i) {
index.userSockets[theirid][i].emit('event:banned'); for(var i=0; i<sockets.length; ++i) {
} sockets[i].emit('event:banned');
} }
module.parent.exports.logoutUser(theirid); module.parent.exports.logoutUser(theirid);
} }
}); });

@ -27,9 +27,6 @@ var SocketIO = require('socket.io'),
var io; var io;
Sockets.userSockets = {};
Sockets.init = function(server) { Sockets.init = function(server) {
io = socketioWildcard(SocketIO).listen(server, { io = socketioWildcard(SocketIO).listen(server, {
@ -63,16 +60,13 @@ Sockets.init = function(server) {
sessionID = socket.handshake.signedCookies["express.sid"]; sessionID = socket.handshake.signedCookies["express.sid"];
db.sessionStore.get(sessionID, function(err, sessionData) { db.sessionStore.get(sessionID, function(err, sessionData) {
if (!err && sessionData && sessionData.passport && sessionData.passport.user) { if (!err && sessionData && sessionData.passport && sessionData.passport.user) {
uid = sessionData.passport.user; uid = parseInt(sessionData.passport.user, 10);
} else { } else {
uid = 0; uid = 0;
} }
socket.uid = parseInt(uid, 10); socket.uid = parseInt(uid, 10);
Sockets.userSockets[uid] = Sockets.userSockets[uid] || [];
Sockets.userSockets[uid].push(socket);
/* Need to save some state for the logger & maybe some other modules later on */ /* Need to save some state for the logger & maybe some other modules later on */
socket.state = { socket.state = {
user : { user : {
@ -106,45 +100,43 @@ Sockets.init = function(server) {
isAdmin: userData.isAdmin, isAdmin: userData.isAdmin,
uid: uid uid: uid
}); });
socketUser.isOnline(socket, uid, function(err, data) {
socket.broadcast.emit('user.isOnline', err, data);
});
}); });
}); });
} else {
socket.broadcast.emit('user.anonConnect');
} }
socketUser.isOnline(socket, uid, function(err, data) {
socket.broadcast.emit('user.isOnline', err, data);
});
}); });
}); });
socket.on('disconnect', function() { socket.on('disconnect', function() {
var index = (Sockets.userSockets[uid] || []).indexOf(socket); if (uid && !Sockets.getUserSockets(uid).length <= 1) {
if (index !== -1) { db.sortedSetRemove('users:online', uid, function(err) {
Sockets.userSockets[uid].splice(index, 1); socketUser.isOnline(socket, uid, function(err, data) {
} socket.broadcast.emit('user.isOnline', err, data);
if (Sockets.userSockets[uid] && Sockets.userSockets[uid].length === 0) {
delete Sockets.userSockets[uid];
if (uid) {
db.sortedSetRemove('users:online', uid, function(err, data) {
}); });
} });
} }
socketUser.isOnline(socket, uid, function(err, data) { if (!uid) {
socket.broadcast.emit('user.isOnline', err, data); socket.broadcast.emit('user.anonDisconnect');
}); }
emitOnlineUserCount(); emitOnlineUserCount();
for(var roomName in io.sockets.manager.roomClients[socket.id]) { for(var roomName in io.sockets.manager.roomClients[socket.id]) {
updateRoomBrowsingText(roomName.slice(1)); updateRoomBrowsingText(roomName.slice(1));
} }
}); });
socket.on('*', function(payload, callback) { socket.on('*', function(payload, callback) {
function callMethod(method) { function callMethod(method) {
if(socket.uid) { if(socket.uid) {
user.setUserField(socket.uid, 'lastonline', Date.now()); user.setUserField(socket.uid, 'lastonline', Date.now());
@ -187,16 +179,10 @@ Sockets.init = function(server) {
}; };
Sockets.logoutUser = function(uid) { Sockets.logoutUser = function(uid) {
if(Sockets.userSockets[uid] && Sockets.userSockets[uid].length) { Sockets.getUserSockets(uid).forEach(function(socket) {
for(var i=0; i< Sockets.userSockets[uid].length; ++i) { socket.emit('event:disconnect');
Sockets.userSockets[uid][i].emit('event:disconnect'); socket.disconnect();
Sockets.userSockets[uid][i].disconnect(); });
if(!Sockets.userSockets[uid]) {
return;
}
}
}
}; };
Sockets.emitUserCount = function() { Sockets.emitUserCount = function() {
@ -212,18 +198,38 @@ Sockets.in = function(room) {
}; };
Sockets.getConnectedClients = function() { Sockets.getConnectedClients = function() {
return Sockets.userSockets; var clients = io.sockets.clients();
var uids = [];
clients.forEach(function(client) {
if(client.uid && uids.indexOf(client.uid) === -1) {
uids.push(client.uid);
}
});
return uids;
}; };
Sockets.getOnlineAnonCount = function () { Sockets.getOnlineAnonCount = function () {
return Sockets.userSockets[0] ? Sockets.userSockets[0].length : 0; return Sockets.getUserSockets(0).length;
};
Sockets.getUserSockets = function(uid) {
var sockets = io.sockets.clients();
if(!sockets || !sockets.length) {
return [];
}
sockets = sockets.filter(function(s) {
return s.uid === parseInt(uid, 10);
});
return sockets;
}; };
/* Helpers */ /* Helpers */
Sockets.isUserOnline = isUserOnline; Sockets.isUserOnline = isUserOnline;
function isUserOnline(uid) { function isUserOnline(uid) {
return !!Sockets.userSockets[uid] && Sockets.userSockets[uid].length > 0; return Sockets.getUserSockets(uid).length > 0;
} }
Sockets.updateRoomBrowsingText = updateRoomBrowsingText; Sockets.updateRoomBrowsingText = updateRoomBrowsingText;
@ -292,11 +298,8 @@ function emitTopicPostStats(callback) {
Sockets.emitOnlineUserCount = emitOnlineUserCount; Sockets.emitOnlineUserCount = emitOnlineUserCount;
function emitOnlineUserCount(callback) { function emitOnlineUserCount(callback) {
var anon = Sockets.userSockets[0] ? Sockets.userSockets[0].length : 0; var anon = Sockets.getOnlineAnonCount(0);
var registered = Object.keys(Sockets.userSockets).length; var registered = Sockets.getConnectedClients().length;
if (anon) {
registered = registered - 1;
}
var returnObj = { var returnObj = {
users: registered + anon, users: registered + anon,

@ -113,39 +113,29 @@ SocketModules.chats.send = function(socket, data) {
usersData[0].uid = socket.uid; usersData[0].uid = socket.uid;
usersData[1].uid = touid; usersData[1].uid = touid;
Messaging.parse(msg, socket.uid, socket.uid, usersData[1], usersData[0], true, function(parsed) { Messaging.parse(msg, socket.uid, socket.uid, usersData[1], usersData[0], true, function(parsed) {
Messaging.addMessage(socket.uid, touid, msg, function(err, message) { Messaging.addMessage(socket.uid, touid, msg, function(err, message) {
var numSockets = 0,
x;
server.getUserSockets(touid).forEach(function(s) {
if (server.userSockets[touid]) { s.emit('event:chats.receive', {
numSockets = server.userSockets[touid].length; fromuid: socket.uid,
username: username,
for (x = 0; x < numSockets; ++x) { message: parsed,
server.userSockets[touid][x].emit('event:chats.receive', { timestamp: Date.now()
fromuid: socket.uid, });
username: username, });
message: parsed,
timestamp: Date.now() server.getUserSockets(socket.uid).forEach(function(s) {
}); s.emit('event:chats.receive', {
} fromuid: touid,
} username: toUsername,
message: parsed,
if (server.userSockets[socket.uid]) { timestamp: Date.now()
});
numSockets = server.userSockets[socket.uid].length; });
});
for (x = 0; x < numSockets; ++x) { });
server.userSockets[socket.uid][x].emit('event:chats.receive', {
fromuid: touid,
username: toUsername,
message: parsed,
timestamp: Date.now()
});
}
}
});
});
}); });
}; };

@ -73,6 +73,24 @@ SocketPosts.reply = function(socket, data, callback) {
}); });
}; };
SocketPosts.upvote = function(socket, data) {
if(data && data.pid && data.room_id) {
favourites.upvote(data.pid, data.room_id, socket.uid, socket);
}
};
SocketPosts.downvote = function(socket, data) {
if(data && data.pid && data.room_id) {
favourites.downvote(data.pid, data.room_id, socket.uid, socket);
}
};
SocketPosts.unvote = function(socket, data) {
if(data && data.pid && data.room_id) {
favourites.unvote(data.pid, data.room_id, socket.uid, socket);
}
};
SocketPosts.favourite = function(socket, data) { SocketPosts.favourite = function(socket, data) {
if(data && data.pid && data.room_id) { if(data && data.pid && data.room_id) {
favourites.favourite(data.pid, data.room_id, socket.uid, socket); favourites.favourite(data.pid, data.room_id, socket.uid, socket);

@ -341,6 +341,12 @@ var async = require('async'),
}); });
} }
function getVoteStatusData(next) {
favourites.getVoteStatusByPostIDs(pids, current_user, function(vote_data) {
next(null, vote_data);
})
}
function addUserInfoToPosts(next) { function addUserInfoToPosts(next) {
function iterator(post, callback) { function iterator(post, callback) {
posts.addUserInfoToPost(post, function() { posts.addUserInfoToPost(post, function() {
@ -370,17 +376,21 @@ var async = require('async'),
} }
} }
async.parallel([getFavouritesData, addUserInfoToPosts, getPrivileges], function(err, results) { async.parallel([getFavouritesData, addUserInfoToPosts, getPrivileges, getVoteStatusData], function(err, results) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
var fav_data = results[0], var fav_data = results[0],
privileges = results[2]; privileges = results[2],
voteStatus = results[3];
for (var i = 0; i < postData.length; ++i) { for (var i = 0; i < postData.length; ++i) {
var pid = postData[i].pid; var pid = postData[i].pid;
postData[i].favourited = fav_data[pid]; postData[i].favourited = fav_data[pid];
postData[i].upvoted = voteStatus[pid].upvoted;
postData[i].downvoted = voteStatus[pid].downvoted;
postData[i].votes = postData[i].votes || 0;
postData[i].display_moderator_tools = (current_user != 0) && privileges[pid].editable; postData[i].display_moderator_tools = (current_user != 0) && privileges[pid].editable;
postData[i].display_move_tools = privileges[pid].move; postData[i].display_move_tools = privileges[pid].move;
if(parseInt(postData[i].deleted, 10) === 1 && !privileges[pid].view_deleted) { if(parseInt(postData[i].deleted, 10) === 1 && !privileges[pid].view_deleted) {
@ -647,8 +657,7 @@ var async = require('async'),
var websockets = require('./socket.io'); var websockets = require('./socket.io');
if (!uids) { if (!uids) {
clients = websockets.getConnectedClients(); uids = websockets.getConnectedClients();
uids = Object.keys(clients);
} else if (!Array.isArray(uids)) { } else if (!Array.isArray(uids)) {
uids = [uids]; uids = [uids];
} }

@ -19,7 +19,7 @@ var db = require('./database'),
Upgrade.check = function(callback) { Upgrade.check = function(callback) {
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
var latestSchema = new Date(2014, 0, 30, 16, 0).getTime(); var latestSchema = new Date(2014, 1, 2, 16, 0).getTime();
db.get('schemaDate', function(err, value) { db.get('schemaDate', function(err, value) {
if (parseInt(value, 10) >= latestSchema) { if (parseInt(value, 10) >= latestSchema) {
@ -431,6 +431,8 @@ Upgrade.upgrade = function(callback) {
} }
}, },
function(next) { function(next) {
thisSchemaDate = new Date(2014, 0, 30, 16, 0).getTime();
function updateTopic(tid, next) { function updateTopic(tid, next) {
Topics.getTopicFields(tid, ['postcount', 'viewcount'], function(err, topicData) { Topics.getTopicFields(tid, ['postcount', 'viewcount'], function(err, topicData) {
if(err) { if(err) {
@ -454,7 +456,6 @@ Upgrade.upgrade = function(callback) {
}); });
} }
thisSchemaDate = new Date(2014, 0, 30, 16, 0).getTime();
if (schemaDate < thisSchemaDate) { if (schemaDate < thisSchemaDate) {
updatesMade = true; updatesMade = true;
@ -476,7 +477,44 @@ Upgrade.upgrade = function(callback) {
winston.info('[2014/1/30] Adding new topic sets -- skipped'); winston.info('[2014/1/30] Adding new topic sets -- skipped');
next(); next();
} }
} },
function(next) {
thisSchemaDate = new Date(2014, 1, 2, 16, 0).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
winston.info('[2014/2/6] Upvoting all favourited posts for each user');
User.getUsers('users:joindate', 0, -1, function (err, users) {
function getFavourites(user, next) {
function upvote(post, next) {
var pid = post.pid,
uid = user.uid;
if (post.uid !== uid) {
db.setAdd('pid:' + pid + ':upvote', uid);
db.sortedSetAdd('uid:' + uid + ':upvote', post.timestamp, pid);
db.incrObjectField('post:' + pid, 'votes');
}
next();
}
Posts.getFavourites(user.uid, 0, -1, function(err, posts) {
async.each(posts.posts, upvote, function(err) {
next(err);
});
});
}
async.each(users, getFavourites, function(err) {
next(err);
});
});
} else {
winston.info('[2014/2/6] Upvoting all favourited posts for each user -- skipped');
next();
}
},
// Add new schema updates here // Add new schema updates here
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 17!!! // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 17!!!
], function(err) { ], function(err) {

Loading…
Cancel
Save