From 62e3a59c27a86cd23ae193598614863859871ef4 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 14 Feb 2024 15:41:30 +0000 Subject: [PATCH 01/11] chore: incrementing version number - v3.6.6 --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 0b5fb0c5f0..da2aaa7ed8 100644 --- a/install/package.json +++ b/install/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "3.6.5", + "version": "3.6.6", "homepage": "https://www.nodebb.org", "repository": { "type": "git", From debaa2b9cdfd29ca04cda10bac340fcacd7a7e3e Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 14 Feb 2024 15:41:31 +0000 Subject: [PATCH 02/11] chore: update changelog for v3.6.6 --- CHANGELOG.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4ace16fe7..79ebb49282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,54 @@ +#### v3.6.6 (2024-02-14) + +##### Chores + +* incrementing version number - v3.6.5 (6c653625) +* update changelog for v3.6.5 (04039f76) +* incrementing version number - v3.6.4 (83d131b4) +* incrementing version number - v3.6.3 (fc7d2bfd) +* incrementing version number - v3.6.2 (0f577a57) +* incrementing version number - v3.6.1 (f1a69468) +* incrementing version number - v3.6.0 (4cdf85f8) +* incrementing version number - v3.5.3 (ed0e8783) +* incrementing version number - v3.5.2 (52fbb2da) +* incrementing version number - v3.5.1 (4c543488) +* incrementing version number - v3.5.0 (d06fb4f0) +* incrementing version number - v3.4.3 (5c984250) +* incrementing version number - v3.4.2 (3f0dac38) +* incrementing version number - v3.4.1 (01e69574) +* incrementing version number - v3.4.0 (fd9247c5) +* incrementing version number - v3.3.9 (5805e770) +* incrementing version number - v3.3.8 (a5603565) +* incrementing version number - v3.3.7 (b26f1744) +* incrementing version number - v3.3.6 (7fb38792) +* incrementing version number - v3.3.4 (a67f84ea) +* incrementing version number - v3.3.3 (f94d239b) +* incrementing version number - v3.3.2 (ec9dac97) +* incrementing version number - v3.3.1 (151cc68f) +* incrementing version number - v3.3.0 (fc1ad70f) +* incrementing version number - v3.2.3 (b06d3e63) +* incrementing version number - v3.2.2 (758ecfcd) +* incrementing version number - v3.2.1 (20145074) +* incrementing version number - v3.2.0 (9ecac38e) +* incrementing version number - v3.1.7 (0b4e81ab) +* incrementing version number - v3.1.6 (b3a3b130) +* incrementing version number - v3.1.5 (ec19343a) +* incrementing version number - v3.1.4 (2452783c) +* incrementing version number - v3.1.3 (3b4e9d3f) +* incrementing version number - v3.1.2 (40fa3489) +* incrementing version number - v3.1.1 (40250733) +* incrementing version number - v3.1.0 (0cb386bd) +* incrementing version number - v3.0.1 (26f6ea49) +* incrementing version number - v3.0.0 (224e08cd) + +##### Bug Fixes + +* closes #12329, fix default value of categoryWatchState (88e9fa37) + +##### Tests + +* fix spec (5fec8b23) + #### v3.6.5 (2024-01-31) ##### Chores From 4a405ce0326554cb363333f82f80dd75dbfa7c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 21 Feb 2024 11:36:04 -0500 Subject: [PATCH 03/11] fix: retry setAdd on e11000 error --- src/database/mongo/sets.js | 28 ++++++++++++++++++---------- test/database/sets.js | 8 ++++++++ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/database/mongo/sets.js b/src/database/mongo/sets.js index 42051bc2a4..3f110b79f9 100644 --- a/src/database/mongo/sets.js +++ b/src/database/mongo/sets.js @@ -13,17 +13,25 @@ module.exports = function (module) { } value = value.map(v => helpers.valueToString(v)); - await module.client.collection('objects').updateOne({ - _key: key, - }, { - $addToSet: { - members: { - $each: value, + try { + await module.client.collection('objects').updateOne({ + _key: key, + }, { + $addToSet: { + members: { + $each: value, + }, }, - }, - }, { - upsert: true, - }); + }, { + upsert: true, + }); + } catch (err) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, key, value); + return await module.setAdd(key, value); + } + throw err; + } }; module.setsAdd = async function (keys, value) { diff --git a/test/database/sets.js b/test/database/sets.js index eae737c688..fdd6ad9e84 100644 --- a/test/database/sets.js +++ b/test/database/sets.js @@ -30,6 +30,14 @@ describe('Set methods', () => { assert.deepStrictEqual(members, []); assert(!exists); }); + + it('should not error with parallel adds', async () => { + await Promise.all([ + db.setAdd('parallelset', 1), + db.setAdd('parallelset', 2), + db.setAdd('parallelset', 3), + ]); + }); }); describe('getSetMembers()', () => { From 4e51bf81bb9008f2e6362a3d73db73b33c4d3790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 21 Feb 2024 11:38:07 -0500 Subject: [PATCH 04/11] test: better test for #12352 --- test/database/sets.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/database/sets.js b/test/database/sets.js index fdd6ad9e84..126490aff8 100644 --- a/test/database/sets.js +++ b/test/database/sets.js @@ -37,6 +37,11 @@ describe('Set methods', () => { db.setAdd('parallelset', 2), db.setAdd('parallelset', 3), ]); + const members = await db.getSetMembers('parallelset'); + assert.strictEqual(members.length, 3); + assert(members.includes('1')); + assert(members.includes('2')); + assert(members.includes('3')); }); }); From 3960d370e065257014c08abbb68453fc4c8c1780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 22 Feb 2024 10:14:35 -0500 Subject: [PATCH 05/11] fix: closes #12358, only load pending/invited for owners --- src/controllers/admin/groups.js | 1 - src/controllers/groups.js | 1 - src/groups/index.js | 20 ++++++++++++++------ src/groups/user.js | 9 +++------ 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/controllers/admin/groups.js b/src/controllers/admin/groups.js index 1a7dc950c7..a1a7c6fd1c 100644 --- a/src/controllers/admin/groups.js +++ b/src/controllers/admin/groups.js @@ -42,7 +42,6 @@ groupsController.get = async function (req, res, next) { if (!group || groupName === groups.BANNED_USERS) { return next(); } - group.isOwner = true; const groupNameData = groupNames.map(name => ({ encodedName: encodeURIComponent(name), diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 3cdb435f9c..6a21610748 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -72,7 +72,6 @@ groupsController.details = async function (req, res, next) { if (!groupData) { return next(); } - groupData.isOwner = groupData.isOwner || isAdmin || (isGlobalMod && !groupData.system); res.render('groups/details', { title: `[[pages:group, ${groupData.displayName}]]`, diff --git a/src/groups/index.js b/src/groups/index.js index ec92f05fb1..7faf8d692a 100644 --- a/src/groups/index.js +++ b/src/groups/index.js @@ -3,6 +3,7 @@ const user = require('../user'); const db = require('../database'); const plugins = require('../plugins'); +const privileges = require('../privileges'); const slugify = require('../slugify'); const Groups = module.exports; @@ -130,30 +131,37 @@ Groups.get = async function (groupName, options) { stop = (parseInt(options.userListCount, 10) || 4) - 1; } - const [groupData, members, pending, invited, isMember, isPending, isInvited, isOwner] = await Promise.all([ + const [groupData, members, isMember, isPending, isInvited, isOwner, isAdmin, isGlobalMod] = await Promise.all([ Groups.getGroupData(groupName), Groups.getOwnersAndMembers(groupName, options.uid, 0, stop), - Groups.getPending(groupName), - Groups.getInvites(groupName), Groups.isMember(options.uid, groupName), Groups.isPending(options.uid, groupName), Groups.isInvited(options.uid, groupName), Groups.ownership.isOwner(options.uid, groupName), + privileges.admin.can('admin:groups', options.uid), + user.isGlobalModerator(options.uid), ]); if (!groupData) { return null; } + + groupData.isOwner = isOwner || isAdmin || (isGlobalMod && !groupData.system); + if (groupData.isOwner) { + ([groupData.pending, groupData.invited] = await Promise.all([ + Groups.getPending(groupName), + Groups.getInvites(groupName), + ])); + } + + const descriptionParsed = await plugins.hooks.fire('filter:parse.raw', String(groupData.description || '')); groupData.descriptionParsed = descriptionParsed; groupData.members = members; groupData.membersNextStart = stop + 1; - groupData.pending = pending.filter(Boolean); - groupData.invited = invited.filter(Boolean); groupData.isMember = isMember; groupData.isPending = isPending; groupData.isInvited = isInvited; - groupData.isOwner = isOwner; const results = await plugins.hooks.fire('filter:group.get', { group: groupData }); return results.group; }; diff --git a/src/groups/user.js b/src/groups/user.js index 4238296a37..d3911f07aa 100644 --- a/src/groups/user.js +++ b/src/groups/user.js @@ -4,13 +4,10 @@ const db = require('../database'); const user = require('../user'); module.exports = function (Groups) { - Groups.getUsersFromSet = async function (set, fields) { + Groups.getUsersFromSet = async function (set, fields = []) { const uids = await db.getSetMembers(set); - - if (fields) { - return await user.getUsersFields(uids, fields); - } - return await user.getUsersData(uids); + const userData = await user.getUsersFields(uids, fields); + return userData.filter(u => u && u.uid); }; Groups.getUserGroups = async function (uids) { From c61b3bbd25c24f0c1281aa41dc5a82d6c252958d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 22 Feb 2024 11:40:47 -0500 Subject: [PATCH 06/11] fix: #12359, fix api call --- public/src/client/groups/memberlist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/groups/memberlist.js b/public/src/client/groups/memberlist.js index 38a3680b86..73d82ce91e 100644 --- a/public/src/client/groups/memberlist.js +++ b/public/src/client/groups/memberlist.js @@ -92,7 +92,7 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b const searchEl = $('[component="groups/members/search"]'); searchEl.on('keyup', utils.debounce(function () { const query = searchEl.val(); - api.get(`/groups/${groupName}/members`, { query }, function (err, results) { + api.get(`/groups/${ajaxify.data.group.slug}/members`, { query }, function (err, results) { if (err) { return alerts.error(err); } From 00e29403f048a037a148c8f5e4cebdf96801b080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 26 Feb 2024 00:50:22 -0500 Subject: [PATCH 07/11] fix: closes #12365, staticHooks with callbacks --- src/plugins/hooks.js | 77 +++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 47 deletions(-) diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 197af92b3d..4717a31fba 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -207,6 +207,34 @@ Hooks.hasListeners = function (hook) { return !!(plugins.loadedHooks[hook] && plugins.loadedHooks[hook].length > 0); }; +function hookHandlerPromise(hook, hookObj, params) { + return new Promise((resolve, reject) => { + let resolved = false; + function _resolve(result) { + if (resolved) { + winston.warn(`[plugins] ${hook} already resolved in plugin ${hookObj.id}`); + return; + } + resolved = true; + resolve(result); + } + const returned = hookObj.method(params, (err, result) => { + if (err) reject(err); else _resolve(result); + }); + + if (utils.isPromise(returned)) { + returned.then( + payload => _resolve(payload), + err => reject(err) + ); + return; + } + if (returned) { + _resolve(returned); + } + }); +} + async function fireFilterHook(hook, hookList, params) { if (!Array.isArray(hookList) || !hookList.length) { return params; @@ -223,31 +251,7 @@ async function fireFilterHook(hook, hookList, params) { if (hookObj.method.constructor && hookObj.method.constructor.name === 'AsyncFunction') { return await hookObj.method(params); } - return new Promise((resolve, reject) => { - let resolved = false; - function _resolve(result) { - if (resolved) { - winston.warn(`[plugins] ${hook} already resolved in plugin ${hookObj.id}`); - return; - } - resolved = true; - resolve(result); - } - const returned = hookObj.method(params, (err, result) => { - if (err) reject(err); else _resolve(result); - }); - - if (utils.isPromise(returned)) { - returned.then( - payload => _resolve(payload), - err => reject(err) - ); - return; - } - if (returned) { - _resolve(returned); - } - }); + return hookHandlerPromise(hook, hookObj, params); } for (const hookObj of hookList) { @@ -303,28 +307,7 @@ async function fireStaticHook(hook, hookList, params) { return timeout(hookObj.method(params), 10000, 'timeout'); } - return new Promise((resolve, reject) => { - let resolved = false; - function _resolve(result) { - if (resolved) { - return; - } - resolved = true; - resolve(result); - } - const returned = hookObj.method(params, (err, result) => { - if (err) reject(err); else _resolve(result); - }); - - if (utils.isPromise(returned)) { - returned.then( - payload => _resolve(payload), - err => reject(err) - ); - return; - } - _resolve(); - }); + return hookHandlerPromise(hook, hookObj, params); } for (const hookObj of hookList) { From 52796bc54ebfa61def887528984a1a370667f738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 26 Feb 2024 09:22:41 -0500 Subject: [PATCH 08/11] static hooks don't return sync data --- src/plugins/hooks.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 4717a31fba..766bccad26 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -229,7 +229,8 @@ function hookHandlerPromise(hook, hookObj, params) { ); return; } - if (returned) { + + if (hook.startsWith('filter:') && returned) { _resolve(returned); } }); From b2a988190c0075d9634e708c3d01d52db376eb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 26 Feb 2024 13:19:16 -0500 Subject: [PATCH 09/11] maintain old behaviour --- src/plugins/hooks.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 766bccad26..9b30ce316e 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -230,8 +230,11 @@ function hookHandlerPromise(hook, hookObj, params) { return; } - if (hook.startsWith('filter:') && returned) { + if (hook.startsWith('filter:') && returned !== undefined) { _resolve(returned); + } else if (hook.startsWith('static:') && hookObj.method.length <= 1) { + // make sure it is resolved if static hook doesn't return anything and doesn't use callback + _resolve(); } }); } From 107f5613bf4e62e55356200ac77af0bfc36c4868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 27 Feb 2024 15:07:23 -0500 Subject: [PATCH 10/11] fix: #12372, fix manual digest buttons --- public/src/admin/manage/digest.js | 2 +- src/views/admin/manage/digest.tpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/src/admin/manage/digest.js b/public/src/admin/manage/digest.js index ea50d2a2c4..365ac776b6 100644 --- a/public/src/admin/manage/digest.js +++ b/public/src/admin/manage/digest.js @@ -5,7 +5,7 @@ define('admin/manage/digest', ['bootbox', 'alerts'], function (bootbox, alerts) const Digest = {}; Digest.init = function () { - $('table').on('click', '[data-action]', function () { + $('.digest').on('click', '[data-action]', function () { const action = this.getAttribute('data-action'); const uid = this.getAttribute('data-uid'); diff --git a/src/views/admin/manage/digest.tpl b/src/views/admin/manage/digest.tpl index bfa7d9b9ce..bfa118dcf1 100644 --- a/src/views/admin/manage/digest.tpl +++ b/src/views/admin/manage/digest.tpl @@ -1,4 +1,4 @@ -
+

[[admin/manage/digest:lead]]

[[admin/manage/digest:disclaimer]]

[[admin/manage/digest:disclaimer-continued]]

From 5f597dc97fde3183ea2be85dd4ddde830d55c910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 27 Feb 2024 15:13:06 -0500 Subject: [PATCH 11/11] align center --- src/views/admin/manage/digest.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/admin/manage/digest.tpl b/src/views/admin/manage/digest.tpl index bfa118dcf1..9c6c226ef1 100644 --- a/src/views/admin/manage/digest.tpl +++ b/src/views/admin/manage/digest.tpl @@ -8,7 +8,7 @@
[[admin/manage/digest:default-help, {default}]]
-
+
[[admin/manage/digest:manual-run]]