From 2b1fdc56a119e397f221430335822009b31e4c06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?=
Date: Thu, 18 Jan 2024 17:07:52 -0500
Subject: [PATCH] feat: limit post/user flags per day closes #12274
---
install/data/defaults.json | 2 ++
.../en-GB/admin/settings/reputation.json | 7 ++++++-
public/language/en-GB/error.json | 2 ++
src/flags.js | 16 +++++++++++++-
src/views/admin/settings/reputation.tpl | 21 +++++++++++++++++++
5 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/install/data/defaults.json b/install/data/defaults.json
index 47a3e8d4a2..7b12002dc4 100644
--- a/install/data/defaults.json
+++ b/install/data/defaults.json
@@ -99,6 +99,8 @@
"min:rep:aboutme": 0,
"min:rep:signature": 0,
"flags:limitPerTarget": 0,
+ "flags:postFlagsPerDay": 10,
+ "flags:userFlagsPerDay": 10,
"flags:autoFlagOnDownvoteThreshold": 0,
"flags:actionOnResolve": "rescind",
"flags:actionOnReject": "rescind",
diff --git a/public/language/en-GB/admin/settings/reputation.json b/public/language/en-GB/admin/settings/reputation.json
index 53801c6662..e4fff22620 100644
--- a/public/language/en-GB/admin/settings/reputation.json
+++ b/public/language/en-GB/admin/settings/reputation.json
@@ -23,7 +23,12 @@
"flags.limit-per-target": "Maximum number of times something can be flagged",
"flags.limit-per-target-placeholder": "Default: 0",
"flags.limit-per-target-help": "When a post or user is flagged multiple times, each additional flag is considered a "report" and added to the original flag. Set this option to a number other than zero to limit the number of reports an item can receive.",
- "flags.auto-flag-on-downvote-threshold": "Number of downvotes to auto flag posts (Set to 0 to disable, default: 0)",
+ "flags.limit-post-flags-per-day": "Maximum number of times a user can flag posts in a day",
+ "flags.limit-post-flags-per-day-help": "Set to 0 to disable, (default: 10)",
+ "flags.limit-user-flags-per-day": "Maximum number of times a user can flag users in a day",
+ "flags.limit-user-flags-per-day-help": "Set to 0 to disable, (default: 10)",
+ "flags.auto-flag-on-downvote-threshold": "Number of downvotes to auto flag posts",
+ "flags.auto-flag-on-downvote-threshold-help": "Set to 0 to disable, (default: 0)",
"flags.auto-resolve-on-ban": "Automatically resolve all of a user's tickets when they are banned",
"flags.action-on-resolve": "Do the following when a flag is resolved",
"flags.action-on-reject": "Do the following when a flag is rejected",
diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json
index 75a8328aa1..47500b65a2 100644
--- a/public/language/en-GB/error.json
+++ b/public/language/en-GB/error.json
@@ -211,6 +211,8 @@
"user-already-flagged": "You have already flagged this user",
"post-flagged-too-many-times": "This post has been flagged by others already",
"user-flagged-too-many-times": "This user has been flagged by others already",
+ "too-many-post-flags-per-day": "You can only flag %1 post(s) per day",
+ "too-many-user-flags-per-day": "You can only flag %1 user(s) per day",
"cant-flag-privileged": "You are not allowed to flag the profiles or content of privileged users (moderators/global moderators/admins)",
"cant-locate-flag-report": "Cannot locate flag report",
"self-vote": "You cannot vote on your own post",
diff --git a/src/flags.js b/src/flags.js
index 7ec1c504c1..833bb7edd8 100644
--- a/src/flags.js
+++ b/src/flags.js
@@ -629,8 +629,22 @@ Flags.canFlag = async function (type, id, uid, skipLimitCheck = false) {
throw new Error(`[[error:${type}-flagged-too-many-times]]`);
}
}
+ const oneday = 24 * 60 * 60 * 1000;
+ const now = Date.now();
+ const [flagIds, canRead, isPrivileged] = await Promise.all([
+ db.getSortedSetRangeByScore(`flags:byReporter:${uid}`, 0, -1, now - oneday, '+inf'),
+ privileges.posts.can('topics:read', id, uid),
+ user.isPrivileged(uid),
+ ]);
+ const allowedFlagsPerDay = meta.config[`flags:${type}FlagsPerDay`];
+ if (!isPrivileged && allowedFlagsPerDay > 0) {
+ const flagData = await db.getObjects(flagIds.map(id => `flag:${id}`));
+ const flagsOfType = flagData.filter(f => f && f.type === type);
+ if (allowedFlagsPerDay > 0 && flagsOfType.length > allowedFlagsPerDay) {
+ throw new Error(`[[error:too-many-${type}-flags-per-day, ${allowedFlagsPerDay}]]`);
+ }
+ }
- const canRead = await privileges.posts.can('topics:read', id, uid);
switch (type) {
case 'user':
return true;
diff --git a/src/views/admin/settings/reputation.tpl b/src/views/admin/settings/reputation.tpl
index c747f22189..1786596c30 100644
--- a/src/views/admin/settings/reputation.tpl
+++ b/src/views/admin/settings/reputation.tpl
@@ -94,9 +94,30 @@
[[admin/settings/reputation:flags.limit-per-target-help]]