From 5c01c7b1c7826bfc5324f9bf57b3418bc92c87cd Mon Sep 17 00:00:00 2001
From: barisusakli <barisusakli@gmail.com>
Date: Wed, 22 Feb 2017 13:34:57 +0300
Subject: [PATCH] delayed notification test

---
 src/messaging/notifications.js | 166 +++++++++++++++++----------------
 test/messaging.js              |  22 +++++
 2 files changed, 107 insertions(+), 81 deletions(-)

diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js
index 6d9500c4ba..2eeb562b5c 100644
--- a/src/messaging/notifications.js
+++ b/src/messaging/notifications.js
@@ -14,71 +14,75 @@ module.exports = function (Messaging) {
 
 	Messaging.notifyQueue = {};	// Only used to notify a user of a new chat message, see Messaging.notifyUser
 
-	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);
-			});
+	Messaging.notificationSendDelay = 1000 * 60;
 
-			// 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] = {
+	Messaging.notifyUsersInRoom = function (fromUid, roomId, messageObj) {
+		async.waterfall([
+			function (next) {
+				Messaging.getUidsInRoom(roomId, 0, -1, next);
+			},
+			function (uids, next) {
+				var data = {
+					roomId: roomId,
+					fromUid: fromUid,
 					message: messageObj
 				};
-			}
 
-			queueObj.timeout = setTimeout(function () {
-				sendNotifications(fromUid, uids, roomId, queueObj.message, function (err) {
-					if (!err) {
-						delete Messaging.notifyQueue[fromUid + ':' + roomId];
-					}
+				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);
 				});
-			}, 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] && parseInt(fromuid, 10) !== parseInt(uid, 10);
-			});
+				// 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
+					};
+				}
 
-			if (!uids.length) {
-				return callback();
+				queueObj.timeout = setTimeout(function () {
+					sendNotifications(fromUid, uids, roomId, queueObj.message);
+				}, Messaging.notificationSendDelay);
+				next();
 			}
+		]);
+	};
 
-			notifications.create({
-				bodyShort: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
-				bodyLong: messageObj.content,
-				nid: 'chat_' + fromuid + '_' + roomId,
-				from: fromuid,
-				path: '/chats/' + messageObj.roomId
-			}, function (err, notification) {
-				if (!err && notification) {
-					notifications.push(notification, uids, callback);
+	function sendNotifications(fromuid, uids, roomId, messageObj) {
+		async.waterfall([
+			function (next) {
+				user.isOnline(uids, next);
+			},
+			function (isOnline, next) {
+				uids = uids.filter(function (uid, index) {
+					return !isOnline[index] && parseInt(fromuid, 10) !== parseInt(uid, 10);
+				});
+
+				if (!uids.length) {
+					return;
 				}
-			});
 
-			sendNotificationEmails(uids, messageObj);
+				notifications.create({
+					bodyShort: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
+					bodyLong: messageObj.content,
+					nid: 'chat_' + fromuid + '_' + roomId,
+					from: fromuid,
+					path: '/chats/' + messageObj.roomId
+				}, next);
+			}
+		], function (err, notification) {
+			if (!err) {
+				delete Messaging.notifyQueue[fromuid + ':' + roomId];
+				if (notification) {
+					notifications.push(notification, uids);
+				}
+				sendNotificationEmails(uids, messageObj);
+			}
 		});
 	}
 
@@ -87,38 +91,38 @@ module.exports = function (Messaging) {
 			return;
 		}
 
-		async.parallel({
-			userData: function (next) {
-				user.getUsersFields(uids, ['uid', 'username', 'userslug'], next);
+		async.waterfall([
+			function (next) {
+				async.parallel({
+					userData: function (next) {
+						user.getUsersFields(uids, ['uid', 'username', 'userslug'], next);
+					},
+					userSettings: function (next) {
+						user.getMultipleUserSettings(uids, next);
+					}
+				}, next);
 			},
-			userSettings: function (next) {
-				user.getMultipleUserSettings(uids, next);
+			function (results, next) {
+				results.userData = results.userData.filter(function (userData, index) {
+					return userData && results.userSettings[index] && results.userSettings[index].sendChatNotifications;
+				});
+				async.each(results.userData, function (userData, next) {
+					emailer.send('notif_chat', userData.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'),
+						roomId: messageObj.roomId,
+						username: userData.username,
+						userslug: userData.userslug
+					}, next);
+				}, next);
 			}
-		}, function (err, results) {
+		], function (err) {
 			if (err) {
 				return winston.error(err);
 			}
-
-			results.userData = results.userData.filter(function (userData, index) {
-				return userData && results.userSettings[index] && results.userSettings[index].sendChatNotifications;
-			});
-
-			async.each(results.userData, function (userData, next) {
-				emailer.send('notif_chat', userData.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'),
-					roomId: messageObj.roomId,
-					username: userData.username,
-					userslug: userData.userslug
-				}, next);
-			}, function (err) {
-				if (err) {
-					winston.error(err);
-				}
-			});
 		});
 	}
 };
\ No newline at end of file
diff --git a/test/messaging.js b/test/messaging.js
index a60504544b..12922f9e1d 100644
--- a/test/messaging.js
+++ b/test/messaging.js
@@ -121,6 +121,28 @@ describe('Messaging Library', function () {
 			});
 		});
 
+		it('should notify offline users of message', function (done) {
+			Messaging.notificationSendDelay = 100;
+
+			db.sortedSetAdd('users:online', Date.now() - 350000, herpUid, function (err) {
+				assert.ifError(err);
+				socketModules.chats.send({uid: fooUid}, {roomId: roomId, message: 'second chat message'}, function (err) {
+					assert.ifError(err);
+					setTimeout(function () {
+						User.notifications.get(herpUid, function (err, data) {
+							assert.ifError(err);
+							assert(data.unread[0]);
+							var notification = data.unread[0];
+							assert.equal(notification.bodyShort, '[[notifications:new_message_from, foo]]');
+							assert.equal(notification.nid, 'chat_' + fooUid + '_' + roomId);
+							assert.equal(notification.path, '/chats/' + roomId);
+							done();
+						});
+					}, 1500);
+				});
+			});
+		});
+
 		it('should get messages from room', function (done) {
 			socketModules.chats.getMessages({uid: fooUid}, {
 				uid: fooUid,