notifications.js style

v1.18.x
Barış Soner Uşaklı 8 years ago
parent f3deef4931
commit b18b0db5be

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

@ -48,7 +48,7 @@ start.start = function () {
require('./socket.io').init(webserver.server); require('./socket.io').init(webserver.server);
if (nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')) { if (nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')) {
require('./notifications').init(); require('./notifications').startJobs();
require('./user').startJobs(); require('./user').startJobs();
} }

Loading…
Cancel
Save