Merge remote-tracking branch 'origin/unread-refactor'

v1.18.x
barisusakli 11 years ago
commit e2e71da4e1

@ -15,9 +15,9 @@ define('forum/infinitescroll', function() {
topOffset = _topOffest || 0; topOffset = _topOffest || 0;
$(window).off('scroll', onScroll).on('scroll', onScroll); $(window).off('scroll', onScroll).on('scroll', onScroll);
if ($(document).height() === $(window).height()) { // if ($(document).height() === $(window).height()) {
callback(1); // callback(1);
} // }
}; };
function onScroll() { function onScroll() {

@ -104,7 +104,12 @@ module.exports = function(db, module) {
if (!key) { if (!key) {
return callback(); return callback();
} }
db.collection('objects').find({_key:key}, {fields: {_id: 0, value: 1, score: 1}})
var fields = {_id: 0, value: 1};
if (withScores) {
fields['score'] = 1;
}
db.collection('objects').find({_key:key}, {fields: fields})
.limit(stop - start + 1) .limit(stop - start + 1)
.skip(start) .skip(start)
.sort({score: sort}) .sort({score: sort})
@ -136,14 +141,18 @@ module.exports = function(db, module) {
}; };
module.getSortedSetRangeByScore = function(key, start, count, min, max, callback) { module.getSortedSetRangeByScore = function(key, start, count, min, max, callback) {
getSortedSetRangeByScore(key, start, count, min, max, 1, callback); getSortedSetRangeByScore(key, start, count, min, max, 1, false, callback);
}; };
module.getSortedSetRevRangeByScore = function(key, start, count, max, min, callback) { module.getSortedSetRevRangeByScore = function(key, start, count, max, min, callback) {
getSortedSetRangeByScore(key, start, count, min, max, -1, callback); getSortedSetRangeByScore(key, start, count, min, max, -1, false, callback);
};
module.getSortedSetRevRangeByScoreWithScores = function(key, start, count, max, min, callback) {
getSortedSetRangeByScore(key, start, count, min, max, -1, true, callback);
}; };
function getSortedSetRangeByScore(key, start, count, min, max, sort, callback) { function getSortedSetRangeByScore(key, start, count, min, max, sort, withScores, callback) {
if (!key) { if (!key) {
return callback(); return callback();
} }
@ -159,7 +168,12 @@ module.exports = function(db, module) {
scoreQuery['$lte'] = max; scoreQuery['$lte'] = max;
} }
db.collection('objects').find({_key:key, score: scoreQuery}, {fields:{value:1}}) var fields = {_id: 0, value: 1};
if (withScores) {
fields['score'] = 1;
}
db.collection('objects').find({_key:key, score: scoreQuery}, {fields: fields})
.limit(count) .limit(count)
.skip(start) .skip(start)
.sort({score: sort}) .sort({score: sort})
@ -168,9 +182,11 @@ module.exports = function(db, module) {
return callback(err); return callback(err);
} }
if (!withScores) {
data = data.map(function(item) { data = data.map(function(item) {
return item.value; return item.value;
}); });
}
callback(err, data); callback(err, data);
}); });

@ -98,6 +98,10 @@ module.exports = function(redisClient, module) {
redisClient.zrevrangebyscore([key, max, min, 'LIMIT', start, count], callback); redisClient.zrevrangebyscore([key, max, min, 'LIMIT', start, count], callback);
}; };
module.getSortedSetRevRangeByScoreWithScores = function(key, start, count, max, min, callback) {
redisClient.zrevrangebyscore([key, max, min, 'WITHSCORES', 'LIMIT', start, count], callback);
};
module.sortedSetCount = function(key, min, max, callback) { module.sortedSetCount = function(key, min, max, callback) {
redisClient.zcount(key, min, max, callback); redisClient.zcount(key, min, max, callback);
}; };

