diff --git a/src/notifications.js b/src/notifications.js index 9034fc54c8..bb002238e6 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -15,500 +15,499 @@ var batch = require('./batch'); var plugins = require('./plugins'); var utils = require('./utils'); -(function (Notifications) { - Notifications.init = function () { - winston.verbose('[notifications.init] Registering jobs.'); - new cron('*/30 * * * *', Notifications.prune, null, true); - }; - - Notifications.get = function (nid, callback) { - Notifications.getMultiple([nid], function (err, notifications) { - callback(err, Array.isArray(notifications) && notifications.length ? notifications[0] : null); - }); - }; +var Notifications = module.exports; + +Notifications.startJobs = function () { + winston.verbose('[notifications.init] Registering jobs.'); + new cron('*/30 * * * *', Notifications.prune, null, true); +}; + +Notifications.get = function (nid, callback) { + Notifications.getMultiple([nid], function (err, notifications) { + callback(err, Array.isArray(notifications) && notifications.length ? notifications[0] : null); + }); +}; + +Notifications.getMultiple = function (nids, callback) { + if (!nids.length) { + return setImmediate(callback, null, []); + } + var keys = nids.map(function (nid) { + return 'notifications:' + nid; + }); + + var notifications; + + async.waterfall([ + function (next) { + db.getObjects(keys, next); + }, + function (_notifications, next) { + notifications = _notifications; + var userKeys = notifications.map(function (notification) { + return notification && notification.from; + }); - Notifications.getMultiple = function (nids, callback) { - if (!nids.length) { - return setImmediate(callback, null, []); - } - var keys = nids.map(function (nid) { - return 'notifications:' + nid; - }); + User.getUsersFields(userKeys, ['username', 'userslug', 'picture'], next); + }, + function (usersData, next) { + notifications.forEach(function (notification, index) { + if (notification) { + notification.datetimeISO = utils.toISOString(notification.datetime); - var notifications; + if (notification.bodyLong) { + notification.bodyLong = S(notification.bodyLong).escapeHTML().s; + } - async.waterfall([ - function (next) { - db.getObjects(keys, next); - }, - function (_notifications, next) { - notifications = _notifications; - var userKeys = notifications.map(function (notification) { - return notification && notification.from; - }); + notification.user = usersData[index]; + if (notification.user) { + notification.image = notification.user.picture || null; + if (notification.user.username === '[[global:guest]]') { + notification.bodyShort = notification.bodyShort.replace(/([\s\S]*?),[\s\S]*?,([\s\S]*?)/, '$1, [[global:guest]], $2'); + } + } else if (notification.image === 'brand:logo' || !notification.image) { + notification.image = meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png'; + } + } + }); - User.getUsersFields(userKeys, ['username', 'userslug', 'picture'], next); - }, - function (usersData, next) { - notifications.forEach(function (notification, index) { - if (notification) { - notification.datetimeISO = utils.toISOString(notification.datetime); + next(null, notifications); + }, + ], callback); +}; + +Notifications.filterExists = function (nids, callback) { + async.waterfall([ + function (next) { + db.isSortedSetMembers('notifications', nids, next); + }, + function (exists, next) { + nids = nids.filter(function (notifId, idx) { + return exists[idx]; + }); - if (notification.bodyLong) { - notification.bodyLong = S(notification.bodyLong).escapeHTML().s; - } + next(null, nids); + }, + ], callback); +}; - notification.user = usersData[index]; - if (notification.user) { - notification.image = notification.user.picture || null; - if (notification.user.username === '[[global:guest]]') { - notification.bodyShort = notification.bodyShort.replace(/([\s\S]*?),[\s\S]*?,([\s\S]*?)/, '$1, [[global:guest]], $2'); - } - } else if (notification.image === 'brand:logo' || !notification.image) { - notification.image = meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png'; - } - } - }); +Notifications.findRelated = function (mergeIds, set, callback) { + // A related notification is one in a zset that has the same mergeId + var _nids; - next(null, notifications); - }, - ], callback); - }; + async.waterfall([ + async.apply(db.getSortedSetRevRange, set, 0, -1), + function (nids, next) { + _nids = nids; - Notifications.filterExists = function (nids, callback) { - async.waterfall([ - function (next) { - db.isSortedSetMembers('notifications', nids, next); - }, - function (exists, next) { - nids = nids.filter(function (notifId, idx) { - return exists[idx]; - }); + var keys = nids.map(function (nid) { + return 'notifications:' + nid; + }); - next(null, nids); - }, - ], callback); - }; + db.getObjectsFields(keys, ['mergeId'], next); + }, + ], function (err, sets) { + if (err) { + return callback(err); + } - Notifications.findRelated = function (mergeIds, set, callback) { - // A related notification is one in a zset that has the same mergeId - var _nids; + sets = sets.map(function (set) { + return set.mergeId; + }); - async.waterfall([ - async.apply(db.getSortedSetRevRange, set, 0, -1), - function (nids, next) { - _nids = nids; + callback(null, _nids.filter(function (nid, idx) { + return mergeIds.indexOf(sets[idx]) !== -1; + })); + }); +}; - var keys = nids.map(function (nid) { - return 'notifications:' + nid; - }); +Notifications.create = function (data, callback) { + if (!data.nid) { + return callback(new Error('no-notification-id')); + } + data.importance = data.importance || 5; + db.getObject('notifications:' + data.nid, function (err, oldNotification) { + if (err) { + return callback(err); + } - db.getObjectsFields(keys, ['mergeId'], next); - }, - ], function (err, sets) { - if (err) { - return callback(err); + if (oldNotification) { + if (parseInt(oldNotification.pid, 10) === parseInt(data.pid, 10) && parseInt(oldNotification.importance, 10) > parseInt(data.importance, 10)) { + return callback(null, null); } + } - sets = sets.map(function (set) { - return set.mergeId; - }); - - callback(null, _nids.filter(function (nid, idx) { - return mergeIds.indexOf(sets[idx]) !== -1; - })); + var now = Date.now(); + data.datetime = now; + async.parallel([ + function (next) { + db.sortedSetAdd('notifications', now, data.nid, next); + }, + function (next) { + db.setObject('notifications:' + data.nid, data, next); + }, + ], function (err) { + callback(err, data); }); - }; + }); +}; - Notifications.create = function (data, callback) { - if (!data.nid) { - return callback(new Error('no-notification-id')); - } - data.importance = data.importance || 5; - db.getObject('notifications:' + data.nid, function (err, oldNotification) { - if (err) { - return callback(err); - } +Notifications.push = function (notification, uids, callback) { + callback = callback || function () {}; - if (oldNotification) { - if (parseInt(oldNotification.pid, 10) === parseInt(data.pid, 10) && parseInt(oldNotification.importance, 10) > parseInt(data.importance, 10)) { - return callback(null, null); - } - } + if (!notification || !notification.nid) { + return callback(); + } - var now = Date.now(); - data.datetime = now; - async.parallel([ - function (next) { - db.sortedSetAdd('notifications', now, data.nid, next); - }, - function (next) { - db.setObject('notifications:' + data.nid, data, next); - }, - ], function (err) { - callback(err, data); - }); + if (!Array.isArray(uids)) { + uids = [uids]; + } + + uids = uids.filter(function (uid, index, array) { + return parseInt(uid, 10) && array.indexOf(uid) === index; + }); + + if (!uids.length) { + return callback(); + } + + setTimeout(function () { + batch.processArray(uids, function (uids, next) { + pushToUids(uids, notification, next); + }, { interval: 1000 }, function (err) { + if (err) { + winston.error(err.stack); + } }); - }; + }, 1000); + + callback(); +}; + +function pushToUids(uids, notification, callback) { + var oneWeekAgo = Date.now() - 604800000; + var unreadKeys = []; + var readKeys = []; + + async.waterfall([ + function (next) { + plugins.fireHook('filter:notification.push', { notification: notification, uids: uids }, next); + }, + function (data, next) { + uids = data.uids; + notification = data.notification; + + uids.forEach(function (uid) { + unreadKeys.push('uid:' + uid + ':notifications:unread'); + readKeys.push('uid:' + uid + ':notifications:read'); + }); - Notifications.push = function (notification, uids, callback) { - callback = callback || function () {}; + db.sortedSetsAdd(unreadKeys, notification.datetime, notification.nid, next); + }, + function (next) { + db.sortedSetsRemove(readKeys, notification.nid, next); + }, + function (next) { + db.sortedSetsRemoveRangeByScore(unreadKeys, '-inf', oneWeekAgo, next); + }, + function (next) { + db.sortedSetsRemoveRangeByScore(readKeys, '-inf', oneWeekAgo, next); + }, + function (next) { + var websockets = require('./socket.io'); + if (websockets.server) { + uids.forEach(function (uid) { + websockets.in('uid_' + uid).emit('event:new_notification', notification); + }); + } - if (!notification || !notification.nid) { - return callback(); + plugins.fireHook('action:notification.pushed', { notification: notification, uids: uids }); + next(); + }, + ], callback); +} + +Notifications.pushGroup = function (notification, groupName, callback) { + callback = callback || function () {}; + groups.getMembers(groupName, 0, -1, function (err, members) { + if (err || !Array.isArray(members) || !members.length) { + return callback(err); } - if (!Array.isArray(uids)) { - uids = [uids]; + Notifications.push(notification, members, callback); + }); +}; + +Notifications.pushGroups = function (notification, groupNames, callback) { + callback = callback || function () {}; + groups.getMembersOfGroups(groupNames, function (err, groupMembers) { + if (err) { + return callback(err); } - uids = uids.filter(function (uid, index, array) { - return parseInt(uid, 10) && array.indexOf(uid) === index; - }); + var members = _.unique(_.flatten(groupMembers)); - if (!uids.length) { - return callback(); - } + Notifications.push(notification, members, callback); + }); +}; - setTimeout(function () { - batch.processArray(uids, function (uids, next) { - pushToUids(uids, notification, next); - }, { interval: 1000 }, function (err) { - if (err) { - winston.error(err.stack); - } - }); - }, 1000); +Notifications.rescind = function (nid, callback) { + callback = callback || function () {}; - callback(); - }; + async.parallel([ + async.apply(db.sortedSetRemove, 'notifications', nid), + async.apply(db.delete, 'notifications:' + nid), + ], function (err) { + if (err) { + winston.error('Encountered error rescinding notification (' + nid + '): ' + err.message); + } else { + winston.verbose('[notifications/rescind] Rescinded notification "' + nid + '"'); + } - function pushToUids(uids, notification, callback) { - var oneWeekAgo = Date.now() - 604800000; - var unreadKeys = []; - var readKeys = []; + callback(err, nid); + }); +}; - async.waterfall([ - function (next) { - plugins.fireHook('filter:notification.push', { notification: notification, uids: uids }, next); - }, - function (data, next) { - uids = data.uids; - notification = data.notification; +Notifications.markRead = function (nid, uid, callback) { + callback = callback || function () {}; + if (!parseInt(uid, 10) || !nid) { + return callback(); + } + Notifications.markReadMultiple([nid], uid, callback); +}; - uids.forEach(function (uid) { - unreadKeys.push('uid:' + uid + ':notifications:unread'); - readKeys.push('uid:' + uid + ':notifications:read'); - }); +Notifications.markUnread = function (nid, uid, callback) { + callback = callback || function () {}; + if (!parseInt(uid, 10) || !nid) { + return callback(); + } - db.sortedSetsAdd(unreadKeys, notification.datetime, notification.nid, next); - }, - function (next) { - db.sortedSetsRemove(readKeys, notification.nid, next); - }, - function (next) { - db.sortedSetsRemoveRangeByScore(unreadKeys, '-inf', oneWeekAgo, next); - }, - function (next) { - db.sortedSetsRemoveRangeByScore(readKeys, '-inf', oneWeekAgo, next); - }, - function (next) { - var websockets = require('./socket.io'); - if (websockets.server) { - uids.forEach(function (uid) { - websockets.in('uid_' + uid).emit('event:new_notification', notification); - }); - } + db.getObject('notifications:' + nid, function (err, notification) { + if (err || !notification) { + return callback(err || new Error('[[error:no-notification]]')); + } + notification.datetime = notification.datetime || Date.now(); - plugins.fireHook('action:notification.pushed', { notification: notification, uids: uids }); - next(); - }, + async.parallel([ + async.apply(db.sortedSetRemove, 'uid:' + uid + ':notifications:read', nid), + async.apply(db.sortedSetAdd, 'uid:' + uid + ':notifications:unread', notification.datetime, nid), ], callback); + }); +}; + +Notifications.markReadMultiple = function (nids, uid, callback) { + callback = callback || function () {}; + nids = nids.filter(Boolean); + if (!Array.isArray(nids) || !nids.length) { + return callback(); } - Notifications.pushGroup = function (notification, groupName, callback) { - callback = callback || function () {}; - groups.getMembers(groupName, 0, -1, function (err, members) { - if (err || !Array.isArray(members) || !members.length) { - return callback(err); - } + var notificationKeys = nids.map(function (nid) { + return 'notifications:' + nid; + }); - Notifications.push(notification, members, callback); - }); - }; + async.waterfall([ + async.apply(db.getObjectsFields, notificationKeys, ['mergeId']), + function (mergeIds, next) { + // Isolate mergeIds and find related notifications + mergeIds = mergeIds.map(function (set) { + return set.mergeId; + }).reduce(function (memo, mergeId, idx, arr) { + if (mergeId && idx === arr.indexOf(mergeId)) { + memo.push(mergeId); + } + return memo; + }, []); - Notifications.pushGroups = function (notification, groupNames, callback) { - callback = callback || function () {}; - groups.getMembersOfGroups(groupNames, function (err, groupMembers) { - if (err) { - return callback(err); - } + Notifications.findRelated(mergeIds, 'uid:' + uid + ':notifications:unread', next); + }, + function (relatedNids, next) { + notificationKeys = _.union(nids, relatedNids).map(function (nid) { + return 'notifications:' + nid; + }); + + db.getObjectsFields(notificationKeys, ['nid', 'datetime'], next); + }, + ], function (err, notificationData) { + if (err) { + return callback(err); + } - var members = _.unique(_.flatten(groupMembers)); + // Filter out notifications that didn't exist + notificationData = notificationData.filter(function (notification) { + return notification && notification.nid; + }); - Notifications.push(notification, members, callback); + // Extract nid + nids = notificationData.map(function (notification) { + return notification.nid; }); - }; - Notifications.rescind = function (nid, callback) { - callback = callback || function () {}; + var datetimes = notificationData.map(function (notification) { + return (notification && notification.datetime) || Date.now(); + }); async.parallel([ - async.apply(db.sortedSetRemove, 'notifications', nid), - async.apply(db.delete, 'notifications:' + nid), + function (next) { + db.sortedSetRemove('uid:' + uid + ':notifications:unread', nids, next); + }, + function (next) { + db.sortedSetAdd('uid:' + uid + ':notifications:read', datetimes, nids, next); + }, ], function (err) { - if (err) { - winston.error('Encountered error rescinding notification (' + nid + '): ' + err.message); - } else { - winston.verbose('[notifications/rescind] Rescinded notification "' + nid + '"'); - } - - callback(err, nid); + callback(err); }); - }; + }); +}; - Notifications.markRead = function (nid, uid, callback) { - callback = callback || function () {}; - if (!parseInt(uid, 10) || !nid) { - return callback(); +Notifications.markAllRead = function (uid, callback) { + db.getSortedSetRevRange('uid:' + uid + ':notifications:unread', 0, 99, function (err, nids) { + if (err) { + return callback(err); } - Notifications.markReadMultiple([nid], uid, callback); - }; - Notifications.markUnread = function (nid, uid, callback) { - callback = callback || function () {}; - if (!parseInt(uid, 10) || !nid) { + if (!Array.isArray(nids) || !nids.length) { return callback(); } - db.getObject('notifications:' + nid, function (err, notification) { - if (err || !notification) { - return callback(err || new Error('[[error:no-notification]]')); - } - notification.datetime = notification.datetime || Date.now(); + Notifications.markReadMultiple(nids, uid, callback); + }); +}; - async.parallel([ - async.apply(db.sortedSetRemove, 'uid:' + uid + ':notifications:read', nid), - async.apply(db.sortedSetAdd, 'uid:' + uid + ':notifications:unread', notification.datetime, nid), - ], callback); - }); - }; +Notifications.prune = function () { + var week = 604800000; + + var cutoffTime = Date.now() - week; + + db.getSortedSetRangeByScore('notifications', 0, 500, '-inf', cutoffTime, function (err, nids) { + if (err) { + return winston.error(err.message); + } - Notifications.markReadMultiple = function (nids, uid, callback) { - callback = callback || function () {}; - nids = nids.filter(Boolean); if (!Array.isArray(nids) || !nids.length) { - return callback(); + return; } - var notificationKeys = nids.map(function (nid) { + var keys = nids.map(function (nid) { return 'notifications:' + nid; }); - async.waterfall([ - async.apply(db.getObjectsFields, notificationKeys, ['mergeId']), - function (mergeIds, next) { - // Isolate mergeIds and find related notifications - mergeIds = mergeIds.map(function (set) { - return set.mergeId; - }).reduce(function (memo, mergeId, idx, arr) { - if (mergeId && idx === arr.indexOf(mergeId)) { - memo.push(mergeId); - } - return memo; - }, []); - - Notifications.findRelated(mergeIds, 'uid:' + uid + ':notifications:unread', next); + async.parallel([ + function (next) { + db.sortedSetRemove('notifications', nids, next); }, - function (relatedNids, next) { - notificationKeys = _.union(nids, relatedNids).map(function (nid) { - return 'notifications:' + nid; - }); - - db.getObjectsFields(notificationKeys, ['nid', 'datetime'], next); + function (next) { + db.deleteAll(keys, next); }, - ], function (err, notificationData) { + ], function (err) { if (err) { - return callback(err); + return winston.error('Encountered error pruning notifications: ' + err.message); } - - // Filter out notifications that didn't exist - notificationData = notificationData.filter(function (notification) { - return notification && notification.nid; - }); - - // Extract nid - nids = notificationData.map(function (notification) { - return notification.nid; - }); - - var datetimes = notificationData.map(function (notification) { - return (notification && notification.datetime) || Date.now(); - }); - - async.parallel([ - function (next) { - db.sortedSetRemove('uid:' + uid + ':notifications:unread', nids, next); - }, - function (next) { - db.sortedSetAdd('uid:' + uid + ':notifications:read', datetimes, nids, next); - }, - ], function (err) { - callback(err); - }); }); - }; - - Notifications.markAllRead = function (uid, callback) { - db.getSortedSetRevRange('uid:' + uid + ':notifications:unread', 0, 99, function (err, nids) { - if (err) { - return callback(err); + }); +}; + +Notifications.merge = function (notifications, callback) { + // When passed a set of notification objects, merge any that can be merged + var mergeIds = [ + 'notifications:upvoted_your_post_in', + 'notifications:user_started_following_you', + 'notifications:user_posted_to', + 'notifications:user_flagged_post_in', + 'notifications:user_flagged_user', + 'new_register', + ]; + var isolated; + var differentiators; + var differentiator; + var modifyIndex; + var set; + + notifications = mergeIds.reduce(function (notifications, mergeId) { + isolated = notifications.filter(function (notifObj) { + if (!notifObj || !notifObj.hasOwnProperty('mergeId')) { + return false; } - if (!Array.isArray(nids) || !nids.length) { - return callback(); - } - - Notifications.markReadMultiple(nids, uid, callback); + return notifObj.mergeId.split('|')[0] === mergeId; }); - }; - - Notifications.prune = function () { - var week = 604800000; - var cutoffTime = Date.now() - week; - - db.getSortedSetRangeByScore('notifications', 0, 500, '-inf', cutoffTime, function (err, nids) { - if (err) { - return winston.error(err.message); - } + if (isolated.length <= 1) { + return notifications; // Nothing to merge + } - if (!Array.isArray(nids) || !nids.length) { - return; + // Each isolated mergeId may have multiple differentiators, so process each separately + differentiators = isolated.reduce(function (cur, next) { + differentiator = next.mergeId.split('|')[1] || 0; + if (cur.indexOf(differentiator) === -1) { + cur.push(differentiator); } - var keys = nids.map(function (nid) { - return 'notifications:' + nid; - }); - - async.parallel([ - function (next) { - db.sortedSetRemove('notifications', nids, next); - }, - function (next) { - db.deleteAll(keys, next); - }, - ], function (err) { - if (err) { - return winston.error('Encountered error pruning notifications: ' + err.message); - } - }); - }); - }; - - Notifications.merge = function (notifications, callback) { - // When passed a set of notification objects, merge any that can be merged - var mergeIds = [ - 'notifications:upvoted_your_post_in', - 'notifications:user_started_following_you', - 'notifications:user_posted_to', - 'notifications:user_flagged_post_in', - 'notifications:user_flagged_user', - 'new_register', - ]; - var isolated; - var differentiators; - var differentiator; - var modifyIndex; - var set; - - notifications = mergeIds.reduce(function (notifications, mergeId) { - isolated = notifications.filter(function (notifObj) { - if (!notifObj || !notifObj.hasOwnProperty('mergeId')) { - return false; - } - - return notifObj.mergeId.split('|')[0] === mergeId; - }); + return cur; + }, []); - if (isolated.length <= 1) { - return notifications; // Nothing to merge + differentiators.forEach(function (differentiator) { + if (differentiator === 0 && differentiators.length === 1) { + set = isolated; + } else { + set = isolated.filter(function (notifObj) { + return notifObj.mergeId === (mergeId + '|' + differentiator); + }); } - // Each isolated mergeId may have multiple differentiators, so process each separately - differentiators = isolated.reduce(function (cur, next) { - differentiator = next.mergeId.split('|')[1] || 0; - if (cur.indexOf(differentiator) === -1) { - cur.push(differentiator); - } + modifyIndex = notifications.indexOf(set[0]); + if (modifyIndex === -1 || set.length === 1) { + return notifications; + } - return cur; - }, []); + switch (mergeId) { + // intentional fall-through + case 'notifications:upvoted_your_post_in': + case 'notifications:user_started_following_you': + case 'notifications:user_posted_to': + case 'notifications:user_flagged_post_in': + case 'notifications:user_flagged_user': + var usernames = set.map(function (notifObj) { + return notifObj && notifObj.user && notifObj.user.username; + }).filter(function (username, idx, array) { + return array.indexOf(username) === idx; + }); + var numUsers = usernames.length; - differentiators.forEach(function (differentiator) { - if (differentiator === 0 && differentiators.length === 1) { - set = isolated; - } else { - set = isolated.filter(function (notifObj) { - return notifObj.mergeId === (mergeId + '|' + differentiator); - }); - } + var title = S(notifications[modifyIndex].topicTitle || '').decodeHTMLEntities().s; + var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ','); + titleEscaped = titleEscaped ? (', ' + titleEscaped) : ''; - modifyIndex = notifications.indexOf(set[0]); - if (modifyIndex === -1 || set.length === 1) { - return notifications; + if (numUsers === 2) { + notifications[modifyIndex].bodyShort = '[[' + mergeId + '_dual, ' + usernames.join(', ') + titleEscaped + ']]'; + } else if (numUsers > 2) { + notifications[modifyIndex].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers - 1) + titleEscaped + ']]'; } - switch (mergeId) { - // intentional fall-through - case 'notifications:upvoted_your_post_in': - case 'notifications:user_started_following_you': - case 'notifications:user_posted_to': - case 'notifications:user_flagged_post_in': - case 'notifications:user_flagged_user': - var usernames = set.map(function (notifObj) { - return notifObj && notifObj.user && notifObj.user.username; - }).filter(function (username, idx, array) { - return array.indexOf(username) === idx; - }); - var numUsers = usernames.length; - - var title = S(notifications[modifyIndex].topicTitle || '').decodeHTMLEntities().s; - var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ','); - titleEscaped = titleEscaped ? (', ' + titleEscaped) : ''; - - if (numUsers === 2) { - notifications[modifyIndex].bodyShort = '[[' + mergeId + '_dual, ' + usernames.join(', ') + titleEscaped + ']]'; - } else if (numUsers > 2) { - notifications[modifyIndex].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers - 1) + titleEscaped + ']]'; - } + notifications[modifyIndex].path = set[set.length - 1].path; + break; - notifications[modifyIndex].path = set[set.length - 1].path; - break; + case 'new_register': + notifications[modifyIndex].bodyShort = '[[notifications:' + mergeId + '_multiple, ' + set.length + ']]'; + break; + } - case 'new_register': - notifications[modifyIndex].bodyShort = '[[notifications:' + mergeId + '_multiple, ' + set.length + ']]'; - break; + // Filter out duplicates + notifications = notifications.filter(function (notifObj, idx) { + if (!notifObj || !notifObj.mergeId) { + return true; } - // Filter out duplicates - notifications = notifications.filter(function (notifObj, idx) { - if (!notifObj || !notifObj.mergeId) { - return true; - } - - return !(notifObj.mergeId === (mergeId + (differentiator ? '|' + differentiator : '')) && idx !== modifyIndex); - }); + return !(notifObj.mergeId === (mergeId + (differentiator ? '|' + differentiator : '')) && idx !== modifyIndex); }); - - return notifications; - }, notifications); - - plugins.fireHook('filter:notifications.merge', { - notifications: notifications, - }, function (err, data) { - callback(err, data.notifications); }); - }; -}(exports)); + return notifications; + }, notifications); + + plugins.fireHook('filter:notifications.merge', { + notifications: notifications, + }, function (err, data) { + callback(err, data.notifications); + }); +}; diff --git a/src/start.js b/src/start.js index 2a6e53f507..8d4e465a55 100644 --- a/src/start.js +++ b/src/start.js @@ -48,7 +48,7 @@ start.start = function () { require('./socket.io').init(webserver.server); if (nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')) { - require('./notifications').init(); + require('./notifications').startJobs(); require('./user').startJobs(); }