mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-02 03:55:55 +01:00
chat notify changes
This commit is contained in:
116
src/messaging.js
116
src/messaging.js
@@ -4,17 +4,15 @@
|
||||
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'),
|
||||
sockets = require('./socket.io');
|
||||
userNotifications = require('./user/notifications');
|
||||
|
||||
(function(Messaging) {
|
||||
|
||||
@@ -23,6 +21,7 @@ var async = require('async'),
|
||||
require('./messaging/edit')(Messaging);
|
||||
require('./messaging/rooms')(Messaging);
|
||||
require('./messaging/unread')(Messaging);
|
||||
require('./messaging/notifications')(Messaging);
|
||||
|
||||
Messaging.notifyQueue = {}; // Only used to notify a user of a new chat message, see Messaging.notifyUser
|
||||
|
||||
@@ -309,46 +308,50 @@ var async = require('async'),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
Messaging.notifyUser = function(uid, roomId, messageObj) {
|
||||
// Immediate notifications
|
||||
// Recipient
|
||||
Messaging.pushUnreadCount(touid);
|
||||
sockets.in('uid_' + touid).emit('event:chats.receive', {
|
||||
withUid: fromuid,
|
||||
message: messageObj,
|
||||
self: 0
|
||||
});
|
||||
// Sender
|
||||
Messaging.pushUnreadCount(fromuid);
|
||||
sockets.in('uid_' + fromuid).emit('event:chats.receive', {
|
||||
withUid: touid,
|
||||
message: messageObj,
|
||||
self: 1
|
||||
});
|
||||
|
||||
// Delayed notifications
|
||||
var queueObj = Messaging.notifyQueue[fromuid + ':' + touid];
|
||||
if (queueObj) {
|
||||
queueObj.message.content += '\n' + messageObj.content;
|
||||
clearTimeout(queueObj.timeout);
|
||||
} else {
|
||||
queueObj = Messaging.notifyQueue[fromuid + ':' + touid] = {
|
||||
message: messageObj
|
||||
};
|
||||
Messaging.canMessageUser = function(uid, toUid, callback) {
|
||||
if (parseInt(meta.config.disableChat) === 1 || !uid || uid === toUid) {
|
||||
return callback(null, false);
|
||||
}
|
||||
|
||||
queueObj.timeout = setTimeout(function() {
|
||||
sendNotifications(fromuid, touid, queueObj.message, function(err) {
|
||||
if (!err) {
|
||||
delete Messaging.notifyQueue[fromuid + ':' + touid];
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.exists(toUid, next);
|
||||
},
|
||||
function (exists, next) {
|
||||
if (!exists) {
|
||||
return callback(null, false);
|
||||
}
|
||||
});
|
||||
}, 1000*60); // wait 60s before sending
|
||||
user.getUserFields(uid, ['banned', 'email:confirmed'], next);
|
||||
},
|
||||
function (userData, next) {
|
||||
if (parseInt(userData.banned, 10) === 1) {
|
||||
return callback(null, false);
|
||||
}
|
||||
|
||||
if (parseInt(meta.config.requireEmailConfirmation, 10) === 1 && parseInt(userData['email:confirmed'], 10) !== 1) {
|
||||
return callback(null, false);
|
||||
}
|
||||
|
||||
user.getSettings(toUid, next);
|
||||
},
|
||||
function(settings, next) {
|
||||
if (!settings.restrictChat) {
|
||||
return callback(null, true);
|
||||
}
|
||||
|
||||
user.isAdministrator(uid, next);
|
||||
},
|
||||
function(isAdmin, next) {
|
||||
if (isAdmin) {
|
||||
return callback(null, true);
|
||||
}
|
||||
user.isFollowing(toUid, uid, next);
|
||||
}
|
||||
], callback);
|
||||
|
||||
};
|
||||
|
||||
Messaging.canMessage = function(uid, roomId, callback) {
|
||||
Messaging.canMessageRoom = function(uid, roomId, callback) {
|
||||
if (parseInt(meta.config.disableChat) === 1 || !uid) {
|
||||
return callback(null, false);
|
||||
}
|
||||
@@ -378,39 +381,4 @@ var async = require('async'),
|
||||
};
|
||||
|
||||
|
||||
function sendNotifications(fromuid, touid, messageObj, callback) {
|
||||
user.isOnline(touid, function(err, isOnline) {
|
||||
if (err || isOnline) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
notifications.create({
|
||||
bodyShort: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
|
||||
bodyLong: messageObj.content,
|
||||
nid: 'chat_' + fromuid + '_' + touid,
|
||||
from: fromuid,
|
||||
path: '/chats/' + messageObj.fromUser.username
|
||||
}, function(err, notification) {
|
||||
if (!err && notification) {
|
||||
notifications.push(notification, [touid], callback);
|
||||
}
|
||||
});
|
||||
|
||||
user.getSettings(messageObj.toUser.uid, function(err, settings) {
|
||||
if (settings.sendChatNotifications && !parseInt(meta.config.disableEmailSubscriptions, 10)) {
|
||||
emailer.send('notif_chat', touid, {
|
||||
subject: '[[email:notif.chat.subject, ' + messageObj.fromUser.username + ']]',
|
||||
username: messageObj.toUser.username,
|
||||
userslug: utils.slugify(messageObj.toUser.username),
|
||||
summary: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
|
||||
message: messageObj,
|
||||
site_title: meta.config.title || 'NodeBB',
|
||||
url: nconf.get('url'),
|
||||
fromUserslug: utils.slugify(messageObj.fromUser.username)
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}(exports));
|
||||
|
||||
@@ -106,6 +106,7 @@ module.exports = function(Messaging) {
|
||||
|
||||
results.messages[0].newSet = results.isNewSet;
|
||||
results.messages[0].mid = mid;
|
||||
results.messages[0].roomId = roomId;
|
||||
next(null, results.messages[0]);
|
||||
}
|
||||
], callback);
|
||||
|
||||
104
src/messaging/notifications.js
Normal file
104
src/messaging/notifications.js
Normal file
@@ -0,0 +1,104 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var nconf = require('nconf');
|
||||
|
||||
var user = require('../user');
|
||||
var emailer = require('../emailer');
|
||||
var notifications = require('./notifications');
|
||||
var meta = require('../meta');
|
||||
var utils = require('../../public/src/utils');
|
||||
var sockets = require('../socket.io');
|
||||
|
||||
module.exports = function(Messaging) {
|
||||
|
||||
Messaging.notifyUsersInRoom = function(fromUid, roomId, messageObj) {
|
||||
Messaging.getUidsInRoom(roomId, 0, -1, function(err, uids) {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
var data = {
|
||||
roomId: roomId,
|
||||
fromUid: fromUid,
|
||||
message: messageObj
|
||||
};
|
||||
uids.forEach(function(uid) {
|
||||
data.self = parseInt(uid, 10) === parseInt(fromUid) ? 1 : 0;
|
||||
Messaging.pushUnreadCount(uid);
|
||||
sockets.in('uid_' + uid).emit('event:chats.receive', data);
|
||||
});
|
||||
|
||||
// Delayed notifications
|
||||
var queueObj = Messaging.notifyQueue[fromUid + ':' + roomId];
|
||||
if (queueObj) {
|
||||
queueObj.message.content += '\n' + messageObj.content;
|
||||
clearTimeout(queueObj.timeout);
|
||||
} else {
|
||||
queueObj = Messaging.notifyQueue[fromUid + ':' + roomId] = {
|
||||
message: messageObj
|
||||
};
|
||||
}
|
||||
|
||||
queueObj.timeout = setTimeout(function() {
|
||||
sendNotifications(fromUid, uids, roomId, queueObj.message, function(err) {
|
||||
if (!err) {
|
||||
delete Messaging.notifyQueue[fromUid + ':' + roomId];
|
||||
}
|
||||
});
|
||||
}, 1000*60); // wait 60s before sending
|
||||
});
|
||||
};
|
||||
|
||||
function sendNotifications(fromuid, uids, roomId, messageObj, callback) {
|
||||
user.isOnline(uids, function(err, isOnline) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
uids = uids.filter(function(uid, index) {
|
||||
return isOnline[index];
|
||||
});
|
||||
|
||||
if (!uids.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
notifications.create({
|
||||
bodyShort: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
|
||||
bodyLong: messageObj.content,
|
||||
nid: 'chat_' + fromuid + '_' + roomId,
|
||||
from: fromuid,
|
||||
path: '/chats/' + messageObj.fromUser.username
|
||||
}, function(err, notification) {
|
||||
if (!err && notification) {
|
||||
notifications.push(notification, uids, callback);
|
||||
}
|
||||
});
|
||||
|
||||
if (parseInt(meta.config.disableEmailSubscriptions, 10) === 1) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
user.getMultipleUserSettings(uids, function(err, userSettings) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
userSettings = userSettings.filter(function(settings) {
|
||||
return settings && settings.sendChatNotifications;
|
||||
});
|
||||
async.each(userSettings, function(settings, next) {
|
||||
emailer.send('notif_chat', settings.uid, {
|
||||
subject: '[[email:notif.chat.subject, ' + messageObj.fromUser.username + ']]',
|
||||
summary: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
|
||||
message: messageObj,
|
||||
site_title: meta.config.title || 'NodeBB',
|
||||
url: nconf.get('url'),
|
||||
fromUserslug: utils.slugify(messageObj.fromUser.username)
|
||||
}, next);
|
||||
}, callback);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -39,6 +39,36 @@ SocketModules.chats.getRaw = function(socket, data, callback) {
|
||||
Messaging.getMessageField(data.mid, 'content', callback);
|
||||
};
|
||||
|
||||
SocketModules.chats.newMessage = function(socket, data, callback) {
|
||||
if (!data) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
var now = Date.now();
|
||||
// Websocket rate limiting
|
||||
socket.lastChatMessageTime = socket.lastChatMessageTime || 0;
|
||||
if (now - socket.lastChatMessageTime < 200) {
|
||||
return callback(new Error('[[error:too-many-messages]]'));
|
||||
} else {
|
||||
socket.lastChatMessageTime = now;
|
||||
}
|
||||
|
||||
Messaging.canMessageUser(socket.uid, data.touid, function(err, allowed) {
|
||||
if (err || !allowed) {
|
||||
return callback(err || new Error('[[error:chat-restricted]]'));
|
||||
}
|
||||
|
||||
Messaging.newMessage(socket.uid, [data.touid], data.content, now, function(err, message) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
Messaging.notifyUsersInRoom(socket.uid, message.roomId, message);
|
||||
|
||||
callback();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
SocketModules.chats.send = function(socket, data, callback) {
|
||||
if (!data || !data.roomId) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
@@ -54,7 +84,7 @@ SocketModules.chats.send = function(socket, data, callback) {
|
||||
socket.lastChatMessageTime = now;
|
||||
}
|
||||
|
||||
Messaging.canMessage(socket.uid, data.roomId, function(err, allowed) {
|
||||
Messaging.canMessageRoom(socket.uid, data.roomId, function(err, allowed) {
|
||||
if (err || !allowed) {
|
||||
return callback(err || new Error('[[error:chat-restricted]]'));
|
||||
}
|
||||
@@ -64,7 +94,7 @@ SocketModules.chats.send = function(socket, data, callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
Messaging.notifyUser(socket.uid, data.roomId, message);
|
||||
Messaging.notifyUsersInRoom(socket.uid, data.roomId, message);
|
||||
|
||||
callback();
|
||||
});
|
||||
@@ -95,7 +125,7 @@ SocketModules.chats.delete = function(socket, data, callback) {
|
||||
Messaging.deleteMessage(data.messageId, data.roomId, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
SocketModules.chats.canMessage = function(socket, roomId, callback) {
|
||||
Messaging.canMessage(socket.uid, roomId, function(err, allowed) {
|
||||
|
||||
28
src/user.js
28
src/user.js
@@ -132,13 +132,27 @@ var async = require('async'),
|
||||
};
|
||||
|
||||
User.isOnline = function(uid, callback) {
|
||||
db.sortedSetScore('users:online', uid, function(err, lastonline) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
var isOnline = Date.now() - parseInt(lastonline, 10) < 300000;
|
||||
callback(null, isOnline);
|
||||
});
|
||||
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);
|
||||
});
|
||||
} else {
|
||||
db.sortedSetScore('users:online', uid, function(err, lastonline) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
var isOnline = Date.now() - parseInt(lastonline, 10) < 300000;
|
||||
callback(null, isOnline);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
User.exists = function(uid, callback) {
|
||||
|
||||
Reference in New Issue
Block a user