From 225bf85e941c95dd0d724ac5b47467918661f806 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 15 Sep 2025 12:47:49 -0400 Subject: [PATCH 1/3] fix: #13657, fix remote category data inconsistency in `sendNotificationToPostOwner` --- src/notifications.js | 20 +++++++++++++++++++- src/socket.io/helpers.js | 11 ++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/notifications.js b/src/notifications.js index bcf27c7d66..e71366417e 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -9,6 +9,7 @@ const _ = require('lodash'); const db = require('./database'); const User = require('./user'); +const categories = require('./categories'); const posts = require('./posts'); const groups = require('./groups'); const meta = require('./meta'); @@ -84,7 +85,24 @@ Notifications.getMultiple = async function (nids) { const notifications = await db.getObjects(keys); const userKeys = notifications.map(n => n && n.from); - const usersData = await User.getUsersFields(userKeys, ['username', 'userslug', 'picture']); + let [usersData, categoriesData] = await Promise.all([ + User.getUsersFields(userKeys, ['username', 'userslug', 'picture']), + categories.getCategoriesFields(userKeys, ['cid', 'name', 'slug', 'picture']), + ]); + // Merge valid categoriesData into usersData + usersData = usersData.map((userData, idx) => { + const categoryData = categoriesData[idx]; + if (!userData.uid && categoryData.cid) { + return { + username: categoryData.slug, + displayname: categoryData.name, + userslug: categoryData.slug, + picture: categoryData.picture, + }; + } + + return userData; + }); notifications.forEach((notification, index) => { if (notification) { diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js index d80638458e..5def5138d4 100644 --- a/src/socket.io/helpers.js +++ b/src/socket.io/helpers.js @@ -94,7 +94,10 @@ SocketHelpers.sendNotificationToPostOwner = async function (pid, fromuid, comman return; } fromuid = utils.isNumber(fromuid) ? parseInt(fromuid, 10) : fromuid; - const postData = await posts.getPostFields(pid, ['tid', 'uid', 'content']); + const [postData, fromCategory] = await Promise.all([ + posts.getPostFields(pid, ['tid', 'uid', 'content']), + !utils.isNumber(fromuid) && categories.exists(fromuid), + ]); const [canRead, isIgnoring] = await Promise.all([ privileges.posts.can('topics:read', pid, postData.uid), topics.isIgnoring([postData.tid], postData.uid), @@ -103,19 +106,17 @@ SocketHelpers.sendNotificationToPostOwner = async function (pid, fromuid, comman return; } const [userData, topicTitle, postObj] = await Promise.all([ - user.getUserFields(fromuid, ['username']), + fromCategory ? categories.getCategoryFields(fromuid, ['name']) : user.getUserFields(fromuid, ['username']), topics.getTopicField(postData.tid, 'title'), posts.parsePost(postData), ]); - const { displayname } = userData; - const title = utils.decodeHTMLEntities(topicTitle); const titleEscaped = title.replace(/%/g, '%').replace(/,/g, ','); const notifObj = await notifications.create({ type: command, - bodyShort: `[[${notification}, ${displayname}, ${titleEscaped}]]`, + bodyShort: `[[${notification}, ${userData.displayname || userData.name}, ${titleEscaped}]]`, bodyLong: postObj.content, pid: pid, tid: postData.tid, From 52fec49310db9957677c3ab3a3a98ae8ad08f903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 15 Sep 2025 12:57:29 -0400 Subject: [PATCH 2/3] chore: remove obsolete deprecation --- src/meta/minifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meta/minifier.js b/src/meta/minifier.js index 0ab268dc4f..324b827797 100644 --- a/src/meta/minifier.js +++ b/src/meta/minifier.js @@ -166,7 +166,7 @@ actions.buildCSS = async function buildCSS(data) { }; if (data.minify) { opts.silenceDeprecations = [ - 'legacy-js-api', 'mixed-decls', 'color-functions', + 'legacy-js-api', 'color-functions', 'global-builtin', 'import', ]; } From f67942caecbefab7f062379f653615f33b074b2f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 15 Sep 2025 13:53:27 -0400 Subject: [PATCH 3/3] fix: local pids not always converted to absolute URLs on topic actor controller --- src/controllers/activitypub/actors.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/controllers/activitypub/actors.js b/src/controllers/activitypub/actors.js index 0f7a348990..850585e379 100644 --- a/src/controllers/activitypub/actors.js +++ b/src/controllers/activitypub/actors.js @@ -136,6 +136,7 @@ Actors.topic = async function (req, res, next) { let collection; let pids; try { + // pids are used in generation of digest only. ([collection, pids] = await Promise.all([ activitypub.helpers.generateCollection({ set: `tid:${req.params.tid}:posts`, @@ -151,7 +152,6 @@ Actors.topic = async function (req, res, next) { } pids.push(mainPid); pids = pids.map(pid => (utils.isNumber(pid) ? `${nconf.get('url')}/post/${pid}` : pid)); - collection.totalItems += 1; // account for mainPid // Generate digest for ETag const digest = activitypub.helpers.generateDigest(new Set(pids)); @@ -168,15 +168,18 @@ Actors.topic = async function (req, res, next) { } res.set('ETag', digest); - // Convert pids to urls + // Add OP to collection on first (or only) page if (page || collection.totalItems < perPage) { collection.orderedItems = collection.orderedItems || []; - if (!page || page === 1) { // add OP to collection + if (!page || page === 1) { collection.orderedItems.unshift(mainPid); + collection.totalItems += 1; } - collection.orderedItems = collection.orderedItems.map(pid => (utils.isNumber(pid) ? `${nconf.get('url')}/post/${pid}` : pid)); } + // Convert pids to urls + collection.orderedItems = collection.orderedItems.map(pid => (utils.isNumber(pid) ? `${nconf.get('url')}/post/${pid}` : pid)); + const object = { '@context': 'https://www.w3.org/ns/activitystreams', id: `${nconf.get('url')}/topic/${req.params.tid}${collection.orderedItems && page ? `?page=${page}` : ''}`,