diff --git a/install/package.json b/install/package.json index ae169114e1..1ae35a827b 100644 --- a/install/package.json +++ b/install/package.json @@ -108,7 +108,7 @@ "nodebb-plugin-spam-be-gone": "2.3.0", "nodebb-plugin-web-push": "0.7.0", "nodebb-rewards-essentials": "1.0.0", - "nodebb-theme-harmony": "2.0.0-pre.45", + "nodebb-theme-harmony": "2.0.0-pre.46", "nodebb-theme-lavender": "7.1.17", "nodebb-theme-peace": "2.2.28", "nodebb-theme-persona": "14.0.0-pre.5", diff --git a/public/language/en-GB/pages.json b/public/language/en-GB/pages.json index d9cfd91fcc..ea1867d8a0 100644 --- a/public/language/en-GB/pages.json +++ b/public/language/en-GB/pages.json @@ -70,6 +70,7 @@ "account/blocks": "Blocked users for %1", "account/uploads": "Uploads by %1", "account/sessions": "Login Sessions", + "account/shares": "Topics shared by %1", "confirm": "Email Confirmed", diff --git a/public/language/en-GB/user.json b/public/language/en-GB/user.json index ebe78a25cd..2810fbd3ab 100644 --- a/public/language/en-GB/user.json +++ b/public/language/en-GB/user.json @@ -49,6 +49,7 @@ "default-category-watch-state": "Default category watch state", "followers": "Followers", "following": "Following", + "shares": "Shares", "blocks": "Blocks", "blocked-users": "Blocked users", "block-toggle": "Toggle Block", @@ -129,6 +130,7 @@ "has-no-downvoted-posts": "This user hasn't downvoted any posts yet.", "has-no-controversial-posts": "This user does not have any downvoted posts yet.", "has-no-blocks": "You have blocked no users.", + "has-no-shares": "This user has not shared any topics.", "email-hidden": "Email Hidden", "hidden": "hidden", diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index 592e966f89..58c111dcc0 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -484,8 +484,12 @@ Notes.announce.list = async ({ pid, tid }) => { }; Notes.announce.add = async (pid, actor, timestamp = Date.now()) => { - await db.sortedSetAdd(`pid:${pid}:announces`, timestamp, actor); - await posts.setPostField(pid, 'announces', await db.sortedSetCard(`pid:${pid}:announces`)); + const tid = await posts.getPostField(pid, 'tid'); + await Promise.all([ + db.sortedSetAdd(`pid:${pid}:announces`, timestamp, actor), + posts.setPostField(pid, 'announces', await db.sortedSetCard(`pid:${pid}:announces`)), + topics.tools.share(tid, actor, timestamp), + ]); }; Notes.announce.remove = async (pid, actor) => { diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index 3cc4f19832..dad9892a10 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -265,6 +265,7 @@ async function getCounts(userData, callerUID) { const promises = { posts: db.sortedSetsCardSum(cids.map(c => `cid:${c}:uid:${uid}:pids`)), topics: db.sortedSetsCardSum(cids.map(c => `cid:${c}:uid:${uid}:tids`)), + shares: db.sortedSetCard(`uid:${uid}:shares`), }; if (userData.isAdmin || userData.isSelf) { promises.uploaded = db.sortedSetCard(`uid:${uid}:uploads`); diff --git a/src/controllers/accounts/posts.js b/src/controllers/accounts/posts.js index fa8bc1ac24..9ce048bd28 100644 --- a/src/controllers/accounts/posts.js +++ b/src/controllers/accounts/posts.js @@ -147,6 +147,14 @@ const templateToData = { return cids.map(c => `cid:${c}:uid:${userData.uid}:tids`); }, }, + 'account/shares': { + type: 'topics', + noItemsFoundKey: '[[user:has-no-shares]]', + crumb: '[[user:shares]]', + getSets: async function (callerUid, userData) { + return `uid:${userData.uid}:shares`; + }, + }, }; postsController.getBookmarks = async function (req, res, next) { @@ -189,6 +197,10 @@ postsController.getTopics = async function (req, res, next) { await getPostsFromUserSet('account/topics', req, res, next); }; +postsController.getShares = async function (req, res, next) { + await getPostsFromUserSet('account/shares', req, res, next); +}; + async function getPostsFromUserSet(template, req, res) { const data = templateToData[template]; const page = Math.max(1, parseInt(req.query.page, 10) || 1); diff --git a/src/routes/user.js b/src/routes/user.js index 1eabff84fc..c2d1cc6f32 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -28,6 +28,7 @@ module.exports = function (app, name, middleware, controllers) { setupPageRoute(app, `/${name}/:userslug/topics`, middlewares, controllers.accounts.posts.getTopics); setupPageRoute(app, `/${name}/:userslug/best`, middlewares, controllers.accounts.posts.getBestPosts); setupPageRoute(app, `/${name}/:userslug/controversial`, middlewares, controllers.accounts.posts.getControversialPosts); + setupPageRoute(app, `/${name}/:userslug/shares`, middlewares, controllers.accounts.posts.getShares); setupPageRoute(app, `/${name}/:userslug/groups`, middlewares, controllers.accounts.groups.get); setupPageRoute(app, `/${name}/:userslug/categories`, accountMiddlewares, controllers.accounts.categories.get); diff --git a/src/topics/tools.js b/src/topics/tools.js index 039655a592..e102437ccf 100644 --- a/src/topics/tools.js +++ b/src/topics/tools.js @@ -283,7 +283,9 @@ module.exports = function (Topics) { oldCid: oldCid, }), Topics.updateCategoryTagsCount([oldCid, cid], tags), - Topics.events.log(tid, { type: oldCid === -1 ? 'share' : 'move', uid: data.uid, fromCid: oldCid }), + oldCid !== -1 ? + Topics.events.log(tid, { type: 'move', uid: data.uid, fromCid: oldCid }) : + topicTools.share(tid, data.uid), ]); // Update entry in recent topics zset — must come after hash update @@ -298,4 +300,11 @@ module.exports = function (Topics) { plugins.hooks.fire('action:topic.move', hookData); }; + + topicTools.share = async function (tid, uid, timestamp = Date.now()) { + await Promise.all([ + Topics.events.log(tid, { type: 'share', uid: uid }), + db.sortedSetAdd(`uid:${uid}:shares`, timestamp, tid), + ]); + }; };