diff --git a/install/data/defaults.json b/install/data/defaults.json index 92bac0b2b7..d60984e99e 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -23,10 +23,11 @@ "chatMessageDelay": 2000, "newbieChatMessageDelay": 120000, "notificationSendDelay": 60, - "newbiePostDelayThreshold": 3, + "newbieReputationThreshold": 3, "postQueue": 0, "postQueueReputationThreshold": 0, "groupsExemptFromPostQueue": ["administrators", "Global Moderators"], + "groupsExemptFromNewUserRestrictions": ["administrators", "Global Moderators"], "groupsExemptFromMaintenanceMode": ["administrators", "Global Moderators"], "minimumPostLength": 8, "maximumPostLength": 32767, diff --git a/public/language/en-GB/admin/settings/user.json b/public/language/en-GB/admin/settings/user.json index 7c55d69ee5..528debebaa 100644 --- a/public/language/en-GB/admin/settings/user.json +++ b/public/language/en-GB/admin/settings/user.json @@ -87,5 +87,6 @@ "restrictions.seconds-between-new": "Seconds between posts for new users", "restrictions.seconds-before-new": "Seconds before a new user can make their first post", "restrictions.seconds-edit-after-new": "Number of seconds a post remains editable for new users (set to 0 to disable)", - "restrictions.milliseconds-between-messages": "Time between chat messages for new users (ms)" + "restrictions.milliseconds-between-messages": "Time between chat messages for new users (ms)", + "restrictions.groups-exempt-from-new-user-restrictions": "Select groups that should be exempt from the new user restrictions" } diff --git a/public/openapi/read/admin/settings/user.yaml b/public/openapi/read/admin/settings/user.yaml index 89b0b1067a..fe89bae2a6 100644 --- a/public/openapi/read/admin/settings/user.yaml +++ b/public/openapi/read/admin/settings/user.yaml @@ -13,6 +13,10 @@ get: properties: title: type: string + groupsExemptFromNewUserRestrictions: + type: array + items: + $ref: ../../../components/schemas/GroupObject.yaml#/GroupDataObject notificationSettings: type: array items: diff --git a/src/api/chats.js b/src/api/chats.js index d3788ea9e1..2ea2b26760 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -20,7 +20,7 @@ async function rateLimitExceeded(caller, field) { user.isPrivileged(caller.uid), user.getUserField(caller.uid, 'reputation'), ]); - const newbie = !isPrivileged && meta.config.newbiePostDelayThreshold > reputation; + const newbie = !isPrivileged && meta.config.newbieReputationThreshold > reputation; const delay = newbie ? meta.config.newbieChatMessageDelay : meta.config.chatMessageDelay; session[field] = session[field] || 0; diff --git a/src/controllers/admin/settings.js b/src/controllers/admin/settings.js index 61ccd6a091..61e8a6fb2d 100644 --- a/src/controllers/admin/settings.js +++ b/src/controllers/admin/settings.js @@ -46,7 +46,10 @@ settingsController.email = async (req, res) => { }; settingsController.user = async (req, res) => { - const notificationTypes = await notifications.getAllNotificationTypes(); + const [notificationTypes, groupData] = await Promise.all([ + notifications.getAllNotificationTypes(), + groups.getNonPrivilegeGroups('groups:createtime', 0, -1), + ]); const notificationSettings = notificationTypes.map(type => ({ name: type, label: `[[notifications:${type.replace(/_/g, '-')}]]`, @@ -54,6 +57,7 @@ settingsController.user = async (req, res) => { res.render('admin/settings/user', { title: '[[admin/menu:settings/user]]', notificationSettings: notificationSettings, + groupsExemptFromNewUserRestrictions: groupData, }); }; diff --git a/src/groups/update.js b/src/groups/update.js index ced53ef04e..9da76c9180 100644 --- a/src/groups/update.js +++ b/src/groups/update.js @@ -274,17 +274,19 @@ module.exports = function (Groups) { } async function updateConfig(oldName, newName) { - if (meta.config.groupsExemptFromPostQueue.includes(oldName)) { - meta.config.groupsExemptFromPostQueue.splice( - meta.config.groupsExemptFromPostQueue.indexOf(oldName), 1, newName - ); - await meta.configs.set('groupsExemptFromPostQueue', meta.config.groupsExemptFromPostQueue); - } - if (meta.config.groupsExemptFromMaintenanceMode.includes(oldName)) { - meta.config.groupsExemptFromMaintenanceMode.splice( - meta.config.groupsExemptFromMaintenanceMode.indexOf(oldName), 1, newName - ); - await meta.configs.set('groupsExemptFromMaintenanceMode', meta.config.groupsExemptFromMaintenanceMode); + const configKeys = [ + 'groupsExemptFromPostQueue', + 'groupsExemptFromNewUserRestrictions', + 'groupsExemptFromMaintenanceMode', + ]; + + for (const key of configKeys) { + if (meta.config[key] && meta.config[key].includes(oldName)) { + meta.config[key].splice( + meta.config[key].indexOf(oldName), 1, newName + ); + await meta.configs.set(key, meta.config[key]); + } } } diff --git a/src/privileges/posts.js b/src/privileges/posts.js index 8b32065df6..fbd6858282 100644 --- a/src/privileges/posts.js +++ b/src/privileges/posts.js @@ -139,7 +139,7 @@ privsPosts.canEdit = async function (pid, uid) { if ( !results.isMod && meta.config.newbiePostEditDuration > 0 && - meta.config.newbiePostDelayThreshold > results.userData.reputation && + meta.config.newbieReputationThreshold > results.userData.reputation && Date.now() - results.postData.timestamp > meta.config.newbiePostEditDuration * 1000 ) { return { flag: false, message: `[[error:post-edit-duration-expired, ${meta.config.newbiePostEditDuration}]]` }; diff --git a/src/upgrades/3.6.0/rename_newbie_config.js b/src/upgrades/3.6.0/rename_newbie_config.js new file mode 100644 index 0000000000..6b496d970c --- /dev/null +++ b/src/upgrades/3.6.0/rename_newbie_config.js @@ -0,0 +1,15 @@ +/* eslint-disable no-await-in-loop */ + +'use strict'; + +const db = require('../../database'); + +module.exports = { + name: 'Rename newbiePostDelayThreshold to newbieReputationThreshold', + timestamp: Date.UTC(2023, 10, 7), + method: async function () { + const current = await db.getObjectField('config', 'newbiePostDelayThreshold'); + await db.setObjectField('config', 'newbieReputationThreshold', current); + await db.deleteObjectField('config', 'newbiePostDelayThreshold'); + }, +}; diff --git a/src/user/posts.js b/src/user/posts.js index b2e2b57be2..5ee7f5e8aa 100644 --- a/src/user/posts.js +++ b/src/user/posts.js @@ -3,6 +3,7 @@ const db = require('../database'); const meta = require('../meta'); const privileges = require('../privileges'); +const groups = require('../groups'); module.exports = function (User) { User.isReadyToPost = async function (uid, cid) { @@ -31,9 +32,10 @@ module.exports = function (User) { if (parseInt(uid, 10) === 0) { return; } - const [userData, isAdminOrMod] = await Promise.all([ + const [userData, isAdminOrMod, isMemberOfExempt] = await Promise.all([ User.getUserFields(uid, ['uid', 'mutedUntil', 'joindate', 'email', 'reputation'].concat([field])), privileges.categories.isAdminOrMod(cid, uid), + groups.isMemberOfAny(uid, meta.config.groupsExemptFromNewUserRestrictions), ]); if (!userData.uid) { @@ -54,14 +56,15 @@ module.exports = function (User) { const lasttime = userData[field] || 0; if ( + !isMemberOfExempt && meta.config.newbiePostDelay > 0 && - meta.config.newbiePostDelayThreshold > userData.reputation && + meta.config.newbieReputationThreshold > userData.reputation && now - lasttime < meta.config.newbiePostDelay * 1000 ) { if (meta.config.newbiewPostDelay % 60 === 0) { - throw new Error(`[[error:too-many-posts-newbie-minutes, ${Math.floor(meta.config.newbiePostDelay / 60)}, ${meta.config.newbiePostDelayThreshold}]]`); + throw new Error(`[[error:too-many-posts-newbie-minutes, ${Math.floor(meta.config.newbiePostDelay / 60)}, ${meta.config.newbieReputationThreshold}]]`); } else { - throw new Error(`[[error:too-many-posts-newbie, ${meta.config.newbiePostDelay}, ${meta.config.newbiePostDelayThreshold}]]`); + throw new Error(`[[error:too-many-posts-newbie, ${meta.config.newbiePostDelay}, ${meta.config.newbieReputationThreshold}]]`); } } else if (now - lasttime < meta.config.postDelay * 1000) { throw new Error(`[[error:too-many-posts, ${meta.config.postDelay}]]`); diff --git a/src/views/admin/settings/user.tpl b/src/views/admin/settings/user.tpl index 4a2bcc19b7..6a5c703a2d 100644 --- a/src/views/admin/settings/user.tpl +++ b/src/views/admin/settings/user.tpl @@ -218,8 +218,8 @@
[[admin/settings/user:restrictions-new]]
- - + +
@@ -241,6 +241,16 @@
+ +
+ + +
+
diff --git a/test/user.js b/test/user.js index 45916cbaf9..6133f14f82 100644 --- a/test/user.js +++ b/test/user.js @@ -317,7 +317,7 @@ describe('User', () => { it('should error when a new user posts if the last post time is 10 < 30 seconds', (done) => { meta.config.newbiePostDelay = 30; - meta.config.newbiePostDelayThreshold = 3; + meta.config.newbieReputationThreshold = 3; User.setUserField(testUid, 'lastposttime', +new Date() - (20 * 1000), () => { Topics.post({