mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 19:46:01 +01:00
recent chat list with rooms
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
"use strict";
|
||||
/* globals app, config, define, socket, templates, utils, ajaxify */
|
||||
/* globals app, define, socket, templates, utils, ajaxify */
|
||||
|
||||
define('chat', ['components', 'taskbar', 'string', 'sounds', 'forum/chats', 'translator'], function(components, taskbar, S, sounds, Chats, translator) {
|
||||
|
||||
@@ -90,15 +90,16 @@ define('chat', ['components', 'taskbar', 'string', 'sounds', 'forum/chats', 'tra
|
||||
module.loadChatsDropdown = function(chatsListEl) {
|
||||
var dropdownEl;
|
||||
|
||||
socket.emit('modules.chats.getRecentChats', {after: 0}, function(err, chats) {
|
||||
socket.emit('modules.chats.getRecentChats', {after: 0}, function(err, data) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
chats = chats.users;
|
||||
|
||||
var rooms = data.rooms;
|
||||
|
||||
chatsListEl.empty();
|
||||
|
||||
if (!chats.length) {
|
||||
if (!rooms.length) {
|
||||
translator.translate('[[modules:chat.no_active]]', function(str) {
|
||||
$('<li />')
|
||||
.addClass('no_active')
|
||||
@@ -108,17 +109,23 @@ define('chat', ['components', 'taskbar', 'string', 'sounds', 'forum/chats', 'tra
|
||||
return;
|
||||
}
|
||||
|
||||
chats.forEach(function(userObj) {
|
||||
dropdownEl = $('<li class="' + (userObj.unread ? 'unread' : '') + '"/>')
|
||||
.attr('data-uid', userObj.uid)
|
||||
.html('<a data-ajaxify="false">'+
|
||||
rooms.forEach(function(roomObj) {
|
||||
function createUserImage(userObj) {
|
||||
return '<a data-ajaxify="false">' +
|
||||
(userObj.picture ?
|
||||
'<img src="' + userObj.picture + '" title="' + userObj.username +'" />' :
|
||||
'<div class="user-icon" style="background-color: ' + userObj['icon:bgColor'] + '">' + userObj['icon:text'] + '</div>') +
|
||||
'<i class="fa fa-circle status ' + userObj.status + '"></i> ' +
|
||||
userObj.username + '</a>')
|
||||
userObj.username + '</a>';
|
||||
}
|
||||
|
||||
dropdownEl = $('<li class="' + (roomObj.unread ? 'unread' : '') + '"/>')
|
||||
.attr('data-roomId', roomObj.roomId)
|
||||
.appendTo(chatsListEl);
|
||||
|
||||
roomObj.users.forEach(function(userObj) {
|
||||
dropdownEl.append(createUserImage(userObj));
|
||||
});
|
||||
|
||||
dropdownEl.click(function() {
|
||||
if (!ajaxify.currentPage.match(/^chats\//)) {
|
||||
@@ -229,7 +236,7 @@ define('chat', ['components', 'taskbar', 'string', 'sounds', 'forum/chats', 'tra
|
||||
chatModal.find('.modal-header').on('dblclick', gotoChats);
|
||||
chatModal.find('button[data-action="maximize"]').on('click', gotoChats);
|
||||
|
||||
chatModal.on('click', function(e) {
|
||||
chatModal.on('click', function() {
|
||||
module.bringModalToTop(chatModal);
|
||||
|
||||
if (!dragged) {
|
||||
|
||||
136
src/messaging.js
136
src/messaging.js
@@ -1,27 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
var db = require('./database'),
|
||||
async = require('async'),
|
||||
nconf = require('nconf'),
|
||||
|
||||
var async = require('async'),
|
||||
winston = require('winston'),
|
||||
S = require('string'),
|
||||
nconf = require('nconf'),
|
||||
|
||||
db = require('./database'),
|
||||
user = require('./user'),
|
||||
plugins = require('./plugins'),
|
||||
meta = require('./meta'),
|
||||
emailer = require('./emailer'),
|
||||
utils = require('../public/src/utils'),
|
||||
notifications = require('./notifications'),
|
||||
userNotifications = require('./user/notifications'),
|
||||
emailer = require('./emailer'),
|
||||
sockets = require('./socket.io');
|
||||
|
||||
(function(Messaging) {
|
||||
|
||||
require('./create')(Messaging);
|
||||
require('./delete')(Messaging);
|
||||
require('./edit')(Messaging);
|
||||
require('./rooms')(Messaging);
|
||||
require('./unread')(Messaging);
|
||||
require('./messaging/create')(Messaging);
|
||||
require('./messaging/delete')(Messaging);
|
||||
require('./messaging/edit')(Messaging);
|
||||
require('./messaging/rooms')(Messaging);
|
||||
require('./messaging/unread')(Messaging);
|
||||
|
||||
Messaging.notifyQueue = {}; // Only used to notify a user of a new chat message, see Messaging.notifyUser
|
||||
|
||||
@@ -32,13 +33,9 @@ var db = require('./database'),
|
||||
threemonths: 7776000000
|
||||
};
|
||||
|
||||
function sortUids(fromuid, touid) {
|
||||
return [fromuid, touid].sort();
|
||||
}
|
||||
|
||||
Messaging.getMessageField = function(mid, field, callback) {
|
||||
Messaging.getMessageFields(mid, [field], function(err, fields) {
|
||||
callback(err, fields[field]);
|
||||
callback(err, fields ? fields[field] : null);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -55,22 +52,21 @@ var db = require('./database'),
|
||||
};
|
||||
|
||||
Messaging.getMessages = function(params, callback) {
|
||||
var fromuid = params.fromuid,
|
||||
touid = params.touid,
|
||||
var uid = params.uid,
|
||||
roomId = params.roomId,
|
||||
since = params.since,
|
||||
isNew = params.isNew,
|
||||
count = params.count || parseInt(meta.config.chatMessageInboxSize, 10) || 250,
|
||||
markRead = params.markRead || true;
|
||||
|
||||
var uids = sortUids(fromuid, touid),
|
||||
min = params.count ? 0 : Date.now() - (terms[since] || terms.day);
|
||||
var min = params.count ? 0 : Date.now() - (terms[since] || terms.day);
|
||||
|
||||
if (since === 'recent') {
|
||||
count = 49;
|
||||
min = 0;
|
||||
}
|
||||
|
||||
db.getSortedSetRevRangeByScore('messages:uid:' + uids[0] + ':to:' + uids[1], 0, count, '+inf', min, function(err, mids) {
|
||||
db.getSortedSetRevRangeByScore('uid:' + uid + ':chat:room:' + roomId + ':mids', 0, count, '+inf', min, function(err, mids) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
@@ -81,52 +77,60 @@ var db = require('./database'),
|
||||
|
||||
mids.reverse();
|
||||
|
||||
Messaging.getMessagesData(mids, fromuid, touid, isNew, callback);
|
||||
Messaging.getMessagesData(mids, uid, roomId, isNew, callback);
|
||||
});
|
||||
|
||||
if (markRead) {
|
||||
notifications.markRead('chat_' + touid + '_' + fromuid, fromuid, function(err) {
|
||||
notifications.markRead('chat_' + roomId + '_' + uid, uid, function(err) {
|
||||
if (err) {
|
||||
winston.error('[messaging] Could not mark notifications related to this chat as read: ' + err.message);
|
||||
}
|
||||
|
||||
userNotifications.pushCount(fromuid);
|
||||
userNotifications.pushCount(uid);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Messaging.getMessagesData = function(mids, fromuid, touid, isNew, callback) {
|
||||
user.getUsersFields([fromuid, touid], ['uid', 'username', 'userslug', 'picture', 'status'], function(err, userData) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
Messaging.getMessagesData = function(mids, uid, roomId, isNew, callback) {
|
||||
|
||||
var keys = mids.map(function(mid) {
|
||||
return 'message:' + mid;
|
||||
});
|
||||
|
||||
var messages;
|
||||
|
||||
async.waterfall([
|
||||
async.apply(db.getObjects, keys),
|
||||
function(messages, next) {
|
||||
messages = messages.map(function(msg, idx) {
|
||||
function (next) {
|
||||
db.getObjects(keys, next);
|
||||
},
|
||||
function (_messages, next) {
|
||||
messages = _messages.map(function(msg, idx) {
|
||||
if (msg) {
|
||||
msg.messageId = parseInt(mids[idx], 10);
|
||||
}
|
||||
return msg;
|
||||
}).filter(Boolean);
|
||||
async.map(messages, function(message, next) {
|
||||
var self = parseInt(message.fromuid, 10) === parseInt(fromuid, 10);
|
||||
message.fromUser = self ? userData[0] : userData[1];
|
||||
message.toUser = self ? userData[1] : userData[0];
|
||||
message.timestampISO = utils.toISOString(message.timestamp);
|
||||
message.self = self ? 1 : 0;
|
||||
message.newSet = false;
|
||||
|
||||
var uids = messages.map(function(msg) {
|
||||
return msg && msg.fromuid;
|
||||
});
|
||||
|
||||
user.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture', 'status'], next);
|
||||
},
|
||||
function (users, next) {
|
||||
messages.forEach(function(message, index) {
|
||||
message.fromUser = users[index];
|
||||
var self = parseInt(message.fromuid, 10) === parseInt(uid, 10);
|
||||
message.self = self ? 1 : 0;
|
||||
message.timestampISO = utils.toISOString(message.timestamp);
|
||||
message.newSet = false;
|
||||
if (message.hasOwnProperty('edited')) {
|
||||
message.editedISO = new Date(parseInt(message.edited, 10)).toISOString();
|
||||
}
|
||||
});
|
||||
|
||||
Messaging.parse(message.content, message.fromuid, fromuid, userData[1], userData[0], isNew, function(result) {
|
||||
async.map(messages, function(message, next) {
|
||||
Messaging.parse(message.content, message.fromuid, uid, roomId, isNew, function(result) {
|
||||
message.content = result;
|
||||
message.cleanedContent = S(result).stripTags().decodeHTMLEntities().s;
|
||||
next(null, message);
|
||||
@@ -152,8 +156,7 @@ var db = require('./database'),
|
||||
next(undefined, messages);
|
||||
} else {
|
||||
// For single messages, we don't know the context, so look up the previous message and compare
|
||||
var uids = [fromuid, touid].sort(function(a, b) { return a > b ? 1 : -1; });
|
||||
var key = 'messages:uid:' + uids[0] + ':to:' + uids[1];
|
||||
var key = 'uid:' + uid + ':chat:room:' + roomId + ':mids';
|
||||
async.waterfall([
|
||||
async.apply(db.sortedSetRank, key, messages[0].messageId),
|
||||
function(index, next) {
|
||||
@@ -186,10 +189,10 @@ var db = require('./database'),
|
||||
}
|
||||
}
|
||||
], callback);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
Messaging.parse = function (message, fromuid, myuid, toUserData, myUserData, isNew, callback) {
|
||||
Messaging.parse = function (message, fromuid, uid, roomId, isNew, callback) {
|
||||
plugins.fireHook('filter:parse.raw', message, function(err, parsed) {
|
||||
if (err) {
|
||||
return callback(message);
|
||||
@@ -199,9 +202,8 @@ var db = require('./database'),
|
||||
message: message,
|
||||
parsed: parsed,
|
||||
fromuid: fromuid,
|
||||
myuid: myuid,
|
||||
toUserData: toUserData,
|
||||
myUserData: myUserData,
|
||||
uid: uid,
|
||||
roomId: roomId,
|
||||
isNew: isNew,
|
||||
parsedMessage: parsed
|
||||
};
|
||||
@@ -212,9 +214,8 @@ var db = require('./database'),
|
||||
});
|
||||
};
|
||||
|
||||
Messaging.isNewSet = function(fromuid, touid, mid, callback) {
|
||||
var uids = sortUids(fromuid, touid),
|
||||
setKey = 'messages:uid:' + uids[0] + ':to:' + uids[1];
|
||||
Messaging.isNewSet = function(uid, roomId, mid, callback) {
|
||||
var setKey = 'uid:' + uid + ':chat:room:' + roomId + ':mids';
|
||||
|
||||
async.waterfall([
|
||||
async.apply(db.sortedSetRank, setKey, mid),
|
||||
@@ -244,23 +245,33 @@ var db = require('./database'),
|
||||
|
||||
|
||||
Messaging.getRecentChats = function(uid, start, stop, callback) {
|
||||
db.getSortedSetRevRange('uid:' + uid + ':chats', start, stop, function(err, uids) {
|
||||
db.getSortedSetRevRange('uid:' + uid + ':chat:rooms', start, stop, function(err, roomIds) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.parallel({
|
||||
unread: function(next) {
|
||||
db.isSortedSetMembers('uid:' + uid + ':chats:unread', uids, next);
|
||||
db.isSortedSetMembers('uid:' + uid + ':chat:rooms:unread', roomIds, next);
|
||||
},
|
||||
users: function(next) {
|
||||
async.map(roomIds, function(roomId, next) {
|
||||
db.getSortedSetRevRange('chat:room:' + roomId + ':uids', 0, 3, function(err, uids) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
uids = uids.filter(function(value, index, array) {
|
||||
return value && parseInt(value, 10) !== parseInt(uid, 10);
|
||||
});
|
||||
user.getUsersFields(uids, ['uid', 'username', 'picture', 'status', 'lastonline'] , next);
|
||||
});
|
||||
}, next);
|
||||
},
|
||||
teasers: function(next) {
|
||||
async.map(uids, function(fromuid, next) {
|
||||
async.map(roomIds, function(roomId, next) {
|
||||
Messaging.getMessages({
|
||||
fromuid: fromuid,
|
||||
touid: uid,
|
||||
uid: uid,
|
||||
roomId: roomId,
|
||||
isNew: false,
|
||||
count: 1,
|
||||
markRead: false
|
||||
@@ -275,20 +286,25 @@ var db = require('./database'),
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
results.users.forEach(function(userData, index) {
|
||||
var rooms = results.users.map(function(users, index) {
|
||||
var data = {
|
||||
users: users,
|
||||
unread: results.unread[index],
|
||||
roomId: roomIds[index],
|
||||
teaser: results.teasers[index]
|
||||
};
|
||||
data.users.forEach(function(userData) {
|
||||
if (userData && parseInt(userData.uid, 10)) {
|
||||
userData.unread = results.unread[index];
|
||||
userData.status = user.getStatus(userData);
|
||||
userData.teaser = results.teasers[index];
|
||||
}
|
||||
});
|
||||
|
||||
results.users = results.users.filter(function(user) {
|
||||
data.users = data.users.filter(function(user) {
|
||||
return user && parseInt(user.uid, 10);
|
||||
});
|
||||
return data;
|
||||
});
|
||||
|
||||
callback(null, {users: results.users, nextStart: stop + 1});
|
||||
callback(null, {rooms: rooms, nextStart: stop + 1});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -95,7 +95,7 @@ module.exports = function(Messaging) {
|
||||
], next);
|
||||
},
|
||||
function (results, next) {
|
||||
getMessages([mid], fromuid, touid, true, next);
|
||||
Messaging.getMessagesData([mid], fromuid, touid, true, next);
|
||||
},
|
||||
function (messages, next) {
|
||||
Messaging.isNewSet(fromuid, touid, mid, next);
|
||||
@@ -119,7 +119,7 @@ module.exports = function(Messaging) {
|
||||
var keys = uids.map(function(uid) {
|
||||
return 'uid:' + uid + ':chat:rooms';
|
||||
});
|
||||
db.sortedSetsAdd(keys, timestamp, roomId, next);
|
||||
db.sortedSetsAdd(keys, timestamp, roomId, callback);
|
||||
};
|
||||
|
||||
Messaging.addMessageToUsers = function(roomId, uids, mid, timestamp, callback) {
|
||||
|
||||
@@ -43,4 +43,5 @@ module.exports = function(Messaging) {
|
||||
Messaging.getUidsInRoom = function(roomId, start, stop, callback) {
|
||||
db.getSortedSetRange('chat:room:' + roomId + ':uids', start, stop, callback);
|
||||
};
|
||||
|
||||
};
|
||||
@@ -57,7 +57,12 @@ module.exports = function(app, middleware, controllers) {
|
||||
});
|
||||
|
||||
router.get('/test', function(req, res) {
|
||||
res.redirect(404);
|
||||
//res.redirect(404);
|
||||
var messaging = require('../messaging');
|
||||
|
||||
messaging.getRecentChats(1, 0, 9, function(err, data) {
|
||||
res.json(data);
|
||||
})
|
||||
});
|
||||
|
||||
app.use(nconf.get('relative_path') + '/debug', router);
|
||||
|
||||
@@ -22,14 +22,13 @@ SocketModules.chats.get = function(socket, data, callback) {
|
||||
}
|
||||
|
||||
Messaging.getMessages({
|
||||
fromuid: socket.uid,
|
||||
touid: data.touid,
|
||||
uid: socket.uid,
|
||||
roomId: data.roomId,
|
||||
since: data.since,
|
||||
isNew: false
|
||||
}, callback);
|
||||
|
||||
// Mark chat as read
|
||||
Messaging.markRead(socket.uid, data.touid);
|
||||
Messaging.markRead(socket.uid, data.roomId);
|
||||
};
|
||||
|
||||
SocketModules.chats.getRaw = function(socket, data, callback) {
|
||||
|
||||
Reference in New Issue
Block a user