From 44434b0d3f1ae7248db136514a1fd0e8710f8cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Mar 2026 09:26:54 -0500 Subject: [PATCH 01/10] fix: closes #14039, only keep chat input in view on the chats page --- public/src/client/chats/messages.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index 523249055b..7b1b7694ed 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -110,7 +110,7 @@ define('forum/chats/messages', [ messages.scrollToBottomAfterImageLoad(chatContentEl); const $composer = chatContentEl.siblings('[component="chat/composer"]'); - if ($composer.length) { + if ($composer.length && ajaxify.data?.template?.chats) { $composer[0].scrollIntoView(true); } } From 0c43e2dafb6774fb14e9a36e67a3e1b1d307d2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Mar 2026 10:44:27 -0500 Subject: [PATCH 02/10] refactor: use includes --- public/src/utils.common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/utils.common.js b/public/src/utils.common.js index 7dd3a3c0e0..dfb6f35c98 100644 --- a/public/src/utils.common.js +++ b/public/src/utils.common.js @@ -332,7 +332,7 @@ const utils = { }, isEmailValid: function (email) { - return typeof email === 'string' && email.length && email.indexOf('@') !== -1 && email.indexOf(',') === -1 && email.indexOf(';') === -1; + return typeof email === 'string' && email.length && email.includes('@') && !email.includes(',') && !email.includes(';'); }, isUserNameValid: function (name) { From c98ef396f583bf8ba792542edf7b30a63a2e1520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Mar 2026 10:46:09 -0500 Subject: [PATCH 03/10] fix: dont crash if payload isnt Error --- src/controllers/helpers.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/controllers/helpers.js b/src/controllers/helpers.js index 554967cab4..7101170357 100644 --- a/src/controllers/helpers.js +++ b/src/controllers/helpers.js @@ -511,9 +511,10 @@ helpers.formatApiResponse = async (statusCode, res, payload) => { returnPayload.response = response; if (process.env.NODE_ENV === 'development') { - returnPayload.stack = payload.stack; + const stack = payload instanceof Error ? payload.stack : new Error(String(payload)).stack; + returnPayload.stack = stack; process.stdout.write(`[${chalk.yellow('api')}] Exception caught, error with stack trace follows:\n`); - process.stdout.write(payload.stack); + process.stdout.write(stack); } res.status(statusCode).json(returnPayload); } else { From b26816468601d19125d62ce5dc5ac8f42eef0c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Mar 2026 11:03:06 -0500 Subject: [PATCH 04/10] fix: closes #14041, show specific error message if config fails to save --- public/language/en-GB/error.json | 1 + public/src/admin/settings.js | 2 +- public/src/modules/settings.js | 2 +- src/meta/configs.js | 5 ++++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index 720e615400..7ef3978faa 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -1,5 +1,6 @@ { "invalid-data": "Invalid Data", + "invalid-config-field-value": "Invalid value for config field \"%1\": %2", "invalid-json": "Invalid JSON", "wrong-parameter-type": "A value of type %3 was expected for property `%1`, but %2 was received instead", "required-parameters-missing": "Required parameters were missing from this API call: %1", diff --git a/public/src/admin/settings.js b/public/src/admin/settings.js index 29ede2f502..46c0fa4380 100644 --- a/public/src/admin/settings.js +++ b/public/src/admin/settings.js @@ -104,7 +104,7 @@ define('admin/settings', [ if (err) { return alerts.alert({ alert_id: 'config_status', - timeout: 2500, + timeout: 5000, title: '[[admin/admin:changes-not-saved]]', message: `[[admin/admin:changes-not-saved-message, ${err.message}]]`, type: 'danger', diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js index bb54ba7436..01fa7bf800 100644 --- a/public/src/modules/settings.js +++ b/public/src/modules/settings.js @@ -544,7 +544,7 @@ define('settings', ['hooks', 'alerts'], function (hooks, alerts) { title: '[[admin/admin:changes-not-saved]]', message: `[[admin/admin:changes-not-saved-message, ${err.message}]]`, type: 'error', - timeout: 2500, + timeout: 5000, }); } else { const saveBtn = document.getElementById('save'); diff --git a/src/meta/configs.js b/src/meta/configs.js index f5adf5b000..f686b3dd72 100644 --- a/src/meta/configs.js +++ b/src/meta/configs.js @@ -8,6 +8,7 @@ const winston = require('winston'); const db = require('../database'); const pubsub = require('../pubsub'); const Meta = require('./index'); +const translator = require('../translator'); const cacheBuster = require('./cacheBuster'); const defaults = require('../../install/data/defaults.json'); @@ -190,7 +191,9 @@ function ensureInteger(data, field, min) { if (data.hasOwnProperty(field)) { data[field] = parseInt(data[field], 10); if (!(data[field] >= min)) { - throw new Error('[[error:invalid-data]]'); + throw new Error(translator.compile( + 'error:invalid-config-field-value', field, data[field] + )); } } } From 2428602f27ff22ead97fee0c1166b371f955ece5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Mar 2026 11:33:52 -0500 Subject: [PATCH 05/10] fix: logic in checkRequired if req.body was undefined req.query wasn't checked --- src/middleware/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/middleware/index.js b/src/middleware/index.js index aa4c456c91..568e0c0aa6 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -308,14 +308,20 @@ middleware.validateAuth = helpers.try(async (req, res, next) => { }); middleware.checkRequired = function (fields, req, res, next) { + const body = req.body || {}; + const query = req.query || {}; // Used in API calls to ensure that necessary parameters/data values are present const missing = fields.filter( - field => req.body && !req.body.hasOwnProperty(field) && !req.query.hasOwnProperty(field) + field => !body.hasOwnProperty(field) && !query.hasOwnProperty(field) ); if (!missing.length) { return next(); } - controllers.helpers.formatApiResponse(400, res, new Error(`[[error:required-parameters-missing, ${missing.join(' ')}]]`)); + controllers.helpers.formatApiResponse( + 400, + res, + new Error(`[[error:required-parameters-missing, ${missing.join(' ')}]]`) + ); }; From 88b91c20d907bb312bf25a7314e27dc944c61571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Mar 2026 12:54:14 -0500 Subject: [PATCH 06/10] refactor: move resolve flags and activitypub.out.remove.context after topic deletion --- src/topics/delete.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/topics/delete.js b/src/topics/delete.js index 6df951c0eb..086609a667 100644 --- a/src/topics/delete.js +++ b/src/topics/delete.js @@ -20,16 +20,17 @@ module.exports = function (Topics) { ]); await Promise.all([ db.sortedSetRemove(`cid:${cid}:pids`, pids), - resolveTopicPostFlags(pids, uid), Topics.setTopicFields(tid, { deleted: 1, deleterUid: uid, deletedTimestamp: Date.now(), }), - activitypub.out.remove.context(uid, tid), ]); - - await categories.updateRecentTidForCid(cid); + await Promise.all([ + resolveTopicPostFlags(pids, uid), + activitypub.out.remove.context(uid, tid), + categories.updateRecentTidForCid(cid), + ]); }; async function resolveTopicPostFlags(pids, uid) { From 4f07b345bffc80033787a0276007fc81f1fc4d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Mar 2026 12:55:55 -0500 Subject: [PATCH 07/10] fix: text-break on outgoing link --- src/views/outgoing.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/outgoing.tpl b/src/views/outgoing.tpl index 8d52b1d3b3..d432170338 100644 --- a/src/views/outgoing.tpl +++ b/src/views/outgoing.tpl @@ -8,7 +8,7 @@ From 2f5fccdb1ac15466e1ec4bcc9d716ea7b51d744d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 4 Mar 2026 11:53:29 -0500 Subject: [PATCH 08/10] fix: #13239, unescape custom user field values --- src/activitypub/mocks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/activitypub/mocks.js b/src/activitypub/mocks.js index 6eef6d2665..4e6fed1a80 100644 --- a/src/activitypub/mocks.js +++ b/src/activitypub/mocks.js @@ -453,7 +453,7 @@ Mocks.actors.user = async (uid) => { attachment.push({ type: 'Link', name, - href: value, + href: validator.unescape(value), }); } else { attachment.push({ @@ -467,7 +467,7 @@ Mocks.actors.user = async (uid) => { attachment.push({ type: 'PropertyValue', name, - value, + value: validator.unescape(value), }); } }); From 95fcb392823db5e84f5e6df8412852a152855eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 4 Mar 2026 20:38:15 -0500 Subject: [PATCH 09/10] chore: up widgets --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 1d2ced9b6d..3a62a63c5c 100644 --- a/install/package.json +++ b/install/package.json @@ -111,7 +111,7 @@ "nodebb-theme-lavender": "7.1.21", "nodebb-theme-peace": "2.2.56", "nodebb-theme-persona": "14.2.21", - "nodebb-widget-essentials": "7.0.42", + "nodebb-widget-essentials": "7.0.43", "nodemailer": "8.0.1", "nprogress": "0.2.0", "passport": "0.7.0", From 58336941eac96a0eb2b8e2b41e3c58c65fd20f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 5 Mar 2026 11:37:15 -0500 Subject: [PATCH 10/10] chore: up themes --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 3a62a63c5c..cb5641217d 100644 --- a/install/package.json +++ b/install/package.json @@ -107,10 +107,10 @@ "nodebb-plugin-spam-be-gone": "2.3.2", "nodebb-plugin-web-push": "0.7.6", "nodebb-rewards-essentials": "1.0.2", - "nodebb-theme-harmony": "2.2.43", + "nodebb-theme-harmony": "2.2.45", "nodebb-theme-lavender": "7.1.21", "nodebb-theme-peace": "2.2.56", - "nodebb-theme-persona": "14.2.21", + "nodebb-theme-persona": "14.2.22", "nodebb-widget-essentials": "7.0.43", "nodemailer": "8.0.1", "nprogress": "0.2.0",