part 1 of notif refactor

v1.18.x
barisusakli 11 years ago
parent 01f983e29c
commit 493d0dea1e

@ -71,6 +71,11 @@ define('notifications', ['sounds'], function(sound) {
Tinycon.setBubble(count);
};
function increaseNotifCount() {
var count = parseInt(notifIcon.attr('data-content'), 10) + 1;
updateNotifCount(count);
}
socket.emit('notifications.getCount', function(err, count) {
if (!err) {
updateNotifCount(count);
@ -79,7 +84,7 @@ define('notifications', ['sounds'], function(sound) {
}
});
socket.on('event:new_notification', function(notifData, notifCount) {
socket.on('event:new_notification', function(notifData) {
app.alert({
alert_id: 'new_notif',
title: '[[notifications:new_notification]]',
@ -93,10 +98,11 @@ define('notifications', ['sounds'], function(sound) {
ajaxify.refresh();
}
updateNotifCount(notifCount);
increaseNotifCount();
sound.play('notification');
});
socket.on('event:notifications.updateCount', function(count) {
updateNotifCount(count);
});

@ -480,7 +480,10 @@ accountsController.uploadPicture = function (req, res, next) {
};
accountsController.getNotifications = function(req, res, next) {
user.notifications.getAll(req.user.uid, 25, function(err, notifications) {
user.notifications.getAll(req.user.uid, 40, function(err, notifications) {
if (err) {
return next(err);
}
res.render('notifications', {
notifications: notifications
});

@ -7,6 +7,9 @@ module.exports = function(db, module) {
var helpers = module.helpers.level;
module.sortedSetAdd = function(key, score, value, callback) {
if (Array.isArray(score) && Array.isArray(value)) {
return sortedSetAddMulti(key, score, value, callback);
}
module.getListRange(key, 0, -1, function(err, set) {
set = set.filter(function(a) {return a.value !== value.toString();});
@ -20,6 +23,10 @@ module.exports = function(db, module) {
});
};
function sortedSetAddMulti(key, scores, values, callback) {
throw new Error('not implemented');
}
module.sortedSetsAdd = function(keys, score, value, callback) {
async.each(keys, function(key, next) {
module.sortedSetAdd(key, score, value, next);
@ -29,8 +36,11 @@ module.exports = function(db, module) {
};
module.sortedSetRemove = function(key, value, callback) {
if (!Array.isArray(value)) {
value = [value];
}
module.getListRange(key, 0, -1, function(err, set) {
set = set.filter(function(a) {return a.value !== value.toString();});
set = set.filter(function(a) { return value.indexOf(a) === -1;});
module.set(key, set, callback);
});
};

@ -7,6 +7,10 @@ module.exports = function(db, module) {
module.sortedSetAdd = function(key, score, value, callback) {
callback = callback || helpers.noop;
if (Array.isArray(score) && Array.isArray(value)) {
return sortedSetAddBulk(key, score, value, callback);
}
value = helpers.valueToString(value);
var data = {
score: parseInt(score, 10),
@ -18,6 +22,24 @@ module.exports = function(db, module) {
});
};
function sortedSetAddBulk(key, scores, values, callback) {
if (scores.length !== values.length) {
return callback(new Error('[[error:invalid-data]]'));
}
values = values.map(helpers.valueToString);
var bulk = db.collection('objects').initializeUnorderedBulkOp();
for(var i=0; i<scores.length; ++i) {
bulk.find({_key: key, value: values[i]}).upsert().updateOne({$set: {score: scores[i], value: values[i]}});
}
bulk.execute(function(err, result) {
callback(err);
});
}
module.sortedSetsAdd = function(keys, score, value, callback) {
callback = callback || helpers.noop;
@ -40,9 +62,12 @@ module.exports = function(db, module) {
module.sortedSetRemove = function(key, value, callback) {
callback = callback || helpers.noop;
value = helpers.valueToString(value);
if (!Array.isArray(value)) {
value = [value];
}
value = value.map(helpers.valueToString);
db.collection('objects').remove({_key: key, value: value}, function(err) {
db.collection('objects').remove({_key: key, value: {$in: value}}, function(err) {
callback(err);
});
};

@ -3,11 +3,27 @@
module.exports = function(redisClient, module) {
module.sortedSetAdd = function(key, score, value, callback) {
callback = callback || function() {};
if (Array.isArray(score) && Array.isArray(value)) {
return sortedSetAddMulti(key, score, value, callback);
}
redisClient.zadd(key, score, value, function(err) {
callback(err);
});
};
function sortedSetAddMulti(key, scores, values, callback) {
if (scores.length !== values.length) {
return callback(new Error('[[error:invalid-data]]'));
}
var multi = redisClient.multi();
for(var i=0; i<scores.lenth; ++i) {
multi.zadd(key, scores[i], values[i]);
}
multi.exec(function(err, result) {
callback(err);
});
}
module.sortedSetsAdd = function(keys, score, value, callback) {
callback = callback || function() {};
var multi = redisClient.multi();
@ -23,7 +39,14 @@ module.exports = function(redisClient, module) {
module.sortedSetRemove = function(key, value, callback) {
callback = callback || function() {};
redisClient.zrem(key, value, function(err) {
if (!Array.isArray(value)) {
value = [value];
}
var multi = redisClient.multi();
for(var i=0; i<value.length; ++i) {
multi.zrem(key, value[i]);
}
multi.exec(function(err) {
callback(err);
});
};

@ -102,8 +102,7 @@ var db = require('./database'),
getMessages(mids, fromuid, touid, isNew, callback);
});
// Mark any chat notifications pertaining to this chat as read
notifications.markReadByUniqueId(fromuid, 'chat_' + touid + '_' + fromuid, function(err) {
notifications.markRead('chat_' + touid + '_' + fromuid, fromuid, function(err) {
if (err) {
winston.error('[messaging] Could not mark notifications related to this chat as read: ' + err.message);
}

@ -53,8 +53,12 @@ var async = require('async'),
notification.text = S(notification.text).escapeHTML().s;
}
notification.bodyShort = S(notification.bodyShort).escapeHTML().s;
notification.bodyLong = S(notification.bodyLong).escapeHTML().s;
if (notification.bodyShort) {
notification.bodyShort = S(notification.bodyShort).escapeHTML().s;
}
if (notification.bodyLong) {
notification.bodyLong = S(notification.bodyLong).escapeHTML().s;
}
if (notification.from && !notification.image) {
User.getUserField(notification.from, 'picture', function(err, picture) {
@ -80,203 +84,134 @@ var async = require('async'),
};
Notifications.create = function(data, callback) {
// Add default values to data Object if not already set
var defaults = {
bodyShort: '',
bodyLong: '',
importance: 5,
datetime: Date.now(),
uniqueId: utils.generateUUID()
};
for(var v in defaults) {
if (defaults.hasOwnProperty(v) && !data[v]) {
data[v] = defaults[v];
}
}
// Backwards compatibility for old notification schema
// Remove this block for NodeBB v0.6.0
if (data.hasOwnProperty('text')) {
data.bodyShort = data.text;
data.bodyLong = '';
delete data.text;
if (!data.nid) {
return callback(new Error('no-notification-id'));
}
db.incrObjectField('global', 'nextNid', function(err, nid) {
data.importance = data.importance || 5;
db.getObject('notifications:' + data.nid, function(err, oldNotification) {
if (err) {
return callback(err);
}
data.nid = nid;
db.setAdd('notifications', nid);
db.setObject('notifications:' + nid, data, function(err) {
callback(err, nid);
if (oldNotification) {
if (parseInt(oldNotification.pid, 10) === parseInt(data.pid, 10) && parseInt(oldNotification.importance, 10) > parseInt(data.importance, 10)) {
return callback(null, null);
}
}
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.push = function(nid, uids, callback) {
Notifications.push = function(notification, uids, callback) {
callback = callback || function() {};
var websockets = require('./socket.io');
if (!Array.isArray(uids)) {
uids = [uids];
}
Notifications.get(nid, function(err, notif_data) {
if (err) {
return callback(err);
}
async.eachLimit(uids, 10, function(uid, next) {
if (!parseInt(uid, 10)) {
return next();
}
shouldPush(uid, notif_data, function(err, shouldPush) {
if (err || !shouldPush) {
return callback(err);
}
async.parallel([
async.apply(db.setObjectField, 'uid:' + uid + ':notifications:uniqueId:nid', notif_data.uniqueId, nid),
async.apply(db.sortedSetAdd, 'uid:' + uid + ':notifications:unread', notif_data.datetime, notif_data.uniqueId),
async.apply(db.sortedSetRemove, 'uid:' + uid + ':notifications:read', notif_data.uniqueId)
], function(err) {
if (err) {
return next(err);
}
var unreadKeys = [];
var readKeys = [];
User.notifications.getUnreadCount(uid, function(err, count) {
if (!err) {
websockets.in('uid_' + uid).emit('event:new_notification', notif_data, count);
}
});
// Plugins
notif_data.uid = uid;
plugins.fireHook('action:notification.pushed', notif_data);
next();
});
});
}, callback);
uids.filter(Boolean).forEach(function(uid) {
unreadKeys.push('uid:' + uid + ':notifications:unread');
readKeys.push('uid:' + uid + ':notifications:read');
});
};
function shouldPush(uid, newNotifObj, callback) {
if (!newNotifObj) {
return callback(null, false);
}
hasNotification(newNotifObj.uniqueId, uid, function(err, hasNotification) {
async.parallel([
function(next) {
db.sortedSetsAdd(unreadKeys, notification.datetime, notification.nid, next);
},
function(next) {
db.sortedSetsRemove(readKeys, notification.nid, next);
}
], function(err) {
if (err) {
return callback(err);
}
if (!hasNotification) {
return callback(null, true);
}
db.getObjectField('uid:' + uid + ':notifications:uniqueId:nid', newNotifObj.uniqueId, function(err, nid) {
if (err) {
return callback(err);
}
db.getObjectFields('notifications:' + nid, ['nid', 'uniqueId', 'importance'], function(err, oldNotifObj) {
if (err) {
return callback(err);
}
if (!oldNotifObj || newNotifObj.uniqueId !== oldNotifObj.uniqueId) {
return callback(null, true);
}
callback(null, parseInt(newNotifObj.importance, 10) >= parseInt(oldNotifObj.importance, 10));
});
});
});
}
plugins.fireHook('action:notification.pushed', {notification: notification, uids: uids});
function hasNotification(uniqueId, uid, callback) {
async.parallel([
async.apply(db.isSortedSetMember, 'uid:' + uid + ':notifications:unread', uniqueId),
async.apply(db.isSortedSetMember, 'uid:' + uid + ':notifications:read', uniqueId)
], function(err, results) {
if (err) {
return callback(err);
for(var i=0; i<uids.length; ++i) {
websockets.in('uid_' + uids[i]).emit('event:new_notification', notification);
}
callback(null, results[0] || results[1]);
});
}
};
Notifications.pushGroup = function(nid, groupName, callback) {
Notifications.pushGroup = function(notification, groupName, callback) {
callback = callback || function() {};
groups.get(groupName, {}, function(err, groupObj) {
if (err || !groupObj || !Array.isArray(groupObj.members) || !groupObj.members.length) {
return callback(err);
}
Notifications.push(nid, groupObj.members, callback);
Notifications.push(notification, groupObj.members, callback);
});
};
Notifications.markRead = function(nid, uid, callback) {
callback = callback || function() {};
if (!parseInt(uid, 10) || !parseInt(nid, 10)) {
return callback();
}
Notifications.markReadMultiple([nid], uid, callback);
};
Notifications.markReadMultiple = function(nids, uid, callback) {
callback = callback || function() {};
if (!Array.isArray(nids) || !nids.length) {
return callback();
}
var notificationKeys = nids.map(function(nid) {
return 'notifications:' + nid;
});
db.getObjectFields('notifications:' + nid, ['uniqueId', 'datetime'], function(err, notificationData) {
if (err || !notificationData) {
db.getObjectsFields(notificationKeys, ['datetime'], function(err, notificationData) {
if (err) {
return callback(err);
}
var datetimes = notificationData.map(function(notification) {
return notification && notification.datetime;
});
async.parallel([
async.apply(db.sortedSetRemove, 'uid:' + uid + ':notifications:unread', notificationData.uniqueId),
async.apply(db.sortedSetAdd, 'uid:' + uid + ':notifications:read', notificationData.datetime, notificationData.uniqueId)
function(next) {
db.sortedSetRemove('uid:' + uid + ':notifications:unread', nids, next);
},
function(next) {
db.sortedSetAdd('uid:' + uid + ':notifications:read', datetimes, nids, next);
}
], callback);
});
};
Notifications.markReadMultiple = function(nids, uid, callback) {
callback = callback || function() {};
if (!nids) {
return callback(null);
}
if (!Array.isArray(nids) && parseInt(nids, 10) > 0) {
nids = [nids];
}
async.each(nids, function(nid, next) {
Notifications.markRead(nid, uid, next);
}, callback);
};
Notifications.markAllRead = function(uid, callback) {
db.getObjectValues('uid:' + uid + ':notifications:uniqueId:nid', function(err, nids) {
db.getSortedSetRange('uid:' + uid + ':notifications:unread', 0, 99, function(err, nids) {
if (err) {
return callback(err);
}
if (!Array.isArray(nids) || !nids.length) {
return callback(err);
return callback();
}
Notifications.markReadMultiple(nids, uid, callback);
});
};
Notifications.markReadByUniqueId = function(uid, uniqueId, callback) {
async.waterfall([
async.apply(db.getObjectField, 'uid:' + uid + ':notifications:uniqueId:nid', uniqueId),
function(nid, next) {
Notifications.markRead(nid, uid, next);
}
], callback);
};
Notifications.prune = function() {
var start = process.hrtime();
@ -289,12 +224,14 @@ var async = require('async'),
var cutoffTime = Date.now() - week;
db.getSetMembers('notifications', function(err, nids) {
db.getSortedSetRange('notifications', 0, 499, function(err, nids) {
if (err) {
return winston.error(err.message);
}
if (!Array.isArray(nids) || !nids.length) {
return;
}
var totalNidCount = nids.length;
nids = _.sortBy(nids, function(num) { return parseInt(num, 10); }).slice(0, 500);
var keys = nids.map(function(nid) {
return 'notifications:' + nid;
@ -319,7 +256,7 @@ var async = require('async'),
async.parallel([
function(next) {
db.setRemove('notifications', expiredNids, next);
db.sortedSetRemove('notifications', expiredNids, next);
},
function(next) {
db.deleteAll(keys, next);

@ -224,11 +224,11 @@ function sendChatNotification(fromuid, touid, messageObj) {
bodyShort: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
bodyLong: messageObj.content,
path: nconf.get('relative_path') + '/chats/' + utils.slugify(messageObj.fromUser.username),
uniqueId: 'chat_' + fromuid + '_' + touid,
nid: 'chat_' + fromuid + '_' + touid,
from: fromuid
}, function(err, nid) {
if (!err) {
notifications.push(nid, [touid]);
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, [touid]);
}
});
}

@ -135,11 +135,11 @@ SocketPosts.sendNotificationToPostOwner = function(pid, fromuid, notification) {
bodyShort: '[[' + notification + ', ' + results.username + ']]',
bodyLong: results.postContent,
pid: pid,
uniqueId: 'post:' + pid + ':uid:' + fromuid,
nid: 'post:' + pid + ':uid:' + fromuid,
from: fromuid
}, function(err, nid) {
if (!err) {
notifications.push(nid, [postData.uid]);
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, [postData.uid]);
}
});
});
@ -310,13 +310,13 @@ SocketPosts.flag = function(socket, pid, callback) {
bodyShort: message,
bodyLong: post.content,
pid: pid,
uniqueId: 'post_flag:' + pid,
nid: 'post_flag:' + pid + ':uid:' + socket.uid,
from: socket.uid
}, function(err, nid) {
if (err) {
}, function(err, notification) {
if (err || !notification) {
return next(err);
}
notifications.push(nid, adminGroup.members, next);
notifications.push(notification, adminGroup.members, next);
});
},
function(next) {

@ -353,11 +353,11 @@ SocketTopics.sendNotificationToTopicOwner = function(tid, fromuid, notification)
notifications.create({
bodyShort: '[[' + notification + ', ' + results.username + ']]',
path: nconf.get('relative_path') + '/topic/' + results.topicData.slug,
uniqueId: 'topic:' + tid + ':uid:' + fromuid,
nid: 'topic:' + tid + ':uid:' + fromuid,
from: fromuid
}, function(err, nid) {
if (!err) {
notifications.push(nid, [results.topicData.uid]);
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, [results.topicData.uid]);
}
});
});

@ -181,31 +181,33 @@ SocketUser.changePicture = function(socket, data, callback) {
};
SocketUser.follow = function(socket, data, callback) {
if (socket.uid && data) {
toggleFollow('follow', socket.uid, data.uid, function(err) {
if (!socket.uid || !data) {
return;
}
toggleFollow('follow', socket.uid, data.uid, function(err) {
if (err) {
return callback(err);
}
user.getUserFields(socket.uid, ['username', 'userslug'], function(err, userData) {
if (err) {
return callback(err);
}
user.getUserFields(socket.uid, ['username', 'userslug'], function(err, userData) {
if (err) {
return callback(err);
notifications.create({
bodyShort: '[[notifications:user_started_following_you, ' + userData.username + ']]',
path: nconf.get('relative_path') + '/user/' + userData.userslug,
nid: 'follow:uid:' + socket.uid,
from: socket.uid
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, [data.uid]);
}
notifications.create({
bodyShort: '[[notifications:user_started_following_you, ' + userData.username + ']]',
path: nconf.get('relative_path') + '/user/' + userData.userslug,
uniqueId: 'follow:uid:' + socket.uid,
from: socket.uid
}, function(err, nid) {
if (!err) {
notifications.push(nid, [data.uid]);
}
callback(err);
});
callback(err);
});
});
}
});
};
SocketUser.unfollow = function(socket, data, callback) {

@ -56,12 +56,12 @@ module.exports = function(Topics) {
bodyShort: '[[notifications:user_posted_to, ' + results.username + ', ' + results.title + ']]',
bodyLong: results.postContent,
pid: pid,
uniqueId: 'topic:' + tid + ':uid:' + exceptUid,
nid: 'topic:' + tid + ':uid:' + exceptUid,
tid: tid,
from: exceptUid
}, function(err, nid) {
if (!err) {
notifications.push(nid, followers);
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, followers);
}
});
});

@ -234,6 +234,9 @@ module.exports = function(Topics) {
Topics.markTopicNotificationsRead = function(tid, uid) {
user.notifications.getUnreadByField(uid, 'tid', tid, function(err, nids) {
if (err) {
return winston.error(err.stack);
}
notifications.markReadMultiple(nids, uid, function() {
user.notifications.pushCount(uid);
});

@ -19,7 +19,7 @@ var db = require('./database'),
schemaDate, thisSchemaDate,
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
latestSchema = Date.UTC(2014, 6, 24);
latestSchema = Date.UTC(2014, 8, 8);
Upgrade.check = function(callback) {
db.get('schemaDate', function(err, value) {
@ -963,6 +963,56 @@ Upgrade.upgrade = function(callback) {
winston.info('[2014/7/24] Upgrading chats to sorted set - skipped');
next();
}
},
function(next) {
thisSchemaDate = Date.UTC(2014, 8, 8);
if (schemaDate < thisSchemaDate) {
winston.info('[2014/9/8] Deleting old notifications...');
async.parallel({
uids: function(next) {
db.getSortedSetRange('users:joindate', 0, -1, next);
},
nids: function(next) {
db.getSetMembers('notifications', next);
}
}, function(err, results) {
if (err) {
return next(err);
}
var uidKeys = results.uids.map(function(uid) {
return 'uid:' + uid + ':notifications:uniqueId:nid';
});
var nidKeys = results.nids.filter(Boolean).map(function(nid) {
return 'notifications:' + nid;
});
async.series([
function(next) {
db.deleteAll(nidKeys, next);
},
function(next) {
db.deleteAll(uidKeys, next);
},
function(next) {
db.delete('notifications', next);
}
], function(err, results) {
if (err) {
winston.error('[2014/9/8] Error encountered while deleting notifications');
return next(err);
}
winston.info('[2014/9/8] Deleted old notifications');
Upgrade.update(thisSchemaDate, next);
});
});
} else {
winston.info('[2014/9/8] Deleting old notifications skipped');
next();
}
}
// Add new schema updates here
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 22!!!

@ -165,10 +165,11 @@ module.exports = function(User) {
bodyShort: '[[user:username_taken_workaround, ' + userData.username + ']]',
bodyLong: '',
image: 'brand:logo',
nid: 'username_taken:' + uid,
datetime: Date.now()
}, function(err, nid) {
if (!err) {
notifications.push(nid, uid);
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, uid);
}
});
}

@ -65,9 +65,6 @@ module.exports = function(User) {
function(next) {
db.delete('uid:' + uid + ':notifications:unread', next);
},
function(next) {
db.delete('uid:' + uid + ':notifications:uniqueId:nid', next);
},
function(next) {
db.sortedSetRemove('users:joindate', uid, next);
},

@ -45,63 +45,61 @@ var async = require('async'),
};
function getNotificationsFromSet(set, uid, start, stop, max, callback) {
db.getSortedSetRevRange(set, start, stop, function(err, uniqueIds) {
db.getSortedSetRevRange(set, start, stop, function(err, nids) {
if (err) {
return callback(err);
}
if(!Array.isArray(uniqueIds) || !uniqueIds.length) {
if(!Array.isArray(nids) || !nids.length) {
return callback(null, []);
}
if (uniqueIds.length > max) {
uniqueIds.length = max;
if (nids.length > max) {
nids.length = max;
}
db.getObjectFields('uid:' + uid + ':notifications:uniqueId:nid', uniqueIds, function(err, uniqueIdToNids) {
UserNotifications.getNotifications(nids, uid, function(err, notifications) {
if (err) {
return callback(err);
}
var nidsToUniqueIds = {};
var nids = [];
uniqueIds.forEach(function(uniqueId) {
nidsToUniqueIds[uniqueIdToNids[uniqueId]] = uniqueId;
nids.push(uniqueIdToNids[uniqueId]);
});
UserNotifications.getNotifications(nids, uid, function(err, notifications) {
if (err) {
return callback(err);
}
var deletedNids = [];
notifications.forEach(function(notification, index) {
if (!notification) {
if (process.env.NODE_ENV === 'development') {
winston.info('[notifications.get] nid ' + nids[index] + ' not found. Removing.');
}
db.sortedSetRemove(set, nidsToUniqueIds[nids[index]]);
db.deleteObjectField('uid:' + uid + ':notifications:uniqueId:nid', nidsToUniqueIds[nids[index]]);
notifications.forEach(function(notification, index) {
if (!notification) {
if (process.env.NODE_ENV === 'development') {
winston.info('[notifications.get] nid ' + nids[index] + ' not found. Removing.');
}
});
callback(null, notifications);
if (nids[index]) {
deletedNids.push(nids[index]);
}
}
});
if (deletedNids.length) {
db.sortedSetRemove(set, deletedNids);
}
callback(null, notifications);
});
});
}
UserNotifications.getAll = function(uid, limit, callback) {
if (!limit || parseInt(limit, 10) <= 0) {
limit = 25;
}
db.getObjectValues('uid:' + uid + ':notifications:uniqueId:nid', function(err, nids) {
UserNotifications.getAll = function(uid, count, callback) {
async.parallel({
unread: function(next) {
db.getSortedSetRevRange('uid:' + uid + ':notifications:unread', 0, count, next);
},
read: function(next) {
db.getSortedSetRevRange('uid:' + uid + ':notifications:read', 0, count, next);
}
}, function(err, results) {
if (err) {
return callback(err);
}
var nids = results.unread.concat(results.read);
UserNotifications.getNotifications(nids, uid, function(err, notifs) {
if (err) {
return callback(err);
@ -122,11 +120,7 @@ var async = require('async'),
return callback(err);
}
var uniqueIds = notifications.map(function(notification) {
return notification ? notification.uniqueId : null;
});
db.isSortedSetMembers('uid:' + uid + ':notifications:read', uniqueIds, function(err, hasRead) {
db.isSortedSetMembers('uid:' + uid + ':notifications:read', nids, function(err, hasRead) {
if (err) {
return callback(err);
}
@ -159,7 +153,8 @@ var async = require('async'),
};
function generatePostPaths(pids, uid, callback) {
var postKeys = pids.filter(Boolean).map(function(pid) {
pids = pids.filter(Boolean);
var postKeys = pids.map(function(pid) {
return 'post:' + pid;
});
@ -193,6 +188,7 @@ var async = require('async'),
pidToPaths[pid] = nconf.get('relative_path') + '/topic/' + slug + '/' + postIndex;
}
});
callback(null, pidToPaths);
});
});
@ -202,26 +198,16 @@ var async = require('async'),
var now = Date.now(),
yesterday = now - (1000*60*60*24); // Approximate, can be more or less depending on time changes, makes no difference really.
db.getSortedSetRangeByScore('uid:' + uid + ':notifications:unread', 0, 20, yesterday, now, function(err, uniqueIds) {
db.getSortedSetRangeByScore('uid:' + uid + ':notifications:unread', 0, 20, yesterday, now, function(err, nids) {
if (err) {
return callback(err);
}
if (!Array.isArray(uniqueIds) || !uniqueIds.length) {
if (!Array.isArray(nids) || !nids.length) {
return callback(null, []);
}
db.getObjectFields('uid:' + uid + ':notifications:uniqueId:nid', uniqueIds, function(err, uniqueIdToNids) {
if (err) {
return callback(err);
}
var nids = Object.keys(uniqueIdToNids).map(function(uniqueId) {
return uniqueIdToNids[uniqueId];
});
UserNotifications.getNotifications(nids, uid, callback);
});
UserNotifications.getNotifications(nids, uid, callback);
});
};
@ -230,46 +216,35 @@ var async = require('async'),
};
UserNotifications.getUnreadByField = function(uid, field, value, callback) {
db.getSortedSetRange('uid:' + uid + ':notifications:unread', 0, -1, function(err, uniqueIds) {
db.getSortedSetRange('uid:' + uid + ':notifications:unread', 0, -1, function(err, nids) {
if (err) {
return callback(err);
}
if (!Array.isArray(uniqueIds) || !uniqueIds.length) {
if (!Array.isArray(nids) || !nids.length) {
return callback(null, []);
}
db.getObjectFields('uid:' + uid + ':notifications:uniqueId:nid', uniqueIds, function(err, uniqueIdsToNids) {
UserNotifications.getNotifications(nids, uid, function(err, notifications) {
if (err) {
return callback(err);
}
var nids = Object.keys(uniqueIdsToNids).map(function(uniqueId) {
return uniqueIdsToNids[uniqueId];
nids = notifications.filter(function(notification) {
return notification && notification[field] !== value.toString();
}).map(function(notification) {
return notification.nid;
});
UserNotifications.getNotifications(nids, uid, function(err, notifications) {
if (err) {
return callback(err);
}
notifications = notifications.filter(function(notification) {
return notification && notification[field] !== value.toString();
}).map(function(notification) {
return notification.nid;
});
callback(null, nids);
});
callback(null, nids);
});
});
};
UserNotifications.sendPostNotificationToFollowers = function(uid, tid, pid) {
return;
db.getSetMembers('followers:' + uid, function(err, followers) {
if (err || !followers || !followers.length) {
if (err || !Array.isArray(followers) || !followers.length) {
return;
}
@ -296,23 +271,30 @@ var async = require('async'),
return !results.topicFollowers[index];
});
notifications.create({
bodyShort: '[[notifications:user_posted_to, ' + results.username + ', ' + results.topic.title + ']]',
bodyLong: results.postContent,
pid: pid,
uniqueId: 'topic:' + tid + ':uid:' + uid,
tid: tid,
from: uid
}, function(err, nid) {
if (err) {
if (!followers.length) {
return;
}
async.filter(followers, function(uid, next) {
privileges.categories.can('read', results.topic.cid, uid, function(err, canRead) {
next(!err && canRead);
});
}, function(followers) {
if (!followers.length) {
return;
}
async.filter(followers, function(uid, next) {
privileges.categories.can('read', results.topic.cid, uid, function(err, canRead) {
next(!err && canRead);
});
}, function(followers){
notifications.push(nid, followers);
notifications.create({
bodyShort: '[[notifications:user_posted_to, ' + results.username + ', ' + results.topic.title + ']]',
bodyLong: results.postContent,
pid: pid,
nid: 'topic:' + tid + ':uid:' + uid,
tid: tid,
from: uid
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, followers);
}
});
});
});

Loading…
Cancel
Save