From 6399b428263d30e652e26a05940d1e3112e93dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 28 Sep 2021 11:13:56 -0400 Subject: [PATCH] feat: closes #9845, sort by views --- public/language/en-GB/topic.json | 1 + src/categories/delete.js | 1 + src/categories/topics.js | 4 +++- src/topics/create.js | 1 + src/topics/delete.js | 1 + src/topics/posts.js | 5 +++-- src/topics/scheduled.js | 2 ++ src/topics/sorted.js | 5 +++++ src/topics/tools.js | 4 ++++ src/upgrades/1.18.4/category_topics_views.js | 23 ++++++++++++++++++++ 10 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/upgrades/1.18.4/category_topics_views.js diff --git a/public/language/en-GB/topic.json b/public/language/en-GB/topic.json index b95a86c862..201b6df316 100644 --- a/public/language/en-GB/topic.json +++ b/public/language/en-GB/topic.json @@ -180,6 +180,7 @@ "newest_to_oldest": "Newest to Oldest", "most_votes": "Most Votes", "most_posts": "Most Posts", + "most_views": "Most Views", "stale.title": "Create new topic instead?", "stale.warning": "The topic you are replying to is quite old. Would you like to create a new topic instead, and reference this one in your reply?", diff --git a/src/categories/delete.js b/src/categories/delete.js index 539ce20b19..ff491a5dbc 100644 --- a/src/categories/delete.js +++ b/src/categories/delete.js @@ -39,6 +39,7 @@ module.exports = function (Categories) { `cid:${cid}:tids:pinned`, `cid:${cid}:tids:posts`, `cid:${cid}:tids:votes`, + `cid:${cid}:tids:views`, `cid:${cid}:tids:lastposttime`, `cid:${cid}:recent_tids`, `cid:${cid}:pids`, diff --git a/src/categories/topics.js b/src/categories/topics.js index 381776738d..fdba6ab59d 100644 --- a/src/categories/topics.js +++ b/src/categories/topics.js @@ -100,6 +100,8 @@ module.exports = function (Categories) { set = `cid:${cid}:tids:posts`; } else if (sort === 'most_votes') { set = `cid:${cid}:tids:votes`; + } else if (sort === 'most_views') { + set = `cid:${cid}:tids:views`; } if (data.tag) { @@ -123,7 +125,7 @@ module.exports = function (Categories) { Categories.getSortedSetRangeDirection = async function (sort) { sort = sort || 'newest_to_oldest'; - const direction = sort === 'newest_to_oldest' || sort === 'most_posts' || sort === 'most_votes' ? 'highest-to-lowest' : 'lowest-to-highest'; + const direction = ['newest_to_oldest', 'most_posts', 'most_votes', 'most_views'].includes(sort) ? 'highest-to-lowest' : 'lowest-to-highest'; const result = await plugins.hooks.fire('filter:categories.getSortedSetRangeDirection', { sort: sort, direction: direction, diff --git a/src/topics/create.js b/src/topics/create.js index c9ac208ea9..2eac1a2f65 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -60,6 +60,7 @@ module.exports = function (Topics) { 'topics:views', 'topics:posts', 'topics:votes', `cid:${topicData.cid}:tids:votes`, `cid:${topicData.cid}:tids:posts`, + `cid:${topicData.cid}:tids:views`, ], 0, topicData.tid), user.addTopicIdToUser(topicData.uid, topicData.tid, timestamp), db.incrObjectField(`category:${topicData.cid}`, 'topic_count'), diff --git a/src/topics/delete.js b/src/topics/delete.js index 889f129c76..3e84a29cc8 100644 --- a/src/topics/delete.js +++ b/src/topics/delete.js @@ -125,6 +125,7 @@ module.exports = function (Topics) { `cid:${topicData.cid}:tids:posts`, `cid:${topicData.cid}:tids:lastposttime`, `cid:${topicData.cid}:tids:votes`, + `cid:${topicData.cid}:tids:views`, `cid:${topicData.cid}:recent_tids`, `cid:${topicData.cid}:uid:${topicData.uid}:tids`, `uid:${topicData.uid}:topics`, diff --git a/src/topics/posts.js b/src/topics/posts.js index ed6f6089ad..457e337fd6 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -208,12 +208,13 @@ module.exports = function (Topics) { }; Topics.increaseViewCount = async function (tid) { - incrementFieldAndUpdateSortedSet(tid, 'viewcount', 1, 'topics:views'); + const cid = await Topics.getTopicField(tid, 'cid'); + incrementFieldAndUpdateSortedSet(tid, 'viewcount', 1, ['topics:views', `cid:${cid}:tids:views`]); }; async function incrementFieldAndUpdateSortedSet(tid, field, by, set) { const value = await db.incrObjectFieldBy(`topic:${tid}`, field, by); - await db.sortedSetAdd(set, value, tid); + await db[Array.isArray(set) ? 'sortedSetsAdd' : 'sortedSetAdd'](set, value, tid); } Topics.getTitleByPid = async function (pid) { diff --git a/src/topics/scheduled.js b/src/topics/scheduled.js index ab9cb04ef0..5d99b1432b 100644 --- a/src/topics/scheduled.js +++ b/src/topics/scheduled.js @@ -54,6 +54,7 @@ Scheduled.pin = async function (tid, topicData) { `cid:${topicData.cid}:tids`, `cid:${topicData.cid}:tids:posts`, `cid:${topicData.cid}:tids:votes`, + `cid:${topicData.cid}:tids:views`, ], tid), ]); }; @@ -80,6 +81,7 @@ function unpin(tid, topicData) { [`cid:${topicData.cid}:tids`, topicData.lastposttime, tid], [`cid:${topicData.cid}:tids:posts`, topicData.postcount, tid], [`cid:${topicData.cid}:tids:votes`, parseInt(topicData.votes, 10) || 0, tid], + [`cid:${topicData.cid}:tids:views`, topicData.viewcount, tid], ]), ]; } diff --git a/src/topics/sorted.js b/src/topics/sorted.js index 52f96ed59e..af2cd344cb 100644 --- a/src/topics/sorted.js +++ b/src/topics/sorted.js @@ -118,6 +118,7 @@ module.exports = function (Topics) { old: sortOld, posts: sortPopular, votes: sortVotes, + views: sortViews, }; const sortFn = sortMap[params.sort] || sortRecent; @@ -156,6 +157,10 @@ module.exports = function (Topics) { return b.viewcount - a.viewcount; } + function sortViews(a, b) { + return b.viewcount - a.viewcount; + } + async function filterTids(tids, params) { const { filter } = params; const { uid } = params; diff --git a/src/topics/tools.js b/src/topics/tools.js index fa0d32aad9..887f166247 100644 --- a/src/topics/tools.js +++ b/src/topics/tools.js @@ -173,6 +173,7 @@ module.exports = function (Topics) { `cid:${topicData.cid}:tids`, `cid:${topicData.cid}:tids:posts`, `cid:${topicData.cid}:tids:votes`, + `cid:${topicData.cid}:tids:views`, ], tid)); } else { promises.push(db.sortedSetRemove(`cid:${topicData.cid}:tids:pinned`, tid)); @@ -181,6 +182,7 @@ module.exports = function (Topics) { [`cid:${topicData.cid}:tids`, topicData.lastposttime, tid], [`cid:${topicData.cid}:tids:posts`, topicData.postcount, tid], [`cid:${topicData.cid}:tids:votes`, parseInt(topicData.votes, 10) || 0, tid], + [`cid:${topicData.cid}:tids:views`, topicData.viewcount, tid], ])); topicData.pinExpiry = undefined; topicData.pinExpiryISO = undefined; @@ -243,6 +245,7 @@ module.exports = function (Topics) { `cid:${topicData.cid}:tids:pinned`, `cid:${topicData.cid}:tids:posts`, `cid:${topicData.cid}:tids:votes`, + `cid:${topicData.cid}:tids:views`, `cid:${topicData.cid}:tids:lastposttime`, `cid:${topicData.cid}:recent_tids`, `cid:${topicData.cid}:uid:${topicData.uid}:tids`, @@ -263,6 +266,7 @@ module.exports = function (Topics) { bulk.push([`cid:${cid}:tids`, topicData.lastposttime, tid]); bulk.push([`cid:${cid}:tids:posts`, topicData.postcount, tid]); bulk.push([`cid:${cid}:tids:votes`, votes, tid]); + bulk.push([`cid:${cid}:tids:views`, topicData.viewcount, tid]); } await db.sortedSetAddBulk(bulk); diff --git a/src/upgrades/1.18.4/category_topics_views.js b/src/upgrades/1.18.4/category_topics_views.js new file mode 100644 index 0000000000..c2d78fbf9e --- /dev/null +++ b/src/upgrades/1.18.4/category_topics_views.js @@ -0,0 +1,23 @@ +'use strict'; + +const db = require('../../database'); +const batch = require('../../batch'); +const topics = require('../../topics'); + +module.exports = { + name: 'Category topics sorted sets by views', + timestamp: Date.UTC(2021, 8, 28), + method: async function () { + const { progress } = this; + + await batch.processSortedSet('topics:tid', async (tids) => { + let topicData = await topics.getTopicsData(tids); + topicData = topicData.filter(t => t && t.cid); + await db.sortedSetAddBulk(topicData.map(t => ([`cid:${t.cid}:tids:views`, t.viewcount || 0, t.tid]))); + progress.incr(tids.length); + }, { + batch: 500, + progress: progress, + }); + }, +};