mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-05-07 05:26:44 +02:00
refactor: /world sorting logic to always use topics/sorted logic
- New params for getSortedTopics (includeRemote, followingOnly) - Ability to show latest (followers only) or latest (all), ?all query param to discriminate - World now always shows posts from the local forum - Popular sort will be followers-only + local
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "World",
|
"name": "World",
|
||||||
"latest": "Latest",
|
"latest": "Latest (Following)",
|
||||||
|
"latest-all": "Latest (All)",
|
||||||
"popular-day": "Popular (Day)",
|
"popular-day": "Popular (Day)",
|
||||||
"popular-week": "Popular (Week)",
|
"popular-week": "Popular (Week)",
|
||||||
"popular-month": "Popular (Month)",
|
"popular-month": "Popular (Month)",
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
const db = require('../../database');
|
|
||||||
const meta = require('../../meta');
|
const meta = require('../../meta');
|
||||||
const user = require('../../user');
|
const user = require('../../user');
|
||||||
const topics = require('../../topics');
|
const topics = require('../../topics');
|
||||||
@@ -20,8 +19,8 @@ controller.list = async function (req, res) {
|
|||||||
const { topicsPerPage } = await user.getSettings(req.uid);
|
const { topicsPerPage } = await user.getSettings(req.uid);
|
||||||
let { page, after } = req.query;
|
let { page, after } = req.query;
|
||||||
page = parseInt(page, 10) || 1;
|
page = parseInt(page, 10) || 1;
|
||||||
let start = Math.max(0, (page - 1) * topicsPerPage);
|
const start = Math.max(0, (page - 1) * topicsPerPage);
|
||||||
let stop = start + topicsPerPage - 1;
|
const stop = start + topicsPerPage - 1;
|
||||||
|
|
||||||
const [userSettings, userPrivileges] = await Promise.all([
|
const [userSettings, userPrivileges] = await Promise.all([
|
||||||
user.getSettings(req.uid),
|
user.getSettings(req.uid),
|
||||||
@@ -50,27 +49,24 @@ controller.list = async function (req, res) {
|
|||||||
if (req.query.sort === 'popular') {
|
if (req.query.sort === 'popular') {
|
||||||
cidQuery = {
|
cidQuery = {
|
||||||
...cidQuery,
|
...cidQuery,
|
||||||
cids: ['-1'],
|
|
||||||
sort: 'posts',
|
sort: 'posts',
|
||||||
term: req.query.term || 'day',
|
term: req.query.term || 'day',
|
||||||
|
includeRemote: true,
|
||||||
|
followingOnly: !req.query.all || !parseInt(req.query.all, 10),
|
||||||
};
|
};
|
||||||
delete cidQuery.cid;
|
delete cidQuery.cid;
|
||||||
({ tids, topicCount } = await topics.getSortedTopics(cidQuery));
|
({ tids, topicCount } = await topics.getSortedTopics(cidQuery));
|
||||||
tids = tids.slice(start, stop !== -1 ? stop + 1 : undefined);
|
tids = tids.slice(start, stop !== -1 ? stop + 1 : undefined);
|
||||||
} else {
|
} else {
|
||||||
if (after) {
|
cidQuery = {
|
||||||
// Update start/stop with values inferred from `after`
|
...cidQuery,
|
||||||
const set = await categories.buildTopicsSortedSet(cidQuery);
|
term: req.query.term,
|
||||||
const index = await db.sortedSetRevRank(set, decodeURIComponent(after));
|
includeRemote: true,
|
||||||
if (index && start - index < 1) {
|
followingOnly: !req.query.all || !parseInt(req.query.all, 10),
|
||||||
const count = stop - start;
|
};
|
||||||
start = index + 1;
|
delete cidQuery.cid;
|
||||||
stop = start + count;
|
({ tids, topicCount } = await topics.getSortedTopics(cidQuery));
|
||||||
}
|
tids = tids.slice(start, stop !== -1 ? stop + 1 : undefined);
|
||||||
}
|
|
||||||
|
|
||||||
tids = await categories.getTopicIds({ ...cidQuery, start, stop });
|
|
||||||
topicCount = await categories.getTopicCount(cidQuery);
|
|
||||||
}
|
}
|
||||||
data.topicCount = topicCount;
|
data.topicCount = topicCount;
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ module.exports = function (Topics) {
|
|||||||
let tids;
|
let tids;
|
||||||
if (params.term !== 'alltime') {
|
if (params.term !== 'alltime') {
|
||||||
if (params.sort === 'posts') {
|
if (params.sort === 'posts') {
|
||||||
tids = await getTidsWithMostPostsInTerm(params.cids, params.uid, params.term);
|
const { cids, uid, term, includeRemote, followingOnly } = params;
|
||||||
|
tids = await getTidsWithMostPostsInTerm({ cids, uid, term, includeRemote, followingOnly });
|
||||||
} else {
|
} else {
|
||||||
const cids = await getCids(params.cids, params.uid);
|
const cids = await getCids(params.cids, params.uid);
|
||||||
tids = await Topics.getLatestTidsFromSet(
|
tids = await Topics.getLatestTidsFromSet(
|
||||||
@@ -74,17 +75,18 @@ module.exports = function (Topics) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getInbox(tids, params) {
|
async function getInbox(tids, params) {
|
||||||
if (!Array.isArray(params.cids) || !params.cids.includes('-1')) {
|
if (!params.includeRemote) {
|
||||||
return tids;
|
return tids;
|
||||||
}
|
}
|
||||||
|
|
||||||
let inbox;
|
let inbox;
|
||||||
|
const set = params.followingOnly ? `uid:${params.uid}:inbox` : 'cid:-1:tids';
|
||||||
if (params.term !== 'alltime') {
|
if (params.term !== 'alltime') {
|
||||||
const method = params.sort === 'old' ?
|
const method = params.sort === 'old' ?
|
||||||
'getSortedSetRangeByScore' :
|
'getSortedSetRangeByScore' :
|
||||||
'getSortedSetRevRangeByScore';
|
'getSortedSetRevRangeByScore';
|
||||||
inbox = await db[method](
|
inbox = await db[method](
|
||||||
`uid:${params.uid}:inbox`,
|
set,
|
||||||
0,
|
0,
|
||||||
1000,
|
1000,
|
||||||
'+inf',
|
'+inf',
|
||||||
@@ -94,7 +96,7 @@ module.exports = function (Topics) {
|
|||||||
const method = params.sort === 'old' ?
|
const method = params.sort === 'old' ?
|
||||||
'getSortedSetRange' :
|
'getSortedSetRange' :
|
||||||
'getSortedSetRevRange';
|
'getSortedSetRevRange';
|
||||||
inbox = await db[method](`uid:${params.uid}:inbox`, 0, meta.config.recentMaxTopics - 1);
|
inbox = await db[method](set, 0, meta.config.recentMaxTopics - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.uniq(tids.concat(inbox));
|
return _.uniq(tids.concat(inbox));
|
||||||
@@ -115,33 +117,41 @@ module.exports = function (Topics) {
|
|||||||
return 'topics:recent';
|
return 'topics:recent';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCids(cids, uid) {
|
async function getCids(cids, uid, includeRemote) {
|
||||||
if (Array.isArray(cids)) {
|
if (Array.isArray(cids)) {
|
||||||
cids = await privileges.categories.filterCids('topics:read', cids, uid);
|
cids = await privileges.categories.filterCids('topics:read', cids, uid);
|
||||||
} else {
|
} else {
|
||||||
cids = await categories.getCidsByPrivilege('categories:cid', uid, 'topics:read');
|
cids = await categories.getCidsByPrivilege('categories:cid', uid, 'topics:read');
|
||||||
cids = cids.filter(cid => cid !== -1);
|
cids = cids.filter(cid => cid !== -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (includeRemote) {
|
||||||
|
const remoteCids = await db.getObjectValues('handle:cid');
|
||||||
|
cids = [-1, ...cids, ...remoteCids];
|
||||||
|
}
|
||||||
return cids;
|
return cids;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTidsWithMostPostsInTerm(cids, uid, term) {
|
async function getTidsWithMostPostsInTerm({ cids, uid, term, includeRemote, followingOnly }) {
|
||||||
cids = await getCids(cids, uid);
|
cids = await getCids(cids, uid, includeRemote);
|
||||||
const pids = await db.getSortedSetRevRangeByScore(
|
const sets = cids.map(cid => `cid:${cid}:tids`);
|
||||||
cids.map(cid => `cid:${cid}:pids`),
|
if (followingOnly && sets.includes('cid:-1:tids')) {
|
||||||
|
sets.splice(sets.indexOf('cid:-1:tids'), 1, `uid:${uid}:inbox`);
|
||||||
|
}
|
||||||
|
const tids = await db.getSortedSetRevRangeByScore(
|
||||||
|
sets,
|
||||||
0,
|
0,
|
||||||
1000,
|
1000,
|
||||||
'+inf',
|
'+inf',
|
||||||
Date.now() - Topics.getSinceFromTerm(term)
|
Date.now() - Topics.getSinceFromTerm(term)
|
||||||
);
|
);
|
||||||
const postObjs = await db.getObjectsFields(pids.map(pid => `post:${pid}`), ['tid']);
|
|
||||||
const tidToCount = {};
|
const tidToCount = {};
|
||||||
postObjs.forEach((post) => {
|
tids.forEach((tid) => {
|
||||||
tidToCount[post.tid] = tidToCount[post.tid] || 0;
|
tidToCount[tid] = tidToCount[tid] || 0;
|
||||||
tidToCount[post.tid] += 1;
|
tidToCount[tid] += 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
return _.uniq(postObjs.map(post => String(post.tid)))
|
return _.uniq(tids)
|
||||||
.sort((t1, t2) => tidToCount[t2] - tidToCount[t1]);
|
.sort((t1, t2) => tidToCount[t2] - tidToCount[t1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +210,7 @@ module.exports = function (Topics) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function sortTids(tids, params) {
|
async function sortTids(tids, params) {
|
||||||
if (params.term === 'alltime' && !params.cids && !params.tags.length && params.filter !== 'watched' && !params.floatPinned) {
|
if (params.term === 'alltime' && !params.cids && !params.tags.length && params.filter !== 'watched' && !params.floatPinned && !params.includeRemote) {
|
||||||
return tids;
|
return tids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user