diff --git a/public/language/en-GB/world.json b/public/language/en-GB/world.json index 427135352d..58e6526fbb 100644 --- a/public/language/en-GB/world.json +++ b/public/language/en-GB/world.json @@ -1,6 +1,7 @@ { "name": "World", - "latest": "Latest", + "latest": "Latest (Following)", + "latest-all": "Latest (All)", "popular-day": "Popular (Day)", "popular-week": "Popular (Week)", "popular-month": "Popular (Month)", diff --git a/src/controllers/activitypub/topics.js b/src/controllers/activitypub/topics.js index 6aaae596af..702893cac8 100644 --- a/src/controllers/activitypub/topics.js +++ b/src/controllers/activitypub/topics.js @@ -2,7 +2,6 @@ const _ = require('lodash'); -const db = require('../../database'); const meta = require('../../meta'); const user = require('../../user'); const topics = require('../../topics'); @@ -20,8 +19,8 @@ controller.list = async function (req, res) { const { topicsPerPage } = await user.getSettings(req.uid); let { page, after } = req.query; page = parseInt(page, 10) || 1; - let start = Math.max(0, (page - 1) * topicsPerPage); - let stop = start + topicsPerPage - 1; + const start = Math.max(0, (page - 1) * topicsPerPage); + const stop = start + topicsPerPage - 1; const [userSettings, userPrivileges] = await Promise.all([ user.getSettings(req.uid), @@ -50,27 +49,24 @@ controller.list = async function (req, res) { if (req.query.sort === 'popular') { cidQuery = { ...cidQuery, - cids: ['-1'], sort: 'posts', term: req.query.term || 'day', + includeRemote: true, + followingOnly: !req.query.all || !parseInt(req.query.all, 10), }; delete cidQuery.cid; ({ tids, topicCount } = await topics.getSortedTopics(cidQuery)); tids = tids.slice(start, stop !== -1 ? stop + 1 : undefined); } else { - if (after) { - // Update start/stop with values inferred from `after` - const set = await categories.buildTopicsSortedSet(cidQuery); - const index = await db.sortedSetRevRank(set, decodeURIComponent(after)); - if (index && start - index < 1) { - const count = stop - start; - start = index + 1; - stop = start + count; - } - } - - tids = await categories.getTopicIds({ ...cidQuery, start, stop }); - topicCount = await categories.getTopicCount(cidQuery); + cidQuery = { + ...cidQuery, + term: req.query.term, + includeRemote: true, + followingOnly: !req.query.all || !parseInt(req.query.all, 10), + }; + delete cidQuery.cid; + ({ tids, topicCount } = await topics.getSortedTopics(cidQuery)); + tids = tids.slice(start, stop !== -1 ? stop + 1 : undefined); } data.topicCount = topicCount; diff --git a/src/topics/sorted.js b/src/topics/sorted.js index 1d4da1f772..6756fbfe38 100644 --- a/src/topics/sorted.js +++ b/src/topics/sorted.js @@ -46,7 +46,8 @@ module.exports = function (Topics) { let tids; if (params.term !== 'alltime') { 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 { const cids = await getCids(params.cids, params.uid); tids = await Topics.getLatestTidsFromSet( @@ -74,17 +75,18 @@ module.exports = function (Topics) { } async function getInbox(tids, params) { - if (!Array.isArray(params.cids) || !params.cids.includes('-1')) { + if (!params.includeRemote) { return tids; } let inbox; + const set = params.followingOnly ? `uid:${params.uid}:inbox` : 'cid:-1:tids'; if (params.term !== 'alltime') { const method = params.sort === 'old' ? 'getSortedSetRangeByScore' : 'getSortedSetRevRangeByScore'; inbox = await db[method]( - `uid:${params.uid}:inbox`, + set, 0, 1000, '+inf', @@ -94,7 +96,7 @@ module.exports = function (Topics) { const method = params.sort === 'old' ? 'getSortedSetRange' : '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)); @@ -115,33 +117,41 @@ module.exports = function (Topics) { return 'topics:recent'; } - async function getCids(cids, uid) { + async function getCids(cids, uid, includeRemote) { if (Array.isArray(cids)) { cids = await privileges.categories.filterCids('topics:read', cids, uid); } else { cids = await categories.getCidsByPrivilege('categories:cid', uid, 'topics:read'); cids = cids.filter(cid => cid !== -1); } + + if (includeRemote) { + const remoteCids = await db.getObjectValues('handle:cid'); + cids = [-1, ...cids, ...remoteCids]; + } return cids; } - async function getTidsWithMostPostsInTerm(cids, uid, term) { - cids = await getCids(cids, uid); - const pids = await db.getSortedSetRevRangeByScore( - cids.map(cid => `cid:${cid}:pids`), + async function getTidsWithMostPostsInTerm({ cids, uid, term, includeRemote, followingOnly }) { + cids = await getCids(cids, uid, includeRemote); + const sets = cids.map(cid => `cid:${cid}:tids`); + 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, 1000, '+inf', Date.now() - Topics.getSinceFromTerm(term) ); - const postObjs = await db.getObjectsFields(pids.map(pid => `post:${pid}`), ['tid']); const tidToCount = {}; - postObjs.forEach((post) => { - tidToCount[post.tid] = tidToCount[post.tid] || 0; - tidToCount[post.tid] += 1; + tids.forEach((tid) => { + tidToCount[tid] = tidToCount[tid] || 0; + tidToCount[tid] += 1; }); - return _.uniq(postObjs.map(post => String(post.tid))) + return _.uniq(tids) .sort((t1, t2) => tidToCount[t2] - tidToCount[t1]); } @@ -200,7 +210,7 @@ module.exports = function (Topics) { } 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; }