mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
fix: #5570, create per category user post zsets
This commit is contained in:
@@ -3,15 +3,19 @@
|
|||||||
|
|
||||||
define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], function (header, infinitescroll) {
|
define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], function (header, infinitescroll) {
|
||||||
var AccountTopics = {};
|
var AccountTopics = {};
|
||||||
|
var method;
|
||||||
|
var template;
|
||||||
var set;
|
var set;
|
||||||
|
|
||||||
AccountTopics.init = function () {
|
AccountTopics.init = function () {
|
||||||
header.init();
|
header.init();
|
||||||
|
|
||||||
AccountTopics.handleInfiniteScroll('account/topics', 'uid:' + ajaxify.data.theirid + ':topics');
|
AccountTopics.handleInfiniteScroll('topics.loadMoreUserTopics', 'account/topics');
|
||||||
};
|
};
|
||||||
|
|
||||||
AccountTopics.handleInfiniteScroll = function (_template, _set) {
|
AccountTopics.handleInfiniteScroll = function (_method, _template, _set) {
|
||||||
|
method = _method;
|
||||||
|
template = _template;
|
||||||
set = _set;
|
set = _set;
|
||||||
|
|
||||||
if (!config.usePagination) {
|
if (!config.usePagination) {
|
||||||
@@ -24,8 +28,9 @@ define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'],
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
infinitescroll.loadMore('topics.loadMoreFromSet', {
|
infinitescroll.loadMore(method, {
|
||||||
set: set,
|
set: set,
|
||||||
|
uid: ajaxify.data.theirid,
|
||||||
after: $('[component="category"]').attr('data-nextstart'),
|
after: $('[component="category"]').attr('data-nextstart'),
|
||||||
count: config.topicsPerPage,
|
count: config.topicsPerPage,
|
||||||
}, function (data, done) {
|
}, function (data, done) {
|
||||||
@@ -40,7 +45,7 @@ define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'],
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onTopicsLoaded(topics, callback) {
|
function onTopicsLoaded(topics, callback) {
|
||||||
app.parseAndTranslate('account/topics', 'topics', { topics: topics }, function (html) {
|
app.parseAndTranslate(template, 'topics', { topics: topics }, function (html) {
|
||||||
$('[component="category"]').append(html);
|
$('[component="category"]').append(html);
|
||||||
html.find('.timeago').timeago();
|
html.find('.timeago').timeago();
|
||||||
app.createUserTooltips();
|
app.createUserTooltips();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ define('forum/account/watched', ['forum/account/header', 'forum/account/topics']
|
|||||||
AccountWatched.init = function () {
|
AccountWatched.init = function () {
|
||||||
header.init();
|
header.init();
|
||||||
|
|
||||||
topics.handleInfiniteScroll('account/watched', 'uid:' + ajaxify.data.theirid + ':followed_tids');
|
topics.handleInfiniteScroll('topics.loadMoreFromSet', 'account/watched', 'uid:' + ajaxify.data.theirid + ':followed_tids');
|
||||||
};
|
};
|
||||||
|
|
||||||
return AccountWatched;
|
return AccountWatched;
|
||||||
|
|||||||
@@ -204,12 +204,10 @@ module.exports = function (Categories) {
|
|||||||
batch.processArray(pids, function (pids, next) {
|
batch.processArray(pids, function (pids, next) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
posts.getPostsFields(pids, ['timestamp'], next);
|
posts.getPostsFields(pids, ['pid', 'uid', 'timestamp', 'upvotes', 'downvotes'], next);
|
||||||
},
|
},
|
||||||
function (postData, next) {
|
function (postData, next) {
|
||||||
var timestamps = postData.map(function (post) {
|
var timestamps = postData.map(p => p && p.timestamp);
|
||||||
return post && post.timestamp;
|
|
||||||
});
|
|
||||||
|
|
||||||
async.parallel([
|
async.parallel([
|
||||||
function (next) {
|
function (next) {
|
||||||
@@ -218,6 +216,25 @@ module.exports = function (Categories) {
|
|||||||
function (next) {
|
function (next) {
|
||||||
db.sortedSetAdd('cid:' + cid + ':pids', timestamps, pids, next);
|
db.sortedSetAdd('cid:' + cid + ':pids', timestamps, pids, next);
|
||||||
},
|
},
|
||||||
|
function (next) {
|
||||||
|
async.each(postData, function (post, next) {
|
||||||
|
db.sortedSetRemove([
|
||||||
|
'cid:' + oldCid + ':uid:' + post.uid + ':pids',
|
||||||
|
'cid:' + oldCid + ':uid:' + post.uid + ':pids:votes',
|
||||||
|
], post.pid, next);
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
async.each(postData, function (post, next) {
|
||||||
|
const keys = ['cid:' + cid + ':uid:' + post.uid + ':pids'];
|
||||||
|
const scores = [post.timestamp];
|
||||||
|
if (post.votes > 0) {
|
||||||
|
keys.push('cid:' + cid + ':uid:' + post.uid + ':pids:votes');
|
||||||
|
scores.push(post.votes);
|
||||||
|
}
|
||||||
|
db.sortedSetsAdd(keys, scores, post.pid, next);
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
], next);
|
], next);
|
||||||
},
|
},
|
||||||
], next);
|
], next);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ var db = require('../../database');
|
|||||||
var user = require('../../user');
|
var user = require('../../user');
|
||||||
var posts = require('../../posts');
|
var posts = require('../../posts');
|
||||||
var topics = require('../../topics');
|
var topics = require('../../topics');
|
||||||
|
var categories = require('../../categories');
|
||||||
var pagination = require('../../pagination');
|
var pagination = require('../../pagination');
|
||||||
var helpers = require('../helpers');
|
var helpers = require('../helpers');
|
||||||
var accountHelpers = require('./helpers');
|
var accountHelpers = require('./helpers');
|
||||||
@@ -15,52 +16,89 @@ var postsController = module.exports;
|
|||||||
|
|
||||||
var templateToData = {
|
var templateToData = {
|
||||||
'account/bookmarks': {
|
'account/bookmarks': {
|
||||||
set: 'bookmarks',
|
|
||||||
type: 'posts',
|
type: 'posts',
|
||||||
noItemsFoundKey: '[[topic:bookmarks.has_no_bookmarks]]',
|
noItemsFoundKey: '[[topic:bookmarks.has_no_bookmarks]]',
|
||||||
crumb: '[[user:bookmarks]]',
|
crumb: '[[user:bookmarks]]',
|
||||||
|
getSets: function (callerUid, userData, calback) {
|
||||||
|
setImmediate(calback, null, 'uid:' + userData.uid + ':bookmarks');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'account/posts': {
|
'account/posts': {
|
||||||
set: 'posts',
|
|
||||||
type: 'posts',
|
type: 'posts',
|
||||||
noItemsFoundKey: '[[user:has_no_posts]]',
|
noItemsFoundKey: '[[user:has_no_posts]]',
|
||||||
crumb: '[[global:posts]]',
|
crumb: '[[global:posts]]',
|
||||||
|
getSets: function (callerUid, userData, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read', next);
|
||||||
|
},
|
||||||
|
function (cids, next) {
|
||||||
|
next(null, cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':pids'));
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'account/upvoted': {
|
'account/upvoted': {
|
||||||
set: 'upvote',
|
|
||||||
type: 'posts',
|
type: 'posts',
|
||||||
noItemsFoundKey: '[[user:has_no_upvoted_posts]]',
|
noItemsFoundKey: '[[user:has_no_upvoted_posts]]',
|
||||||
crumb: '[[global:upvoted]]',
|
crumb: '[[global:upvoted]]',
|
||||||
|
getSets: function (callerUid, userData, calback) {
|
||||||
|
setImmediate(calback, null, 'uid:' + userData.uid + ':upvote');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'account/downvoted': {
|
'account/downvoted': {
|
||||||
set: 'downvote',
|
|
||||||
type: 'posts',
|
type: 'posts',
|
||||||
noItemsFoundKey: '[[user:has_no_downvoted_posts]]',
|
noItemsFoundKey: '[[user:has_no_downvoted_posts]]',
|
||||||
crumb: '[[global:downvoted]]',
|
crumb: '[[global:downvoted]]',
|
||||||
|
getSets: function (callerUid, userData, calback) {
|
||||||
|
setImmediate(calback, null, 'uid:' + userData.uid + ':downvote');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'account/best': {
|
'account/best': {
|
||||||
set: 'posts:votes',
|
|
||||||
type: 'posts',
|
type: 'posts',
|
||||||
noItemsFoundKey: '[[user:has_no_voted_posts]]',
|
noItemsFoundKey: '[[user:has_no_voted_posts]]',
|
||||||
crumb: '[[global:best]]',
|
crumb: '[[global:best]]',
|
||||||
|
getSets: function (callerUid, userData, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read', next);
|
||||||
|
},
|
||||||
|
function (cids, next) {
|
||||||
|
next(null, cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':pids:votes'));
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'account/watched': {
|
'account/watched': {
|
||||||
set: 'followed_tids',
|
|
||||||
type: 'topics',
|
type: 'topics',
|
||||||
noItemsFoundKey: '[[user:has_no_watched_topics]]',
|
noItemsFoundKey: '[[user:has_no_watched_topics]]',
|
||||||
crumb: '[[user:watched]]',
|
crumb: '[[user:watched]]',
|
||||||
|
getSets: function (callerUid, userData, calback) {
|
||||||
|
setImmediate(calback, null, 'uid:' + userData.uid + ':followed_tids');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'account/ignored': {
|
'account/ignored': {
|
||||||
set: 'ignored_tids',
|
|
||||||
type: 'topics',
|
type: 'topics',
|
||||||
noItemsFoundKey: '[[user:has_no_ignored_topics]]',
|
noItemsFoundKey: '[[user:has_no_ignored_topics]]',
|
||||||
crumb: '[[user:ignored]]',
|
crumb: '[[user:ignored]]',
|
||||||
|
getSets: function (callerUid, userData, calback) {
|
||||||
|
setImmediate(calback, null, 'uid:' + userData.uid + ':ignored_tids');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'account/topics': {
|
'account/topics': {
|
||||||
set: 'topics',
|
|
||||||
type: 'topics',
|
type: 'topics',
|
||||||
noItemsFoundKey: '[[user:has_no_topics]]',
|
noItemsFoundKey: '[[user:has_no_topics]]',
|
||||||
crumb: '[[global:topics]]',
|
crumb: '[[global:topics]]',
|
||||||
|
getSets: function (callerUid, userData, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read', next);
|
||||||
|
},
|
||||||
|
function (cids, next) {
|
||||||
|
next(null, cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':tids'));
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -98,9 +136,8 @@ postsController.getTopics = function (req, res, next) {
|
|||||||
|
|
||||||
function getFromUserSet(template, req, res, callback) {
|
function getFromUserSet(template, req, res, callback) {
|
||||||
var data = templateToData[template];
|
var data = templateToData[template];
|
||||||
data.template = template;
|
|
||||||
data.method = data.type === 'posts' ? posts.getPostSummariesFromSet : topics.getTopicsFromSet;
|
|
||||||
var userData;
|
var userData;
|
||||||
|
var settings;
|
||||||
var itemsPerPage;
|
var itemsPerPage;
|
||||||
var page = Math.max(1, parseInt(req.query.page, 10) || 1);
|
var page = Math.max(1, parseInt(req.query.page, 10) || 1);
|
||||||
|
|
||||||
@@ -121,15 +158,16 @@ function getFromUserSet(template, req, res, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
userData = results.userData;
|
userData = results.userData;
|
||||||
|
settings = results.settings;
|
||||||
|
itemsPerPage = data.type === 'topics' ? settings.topicsPerPage : settings.postsPerPage;
|
||||||
|
|
||||||
var setName = 'uid:' + userData.uid + ':' + data.set;
|
data.getSets(req.uid, userData, next);
|
||||||
|
},
|
||||||
itemsPerPage = (data.template === 'account/topics' || data.template === 'account/watched') ? results.settings.topicsPerPage : results.settings.postsPerPage;
|
function (sets, next) {
|
||||||
|
|
||||||
async.parallel({
|
async.parallel({
|
||||||
itemCount: function (next) {
|
itemCount: function (next) {
|
||||||
if (results.settings.usePagination) {
|
if (settings.usePagination) {
|
||||||
db.sortedSetCard(setName, next);
|
db.sortedSetsCardSum(sets, next);
|
||||||
} else {
|
} else {
|
||||||
next(null, 0);
|
next(null, 0);
|
||||||
}
|
}
|
||||||
@@ -137,7 +175,8 @@ function getFromUserSet(template, req, res, callback) {
|
|||||||
data: function (next) {
|
data: function (next) {
|
||||||
var start = (page - 1) * itemsPerPage;
|
var start = (page - 1) * itemsPerPage;
|
||||||
var stop = start + itemsPerPage - 1;
|
var stop = start + itemsPerPage - 1;
|
||||||
data.method(setName, req.uid, start, stop, next);
|
const method = data.type === 'topics' ? topics.getTopicsFromSet : posts.getPostSummariesFromSet;
|
||||||
|
method(sets, req.uid, start, stop, next);
|
||||||
},
|
},
|
||||||
}, next);
|
}, next);
|
||||||
},
|
},
|
||||||
@@ -149,10 +188,10 @@ function getFromUserSet(template, req, res, callback) {
|
|||||||
userData.pagination = pagination.create(page, pageCount);
|
userData.pagination = pagination.create(page, pageCount);
|
||||||
|
|
||||||
userData.noItemsFoundKey = data.noItemsFoundKey;
|
userData.noItemsFoundKey = data.noItemsFoundKey;
|
||||||
userData.title = '[[pages:' + data.template + ', ' + userData.username + ']]';
|
userData.title = '[[pages:' + template + ', ' + userData.username + ']]';
|
||||||
userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: data.crumb }]);
|
userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: data.crumb }]);
|
||||||
|
|
||||||
res.render(data.template, userData);
|
res.render(template, userData);
|
||||||
},
|
},
|
||||||
], callback);
|
], callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ var nconf = require('nconf');
|
|||||||
var async = require('async');
|
var async = require('async');
|
||||||
|
|
||||||
const db = require('../../database');
|
const db = require('../../database');
|
||||||
const privileges = require('../../privileges');
|
|
||||||
var user = require('../../user');
|
var user = require('../../user');
|
||||||
var posts = require('../../posts');
|
var posts = require('../../posts');
|
||||||
|
const categories = require('../../categories');
|
||||||
var plugins = require('../../plugins');
|
var plugins = require('../../plugins');
|
||||||
var meta = require('../../meta');
|
var meta = require('../../meta');
|
||||||
var accountHelpers = require('./helpers');
|
var accountHelpers = require('./helpers');
|
||||||
@@ -103,34 +103,23 @@ profileController.get = function (req, res, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function getLatestPosts(callerUid, userData, callback) {
|
function getLatestPosts(callerUid, userData, callback) {
|
||||||
async.waterfall([
|
getPosts(callerUid, userData, 'pids', callback);
|
||||||
function (next) {
|
|
||||||
db.getSortedSetRevRange('uid:' + userData.uid + ':posts', 0, 99, next);
|
|
||||||
},
|
|
||||||
function (pids, next) {
|
|
||||||
getPosts(callerUid, pids, next);
|
|
||||||
},
|
|
||||||
], callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBestPosts(callerUid, userData, callback) {
|
function getBestPosts(callerUid, userData, callback) {
|
||||||
async.waterfall([
|
getPosts(callerUid, userData, 'pids:votes', callback);
|
||||||
function (next) {
|
|
||||||
db.getSortedSetRevRange('uid:' + userData.uid + ':posts:votes', 0, 99, next);
|
|
||||||
},
|
|
||||||
function (pids, next) {
|
|
||||||
getPosts(callerUid, pids, next);
|
|
||||||
},
|
|
||||||
], callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPosts(callerUid, pids, callback) {
|
function getPosts(callerUid, userData, setSuffix, callback) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
privileges.posts.filter('topics:read', pids, callerUid, next);
|
categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read', next);
|
||||||
|
},
|
||||||
|
function (cids, next) {
|
||||||
|
const keys = cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':' + setSuffix);
|
||||||
|
db.getSortedSetRevRange(keys, 0, 9, next);
|
||||||
},
|
},
|
||||||
function (pids, next) {
|
function (pids, next) {
|
||||||
pids = pids.slice(0, 10);
|
|
||||||
posts.getPostSummaryByPids(pids, callerUid, { stripTags: false }, next);
|
posts.getPostSummaryByPids(pids, callerUid, { stripTags: false }, next);
|
||||||
},
|
},
|
||||||
], callback);
|
], callback);
|
||||||
|
|||||||
@@ -162,6 +162,17 @@ module.exports = function (db, module) {
|
|||||||
async.map(keys, module.sortedSetCard, callback);
|
async.map(keys, module.sortedSetCard, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.sortedSetsCardSum = function (keys, callback) {
|
||||||
|
if (!keys || (Array.isArray(keys) && !keys.length)) {
|
||||||
|
return callback(null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.collection('objects').countDocuments({ _key: Array.isArray(keys) ? { $in: keys } : keys }, function (err, count) {
|
||||||
|
count = parseInt(count, 10);
|
||||||
|
callback(err, count || 0);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.sortedSetRank = function (key, value, callback) {
|
module.sortedSetRank = function (key, value, callback) {
|
||||||
getSortedSetRank(false, key, value, callback);
|
getSortedSetRank(false, key, value, callback);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -259,6 +259,22 @@ SELECT o."_key" k,
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.sortedSetsCardSum = function (keys, callback) {
|
||||||
|
if (!keys || (Array.isArray(keys) && !keys.length)) {
|
||||||
|
return callback(null, 0);
|
||||||
|
}
|
||||||
|
if (!Array.isArray(keys)) {
|
||||||
|
keys = [keys];
|
||||||
|
}
|
||||||
|
module.sortedSetsCard(keys, function (err, counts) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
const sum = counts.reduce(function (acc, val) { return acc + val; }, 0);
|
||||||
|
callback(null, sum);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.sortedSetRank = function (key, value, callback) {
|
module.sortedSetRank = function (key, value, callback) {
|
||||||
getSortedSetRank('ASC', [key], [value], function (err, result) {
|
getSortedSetRank('ASC', [key], [value], function (err, result) {
|
||||||
callback(err, result ? result[0] : null);
|
callback(err, result ? result[0] : null);
|
||||||
|
|||||||
@@ -129,6 +129,22 @@ module.exports = function (redisClient, module) {
|
|||||||
batch.exec(callback);
|
batch.exec(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.sortedSetsCardSum = function (keys, callback) {
|
||||||
|
if (!keys || (Array.isArray(keys) && !keys.length)) {
|
||||||
|
return callback(null, 0);
|
||||||
|
}
|
||||||
|
if (!Array.isArray(keys)) {
|
||||||
|
keys = [keys];
|
||||||
|
}
|
||||||
|
module.sortedSetsCard(keys, function (err, counts) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
const sum = counts.reduce(function (acc, val) { return acc + val; }, 0);
|
||||||
|
callback(null, sum);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.sortedSetRank = function (key, value, callback) {
|
module.sortedSetRank = function (key, value, callback) {
|
||||||
redisClient.zrank(key, value, callback);
|
redisClient.zrank(key, value, callback);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ module.exports = function (Posts) {
|
|||||||
const tasks = [
|
const tasks = [
|
||||||
async.apply(db.decrObjectField, 'global', 'postCount'),
|
async.apply(db.decrObjectField, 'global', 'postCount'),
|
||||||
async.apply(db.decrObjectField, 'category:' + topicData.cid, 'post_count'),
|
async.apply(db.decrObjectField, 'category:' + topicData.cid, 'post_count'),
|
||||||
|
async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':uid:' + postData.uid + ':pids', postData.pid),
|
||||||
|
async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':uid:' + postData.uid + ':pids:votes', postData.pid),
|
||||||
async.apply(topics.decreasePostCount, postData.tid),
|
async.apply(topics.decreasePostCount, postData.tid),
|
||||||
async.apply(topics.updateTeaser, postData.tid),
|
async.apply(topics.updateTeaser, postData.tid),
|
||||||
async.apply(topics.updateLastPostTimeFromLastPid, postData.tid),
|
async.apply(topics.updateLastPostTimeFromLastPid, postData.tid),
|
||||||
|
|||||||
@@ -144,23 +144,16 @@ Posts.updatePostVoteCount = function (postData, callback) {
|
|||||||
}
|
}
|
||||||
async.parallel([
|
async.parallel([
|
||||||
function (next) {
|
function (next) {
|
||||||
if (postData.uid) {
|
let cid;
|
||||||
if (postData.votes > 0) {
|
|
||||||
db.sortedSetAdd('uid:' + postData.uid + ':posts:votes', postData.votes, postData.pid, next);
|
|
||||||
} else {
|
|
||||||
db.sortedSetRemove('uid:' + postData.uid + ':posts:votes', postData.pid, next);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
topics.getTopicFields(postData.tid, ['mainPid', 'cid', 'pinned'], next);
|
topics.getTopicFields(postData.tid, ['mainPid', 'cid', 'pinned'], next);
|
||||||
},
|
},
|
||||||
function (topicData, next) {
|
function (topicData, next) {
|
||||||
if (parseInt(topicData.mainPid, 10) === parseInt(postData.pid, 10)) {
|
cid = topicData.cid;
|
||||||
|
if (parseInt(topicData.mainPid, 10) !== parseInt(postData.pid, 10)) {
|
||||||
|
return db.sortedSetAdd('tid:' + postData.tid + ':posts:votes', postData.votes, postData.pid, next);
|
||||||
|
}
|
||||||
async.parallel([
|
async.parallel([
|
||||||
function (next) {
|
function (next) {
|
||||||
topics.setTopicFields(postData.tid, {
|
topics.setTopicFields(postData.tid, {
|
||||||
@@ -181,9 +174,17 @@ Posts.updatePostVoteCount = function (postData, callback) {
|
|||||||
], function (err) {
|
], function (err) {
|
||||||
next(err);
|
next(err);
|
||||||
});
|
});
|
||||||
return;
|
},
|
||||||
|
function (next) {
|
||||||
|
if (postData.uid) {
|
||||||
|
if (postData.votes > 0) {
|
||||||
|
db.sortedSetAdd('cid:' + cid + ':uid:' + postData.uid + ':pids:votes', postData.votes, postData.pid, next);
|
||||||
|
} else {
|
||||||
|
db.sortedSetRemove('cid:' + cid + ':uid:' + postData.uid + ':pids:votes', postData.pid, next);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
}
|
}
|
||||||
db.sortedSetAdd('tid:' + postData.tid + ':posts:votes', postData.votes, postData.pid, next);
|
|
||||||
},
|
},
|
||||||
], next);
|
], next);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ var privileges = require('../privileges');
|
|||||||
var plugins = require('../plugins');
|
var plugins = require('../plugins');
|
||||||
var meta = require('../meta');
|
var meta = require('../meta');
|
||||||
var topics = require('../topics');
|
var topics = require('../topics');
|
||||||
|
const categories = require('../categories');
|
||||||
var user = require('../user');
|
var user = require('../user');
|
||||||
var websockets = require('./index');
|
var websockets = require('./index');
|
||||||
var socketHelpers = require('./helpers');
|
var socketHelpers = require('./helpers');
|
||||||
@@ -135,11 +136,27 @@ SocketPosts.loadMoreBookmarks = function (socket, data, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
SocketPosts.loadMoreUserPosts = function (socket, data, callback) {
|
SocketPosts.loadMoreUserPosts = function (socket, data, callback) {
|
||||||
loadMorePosts('uid:' + data.uid + ':posts', socket.uid, data, callback);
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
categories.getCidsByPrivilege('categories:cid', socket.uid, 'topics:read', next);
|
||||||
|
},
|
||||||
|
function (cids, next) {
|
||||||
|
const keys = cids.map(c => 'cid:' + c + ':uid:' + data.uid + ':pids');
|
||||||
|
loadMorePosts(keys, socket.uid, data, next);
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketPosts.loadMoreBestPosts = function (socket, data, callback) {
|
SocketPosts.loadMoreBestPosts = function (socket, data, callback) {
|
||||||
loadMorePosts('uid:' + data.uid + ':posts:votes', socket.uid, data, callback);
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
categories.getCidsByPrivilege('categories:cid', socket.uid, 'topics:read', next);
|
||||||
|
},
|
||||||
|
function (cids, next) {
|
||||||
|
const keys = cids.map(c => 'cid:' + c + ':uid:' + data.uid + ':pids:votes');
|
||||||
|
loadMorePosts(keys, socket.uid, data, next);
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketPosts.loadMoreUpVotedPosts = function (socket, data, callback) {
|
SocketPosts.loadMoreUpVotedPosts = function (socket, data, callback) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
var async = require('async');
|
var async = require('async');
|
||||||
|
|
||||||
var topics = require('../../topics');
|
var topics = require('../../topics');
|
||||||
|
const categories = require('../../categories');
|
||||||
var privileges = require('../../privileges');
|
var privileges = require('../../privileges');
|
||||||
var meta = require('../../meta');
|
var meta = require('../../meta');
|
||||||
var utils = require('../../utils');
|
var utils = require('../../utils');
|
||||||
@@ -117,6 +118,18 @@ module.exports = function (SocketTopics) {
|
|||||||
topics.getTopicsFromSet(data.set, socket.uid, start, stop, callback);
|
topics.getTopicsFromSet(data.set, socket.uid, start, stop, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SocketTopics.loadMoreUserTopics = function (socket, data, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
categories.getCidsByPrivilege('categories:cid', socket.uid, 'topics:read', next);
|
||||||
|
},
|
||||||
|
function (cids, next) {
|
||||||
|
data.set = cids.map(c => 'cid:' + c + ':uid:' + data.uid + ':tids');
|
||||||
|
SocketTopics.loadMoreFromSet(socket, data, next);
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
};
|
||||||
|
|
||||||
function calculateStartStop(data) {
|
function calculateStartStop(data) {
|
||||||
var itemsPerPage = Math.min(meta.config.topicsPerPage || 20, parseInt(data.count, 10) || meta.config.topicsPerPage || 20);
|
var itemsPerPage = Math.min(meta.config.topicsPerPage || 20, parseInt(data.count, 10) || meta.config.topicsPerPage || 20);
|
||||||
var start = Math.max(0, parseInt(data.after, 10));
|
var start = Math.max(0, parseInt(data.after, 10));
|
||||||
|
|||||||
@@ -158,13 +158,22 @@ module.exports = function (Topics) {
|
|||||||
if (topicData[0].cid === topicData[1].cid) {
|
if (topicData[0].cid === topicData[1].cid) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
const removeFrom = [
|
||||||
async.parallel([
|
'cid:' + topicData[0].cid + ':pids',
|
||||||
|
'cid:' + topicData[0].cid + ':uid:' + postData.uid + ':pids',
|
||||||
|
'cid:' + topicData[0].cid + ':uid:' + postData.uid + ':pids:votes',
|
||||||
|
];
|
||||||
|
const tasks = [
|
||||||
async.apply(db.incrObjectFieldBy, 'category:' + topicData[0].cid, 'post_count', -1),
|
async.apply(db.incrObjectFieldBy, 'category:' + topicData[0].cid, 'post_count', -1),
|
||||||
async.apply(db.incrObjectFieldBy, 'category:' + topicData[1].cid, 'post_count', 1),
|
async.apply(db.incrObjectFieldBy, 'category:' + topicData[1].cid, 'post_count', 1),
|
||||||
async.apply(db.sortedSetRemove, 'cid:' + topicData[0].cid + ':pids', postData.pid),
|
async.apply(db.sortedSetRemove, removeFrom, postData.pid),
|
||||||
async.apply(db.sortedSetAdd, 'cid:' + topicData[1].cid + ':pids', postData.timestamp, postData.pid),
|
async.apply(db.sortedSetAdd, 'cid:' + topicData[1].cid + ':pids', postData.timestamp, postData.pid),
|
||||||
], next);
|
async.apply(db.sortedSetAdd, 'cid:' + topicData[1].cid + ':uid:' + postData.uid + ':pids', postData.timestamp, postData.pid),
|
||||||
|
];
|
||||||
|
if (postData.votes > 0) {
|
||||||
|
tasks.push(async.apply(db.sortedSetAdd, 'cid:' + topicData[1].cid + ':uid:' + postData.uid + ':pids:votes', postData.votes, postData.pid));
|
||||||
|
}
|
||||||
|
async.parallel(tasks, next);
|
||||||
},
|
},
|
||||||
], callback);
|
], callback);
|
||||||
}
|
}
|
||||||
|
|||||||
54
src/upgrades/1.12.3/user_pid_sets.js
Normal file
54
src/upgrades/1.12.3/user_pid_sets.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const async = require('async');
|
||||||
|
|
||||||
|
const db = require('../../database');
|
||||||
|
const batch = require('../../batch');
|
||||||
|
const posts = require('../../posts');
|
||||||
|
const topics = require('../../topics');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Create zsets for user posts per category',
|
||||||
|
timestamp: Date.UTC(2019, 5, 23),
|
||||||
|
method: function (callback) {
|
||||||
|
const progress = this.progress;
|
||||||
|
|
||||||
|
batch.processSortedSet('posts:pid', function (pids, next) {
|
||||||
|
async.eachSeries(pids, function (pid, _next) {
|
||||||
|
progress.incr();
|
||||||
|
let postData;
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
posts.getPostFields(pid, ['uid', 'tid', 'upvotes', 'downvotes', 'timestamp'], next);
|
||||||
|
},
|
||||||
|
function (_postData, next) {
|
||||||
|
if (!_postData.uid || !_postData.tid) {
|
||||||
|
return _next();
|
||||||
|
}
|
||||||
|
postData = _postData;
|
||||||
|
topics.getTopicField(postData.tid, 'cid', next);
|
||||||
|
},
|
||||||
|
function (cid, next) {
|
||||||
|
const keys = [
|
||||||
|
'cid:' + cid + ':uid:' + postData.uid + ':pids',
|
||||||
|
];
|
||||||
|
const scores = [
|
||||||
|
postData.timestamp,
|
||||||
|
];
|
||||||
|
if (postData.votes > 0) {
|
||||||
|
keys.push('cid:' + cid + ':uid:' + postData.uid + ':pids:votes');
|
||||||
|
scores.push(postData.votes);
|
||||||
|
}
|
||||||
|
db.sortedSetsAdd(keys, scores, pid, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
db.sortedSetRemove('uid:' + postData.uid + ':posts:votes', pid, next);
|
||||||
|
},
|
||||||
|
], _next);
|
||||||
|
}, next);
|
||||||
|
}, {
|
||||||
|
progress: progress,
|
||||||
|
}, callback);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -392,7 +392,7 @@ describe('Sorted Set methods', function () {
|
|||||||
describe('sortedSetsCard()', function () {
|
describe('sortedSetsCard()', function () {
|
||||||
it('should return the number of elements in sorted sets', function (done) {
|
it('should return the number of elements in sorted sets', function (done) {
|
||||||
db.sortedSetsCard(['sortedSetTest1', 'sortedSetTest2', 'doesnotexist'], function (err, counts) {
|
db.sortedSetsCard(['sortedSetTest1', 'sortedSetTest2', 'doesnotexist'], function (err, counts) {
|
||||||
assert.equal(err, null);
|
assert.ifError(err);
|
||||||
assert.equal(arguments.length, 2);
|
assert.equal(arguments.length, 2);
|
||||||
assert.deepEqual(counts, [3, 2, 0]);
|
assert.deepEqual(counts, [3, 2, 0]);
|
||||||
done();
|
done();
|
||||||
@@ -418,6 +418,44 @@ describe('Sorted Set methods', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('sortedSetsCardSum()', function () {
|
||||||
|
it('should return the total number of elements in sorted sets', function (done) {
|
||||||
|
db.sortedSetsCardSum(['sortedSetTest1', 'sortedSetTest2', 'doesnotexist'], function (err, sum) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.equal(arguments.length, 2);
|
||||||
|
assert.equal(sum, 5);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 0 if keys is falsy', function (done) {
|
||||||
|
db.sortedSetsCardSum(undefined, function (err, counts) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.equal(arguments.length, 2);
|
||||||
|
assert.deepEqual(counts, 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 0 if keys is empty array', function (done) {
|
||||||
|
db.sortedSetsCardSum([], function (err, counts) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.equal(arguments.length, 2);
|
||||||
|
assert.deepEqual(counts, 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the total number of elements in sorted set', function (done) {
|
||||||
|
db.sortedSetsCardSum('sortedSetTest1', function (err, sum) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.equal(arguments.length, 2);
|
||||||
|
assert.equal(sum, 3);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('sortedSetRank()', function () {
|
describe('sortedSetRank()', function () {
|
||||||
it('should return falsy if sorted set does not exist', function (done) {
|
it('should return falsy if sorted set does not exist', function (done) {
|
||||||
db.sortedSetRank('doesnotexist', 'value1', function (err, rank) {
|
db.sortedSetRank('doesnotexist', 'value1', function (err, rank) {
|
||||||
|
|||||||
Reference in New Issue
Block a user