mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-12 17:05:51 +01:00
* feat: post auto flagging on downvotes * fix: just get one admin
This commit is contained in:
@@ -87,6 +87,7 @@
|
|||||||
"min:rep:aboutme": 0,
|
"min:rep:aboutme": 0,
|
||||||
"min:rep:signature": 0,
|
"min:rep:signature": 0,
|
||||||
"flags:limitPerTarget": 0,
|
"flags:limitPerTarget": 0,
|
||||||
|
"flags:autoFlagOnDownvoteThreshold": 0,
|
||||||
"notificationType_upvote": "notification",
|
"notificationType_upvote": "notification",
|
||||||
"notificationType_new-topic": "notification",
|
"notificationType_new-topic": "notification",
|
||||||
"notificationType_new-reply": "notification",
|
"notificationType_new-reply": "notification",
|
||||||
|
|||||||
@@ -18,5 +18,6 @@
|
|||||||
"flags.limit-per-target": "Maximum number of times something can be flagged",
|
"flags.limit-per-target": "Maximum number of times something can be flagged",
|
||||||
"flags.limit-per-target-placeholder": "Default: 0",
|
"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.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.auto-resolve-on-ban": "Automatically resolve all of a user's tickets when they are banned"
|
"flags.auto-resolve-on-ban": "Automatically resolve all of a user's tickets when they are banned"
|
||||||
}
|
}
|
||||||
@@ -81,5 +81,6 @@
|
|||||||
"bulk-actions": "Bulk Actions",
|
"bulk-actions": "Bulk Actions",
|
||||||
"bulk-resolve": "Resolve Flag(s)",
|
"bulk-resolve": "Resolve Flag(s)",
|
||||||
"bulk-success": "%1 flags updated",
|
"bulk-success": "%1 flags updated",
|
||||||
"flagged-timeago-readable": "Flagged <span class=\"timeago\" title=\"%1\"></span> (%2)"
|
"flagged-timeago-readable": "Flagged <span class=\"timeago\" title=\"%1\"></span> (%2)",
|
||||||
|
"auto-flagged": "[Auto Flagged] Received %1 downvotes."
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ async function execute(cmd, args) {
|
|||||||
|
|
||||||
function UserCmdHelpers() {
|
function UserCmdHelpers() {
|
||||||
async function getAdminUidOrFail() {
|
async function getAdminUidOrFail() {
|
||||||
const adminUid = (await db.getSortedSetMembers('group:administrators:members')).reverse()[0];
|
const adminUid = await user.getFirstAdminUid();
|
||||||
if (!adminUid) {
|
if (!adminUid) {
|
||||||
const err = new Error('An admin account does not exists to execute the operation.');
|
const err = new Error('An admin account does not exists to execute the operation.');
|
||||||
err.name = 'UserError';
|
err.name = 'UserError';
|
||||||
|
|||||||
14
src/flags.js
14
src/flags.js
@@ -377,7 +377,7 @@ Flags.deleteNote = async function (flagId, datetime) {
|
|||||||
await db.sortedSetRemove(`flag:${flagId}:notes`, note[0]);
|
await db.sortedSetRemove(`flag:${flagId}:notes`, note[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
Flags.create = async function (type, id, uid, reason, timestamp) {
|
Flags.create = async function (type, id, uid, reason, timestamp, forceFlag = false) {
|
||||||
let doHistoryAppend = false;
|
let doHistoryAppend = false;
|
||||||
if (!timestamp) {
|
if (!timestamp) {
|
||||||
timestamp = Date.now();
|
timestamp = Date.now();
|
||||||
@@ -387,14 +387,14 @@ Flags.create = async function (type, id, uid, reason, timestamp) {
|
|||||||
// Sanity checks
|
// Sanity checks
|
||||||
Flags.exists(type, id, uid),
|
Flags.exists(type, id, uid),
|
||||||
Flags.targetExists(type, id),
|
Flags.targetExists(type, id),
|
||||||
Flags.canFlag(type, id, uid),
|
Flags.canFlag(type, id, uid, forceFlag),
|
||||||
Flags.targetFlagged(type, id),
|
Flags.targetFlagged(type, id),
|
||||||
|
|
||||||
// Extra data for zset insertion
|
// Extra data for zset insertion
|
||||||
Flags.getTargetUid(type, id),
|
Flags.getTargetUid(type, id),
|
||||||
Flags.getTargetCid(type, id),
|
Flags.getTargetCid(type, id),
|
||||||
]);
|
]);
|
||||||
if (flagExists) {
|
if (!forceFlag && flagExists) {
|
||||||
throw new Error(`[[error:${type}-already-flagged]]`);
|
throw new Error(`[[error:${type}-already-flagged]]`);
|
||||||
} else if (!targetExists) {
|
} else if (!targetExists) {
|
||||||
throw new Error('[[error:invalid-data]]');
|
throw new Error('[[error:invalid-data]]');
|
||||||
@@ -499,9 +499,9 @@ Flags.exists = async function (type, id, uid) {
|
|||||||
return await db.isSortedSetMember('flags:hash', [type, id, uid].join(':'));
|
return await db.isSortedSetMember('flags:hash', [type, id, uid].join(':'));
|
||||||
};
|
};
|
||||||
|
|
||||||
Flags.canFlag = async function (type, id, uid) {
|
Flags.canFlag = async function (type, id, uid, skipLimitCheck = false) {
|
||||||
const limit = meta.config['flags:limitPerTarget'];
|
const limit = meta.config['flags:limitPerTarget'];
|
||||||
if (limit > 0) {
|
if (!skipLimitCheck && limit > 0) {
|
||||||
const score = await db.sortedSetScore('flags:byTarget', `${type}:${id}`);
|
const score = await db.sortedSetScore('flags:byTarget', `${type}:${id}`);
|
||||||
if (score >= limit) {
|
if (score >= limit) {
|
||||||
throw new Error(`[[error:${type}-flagged-too-many-times]]`);
|
throw new Error(`[[error:${type}-flagged-too-many-times]]`);
|
||||||
@@ -729,7 +729,7 @@ Flags.appendNote = async function (flagId, uid, note, datetime) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Flags.notify = async function (flagObj, uid) {
|
Flags.notify = async function (flagObj, uid, notifySelf = false) {
|
||||||
const [admins, globalMods] = await Promise.all([
|
const [admins, globalMods] = await Promise.all([
|
||||||
groups.getMembers('administrators', 0, -1),
|
groups.getMembers('administrators', 0, -1),
|
||||||
groups.getMembers('Global Moderators', 0, -1),
|
groups.getMembers('Global Moderators', 0, -1),
|
||||||
@@ -780,7 +780,9 @@ Flags.notify = async function (flagObj, uid) {
|
|||||||
from: uid,
|
from: uid,
|
||||||
to: uids,
|
to: uids,
|
||||||
});
|
});
|
||||||
|
if (!notifySelf) {
|
||||||
uids = uids.filter(_uid => parseInt(_uid, 10) !== parseInt(uid, 10));
|
uids = uids.filter(_uid => parseInt(_uid, 10) !== parseInt(uid, 10));
|
||||||
|
}
|
||||||
await notifications.push(notifObj, uids);
|
await notifications.push(notifObj, uids);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
const meta = require('../meta');
|
const meta = require('../meta');
|
||||||
const db = require('../database');
|
const db = require('../database');
|
||||||
|
const flags = require('../flags');
|
||||||
const user = require('../user');
|
const user = require('../user');
|
||||||
const topics = require('../topics');
|
const topics = require('../topics');
|
||||||
const plugins = require('../plugins');
|
const plugins = require('../plugins');
|
||||||
const privileges = require('../privileges');
|
const privileges = require('../privileges');
|
||||||
|
const translator = require('../translator');
|
||||||
|
|
||||||
module.exports = function (Posts) {
|
module.exports = function (Posts) {
|
||||||
const votesInProgress = {};
|
const votesInProgress = {};
|
||||||
@@ -243,6 +245,13 @@ module.exports = function (Posts) {
|
|||||||
if (!postData || !postData.pid || !postData.tid) {
|
if (!postData || !postData.pid || !postData.tid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const threshold = meta.config['flags:autoFlagOnDownvoteThreshold'];
|
||||||
|
if (threshold && postData.votes <= (-threshold)) {
|
||||||
|
const adminUid = await user.getFirstAdminUid();
|
||||||
|
const reportMsg = await translator.translate(`[[flags:auto-flagged, ${-postData.votes}]]`);
|
||||||
|
const flagObj = await flags.create('post', postData.pid, adminUid, reportMsg, null, true);
|
||||||
|
await flags.notify(flagObj, adminUid, true);
|
||||||
|
}
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
updateTopicVoteCount(postData),
|
updateTopicVoteCount(postData),
|
||||||
db.sortedSetAdd('posts:votes', postData.votes, postData.pid),
|
db.sortedSetAdd('posts:votes', postData.votes, postData.pid),
|
||||||
|
|||||||
@@ -211,6 +211,10 @@ User.getAdminsandGlobalModsandModerators = async function () {
|
|||||||
return await User.getUsersData(_.union(...results));
|
return await User.getUsersData(_.union(...results));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
User.getFirstAdminUid = async function () {
|
||||||
|
return (await db.getSortedSetRange('group:administrators:members', 0, 0))[0];
|
||||||
|
};
|
||||||
|
|
||||||
User.getModeratorUids = async function () {
|
User.getModeratorUids = async function () {
|
||||||
const cids = await categories.getAllCidsFromSet('categories:cid');
|
const cids = await categories.getAllCidsFromSet('categories:cid');
|
||||||
const uids = await categories.getModeratorUids(cids);
|
const uids = await categories.getModeratorUids(cids);
|
||||||
|
|||||||
@@ -82,6 +82,10 @@
|
|||||||
[[admin/settings/reputation:flags.limit-per-target-help]]
|
[[admin/settings/reputation:flags.limit-per-target-help]]
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="flags:autoFlagOnDownvoteThreshold">[[admin/settings/reputation:flags.auto-flag-on-downvote-threshold]]</label>
|
||||||
|
<input type="text" class="form-control" placeholder="0" data-field="flags:autoFlagOnDownvoteThreshold" id="flags:autoFlagOnDownvoteThreshold">
|
||||||
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
|
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
|
||||||
<input type="checkbox" class="mdl-switch__input" data-field="flags:autoResolveOnBan">
|
<input type="checkbox" class="mdl-switch__input" data-field="flags:autoResolveOnBan">
|
||||||
|
|||||||
Reference in New Issue
Block a user