diff --git a/install/package.json b/install/package.json index 64b123680a..b613553de9 100644 --- a/install/package.json +++ b/install/package.json @@ -107,11 +107,11 @@ "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.44", + "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-widget-essentials": "7.0.42", + "nodebb-theme-persona": "14.2.22", + "nodebb-widget-essentials": "7.0.43", "nodemailer": "8.0.1", "nprogress": "0.2.0", "passport": "0.7.0", 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/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); } } 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/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) { 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 { 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] + )); } } } 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(' ')}]]`) + ); }; 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) { 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 @@