@ -27,7 +27,11 @@ module.exports = function(Topics) {
topics: [] topics: []
}; };
function sendUnreadTopics(tids, callback) { Topics.getUnreadTids(uid, start, stop, function(err, tids) {
if (err) {
return callback(err);
}
if (!tids.length) { if (!tids.length) {
return callback(null, unreadTopics); return callback(null, unreadTopics);
} }
@ -52,14 +56,6 @@ module.exports = function(Topics) {
callback(null, unreadTopics); callback(null, unreadTopics);
}); });
}); });
}
Topics.getUnreadTids(uid, start, stop, function(err, unreadTids) {
if (err) {
return callback(err);
}
sendUnreadTopics(unreadTids, callback);
}); });
}; };
@ -69,12 +65,17 @@ module.exports = function(Topics) {
return callback(null, []); return callback(null, []);
} }
var yesterday = Date.now() - 86400000;
async.parallel({ async.parallel({
ignoredCids: function(next) { ignoredCids: function(next) {
user.getIgnoredCategories(uid, next); user.getIgnoredCategories(uid, next);
}, },
recentTids: function(next) { recentTids: function(next) {
Topics.getLatestTids(0, -1, 'day', next); db.getSortedSetRevRangeByScoreWithScores('topics:recent', 0, -1, Infinity, yesterday, next);
},
userScores: function(next) {
db.getSortedSetRevRangeByScoreWithScores('uid:' + uid + ':tids_read', 0, -1, Infinity, yesterday, next);
} }
}, function(err, results) { }, function(err, results) {
if (err) { if (err) {
@ -85,13 +86,16 @@ module.exports = function(Topics) {
return callback(null, []); return callback(null, []);
} }
Topics.hasReadTopics(results.recentTids, uid, function(err, read) { var userRead = {};
if (err) { results.userScores.forEach(function(userItem) {
return callback(err); userRead[userItem.value] = userItem.score;
} });
var tids = results.recentTids.filter(function(tid, index) { var tids = results.recentTids.filter(function(recentTopic, index) {
return !read[index]; return !userRead[recentTopic.value] || recentTopic.score > userRead[recentTopic.value];
}).map(function(topic) {
return topic.value;
}); });
filterTopics(uid, tids, results.ignoredCids, function(err, tids) { filterTopics(uid, tids, results.ignoredCids, function(err, tids) {
@ -108,7 +112,6 @@ module.exports = function(Topics) {
callback(err, tids); callback(err, tids);
}); });
}); });
});
}; };
function filterTopics(uid, tids, ignoredCids, callback) { function filterTopics(uid, tids, ignoredCids, callback) {
@ -167,12 +170,7 @@ module.exports = function(Topics) {
}; };
Topics.markAsUnreadForAll = function(tid, callback) { Topics.markAsUnreadForAll = function(tid, callback) {
db.delete('tid:' + tid + ':read_by_uid', function(err) {
if(err) {
return callback(err);
}
Topics.markCategoryUnreadForAll(tid, callback); Topics.markCategoryUnreadForAll(tid, callback);
});
}; };
Topics.markAsRead = function(tids, uid, callback) { Topics.markAsRead = function(tids, uid, callback) {
@ -181,13 +179,15 @@ module.exports = function(Topics) {
return callback(); return callback();
} }
tids = tids.filter(Boolean); tids = tids.filter(Boolean);
var keys = tids.map(function(tid) {
return 'tid:' + tid + ':read_by_uid'; var now = Date.now();
var scores = tids.map(function(tid) {
return now;
}); });
async.parallel({ async.parallel({
markRead: function(next) { markRead: function(next) {
db.setsAdd(keys, uid, next); db.sortedSetAdd('uid:' + uid + ':tids_read', scores, tids, next);
}, },
topicData: function(next) { topicData: function(next) {
Topics.getTopicsFields(tids, ['cid'], next); Topics.getTopicsFields(tids, ['cid'], next);
@ -238,21 +238,29 @@ module.exports = function(Topics) {
})); }));
} }
var sets = []; async.parallel({
recentScores: function(next) {
for (var i = 0, ii = tids.length; i < ii; i++) { db.sortedSetScores('topics:recent', tids, next);
sets.push('tid:' + tids[i] + ':read_by_uid'); },
userScores: function(next) {
db.sortedSetScores('uid:' + uid + ':tids_read', tids, next);
} }
}, function(err, results) {
if (err) {
return callback(err);
}
var result = tids.map(function(tid, index) {
return !!(results.userScores[index] && results.userScores[index] >= results.recentScores[index]);
});
db.isMemberOfSets(sets, uid, callback); callback(null, result);
});
}; };
Topics.hasReadTopic = function(tid, uid, callback) { Topics.hasReadTopic = function(tid, uid, callback) {
if(!parseInt(uid, 10)) { Topics.hasReadTopics([tid], uid, function(err, hasRead) {
return callback(null, false); callback(err, Array.isArray(hasRead) && hasRead.length ? hasRead[0] : false);
} });
db.isSetMember('tid:' + tid + ':read_by_uid', uid, callback);
}; };

@ -19,7 +19,7 @@ var db = require('./database'),
schemaDate, thisSchemaDate, schemaDate, thisSchemaDate,
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
latestSchema = Date.UTC(2014, 8, 8); latestSchema = Date.UTC(2014, 8, 27);
Upgrade.check = function(callback) { Upgrade.check = function(callback) {
db.get('schemaDate', function(err, value) { db.get('schemaDate', function(err, value) {
@ -1013,6 +1013,35 @@ Upgrade.upgrade = function(callback) {
winston.info('[2014/9/8] Deleting old notifications skipped'); winston.info('[2014/9/8] Deleting old notifications skipped');
next(); next();
} }
},
function(next) {
thisSchemaDate = Date.UTC(2014, 8, 27);
if (schemaDate < thisSchemaDate) {
winston.info('[2014/9/27] Deleting tid:<tid>:read_by_uid...');
db.getSortedSetRange('topics:tid', 0, -1, function(err, tids) {
if (err) {
return next(err);
}
tids = tids.filter(Boolean);
var readKeys = tids.map(function(tid) {
return 'tid:' + tid + ':read_by_uid';
});
db.deleteAll(readKeys, function(err, results) {
if (err) {
winston.error('[2014/9/27] Error encountered while deleting tid:<tid>:read_by_uid');
return next(err);
}
winston.info('[2014/9/27] Deleted tid:<tid>:read_by_uid');
Upgrade.update(thisSchemaDate, next);
});
});
} else {
winston.info('[2014/9/27] Deleting tid:<tid>:read_by_uid skipped');
next();
}
} }
// Add new schema updates here // Add new schema updates here
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 22!!! // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 22!!!

Loading…
Cancel
Save