feat: introduce ACP defined option to rescind notif or do nothing on flag resolve/reject

/cc #10867
isekai-main
Julian Lam 2 years ago
parent df36d96788
commit 15b1561fd3

@ -94,6 +94,8 @@
"min:rep:signature": 0,
"flags:limitPerTarget": 0,
"flags:autoFlagOnDownvoteThreshold": 0,
"flags:actionOnResolve": "rescind",
"flags:actionOnReject": "rescind",
"notificationType_upvote": "notification",
"notificationType_new-topic": "notification",
"notificationType_new-reply": "notification",

@ -23,5 +23,9 @@
"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.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",
"flags.action-on-resolve": "Do the following when a flag is resolved",
"flags.action-on-reject": "Do the following when a flag is rejected",
"flags.action.nothing": "Do nothing",
"flags.action.rescind": "Rescind the notification send to moderators/administrators"
}

@ -679,7 +679,10 @@ Flags.update = async function (flagId, uid, changeset) {
} else {
tasks.push(db.sortedSetAdd(`flags:byState:${changeset[prop]}`, now, flagId));
tasks.push(db.sortedSetRemove(`flags:byState:${current[prop]}`, flagId));
if (changeset[prop] === 'resolved' || changeset[prop] === 'rejected') {
if (changeset[prop] === 'resolved' && meta.config['flags:actionOnResolve'] === 'rescind') {
tasks.push(notifications.rescind(`flag:${current.type}:${current.targetId}`));
}
if (changeset[prop] === 'rejected' && meta.config['flags:actionOnReject'] === 'rescind') {
tasks.push(notifications.rescind(`flag:${current.type}:${current.targetId}`));
}
}

@ -103,6 +103,26 @@
<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="row">
<div class="col-sm-6">
<div class="form-group">
<label for="flags:actionOnResolve">[[admin/settings/reputation:flags.action-on-resolve]]</label>
<select class="form-control" data-field="flags:actionOnResolve" name="flags:actionOnResolve" id="flags:actionOnResolve">
<option value="">[[admin/settings/reputation:flags.action.nothing]]</option>
<option value="rescind">[[admin/settings/reputation:flags.action.rescind]]</option>
</select>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="flags:actionOnReject">[[admin/settings/reputation:flags.action-on-reject]]</label>
<select class="form-control" data-field="flags:actionOnReject" name="flags:actionOnReject" id="flags:actionOnReject">
<option value="">[[admin/settings/reputation:flags.action.nothing]]</option>
<option value="rescind">[[admin/settings/reputation:flags.action.rescind]]</option>
</select>
</div>
</div>
</div>
<div class="checkbox">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input type="checkbox" class="mdl-switch__input" data-field="flags:autoResolveOnBan">

@ -20,6 +20,7 @@ const Groups = require('../src/groups');
const Meta = require('../src/meta');
const Privileges = require('../src/privileges');
const utils = require('../src/utils');
const api = require('../src/api');
describe('Flags', () => {
let uid1;
@ -511,26 +512,75 @@ describe('Flags', () => {
assert.strictEqual('wip', state);
});
it('should rescind notification if flag is resolved', async () => {
const flagsAPI = require('../src/api/flags');
const result = await Topics.post({
cid: category.cid,
uid: uid3,
title: 'Topic to flag',
content: 'This is flaggable content',
describe('resolve/reject', () => {
let result;
let flagObj;
beforeEach(async () => {
result = await Topics.post({
cid: category.cid,
uid: uid3,
title: 'Topic to flag',
content: 'This is flaggable content',
});
flagObj = await api.flags.create({ uid: uid1 }, { type: 'post', id: result.postData.pid, reason: 'spam' });
await sleep(2000);
});
const flagObj = await flagsAPI.create({ uid: uid1 }, { type: 'post', id: result.postData.pid, reason: 'spam' });
await sleep(2000);
let userNotifs = await User.notifications.getAll(adminUid);
assert(userNotifs.includes(`flag:post:${result.postData.pid}`));
it('should rescind notification if flag is resolved', async () => {
let userNotifs = await User.notifications.getAll(adminUid);
assert(userNotifs.includes(`flag:post:${result.postData.pid}`));
await Flags.update(flagObj.flagId, adminUid, {
state: 'resolved',
});
userNotifs = await User.notifications.getAll(adminUid);
assert(!userNotifs.includes(`flag:post:${result.postData.pid}`));
});
it('should rescind notification if flag is rejected', async () => {
let userNotifs = await User.notifications.getAll(adminUid);
assert(userNotifs.includes(`flag:post:${result.postData.pid}`));
await Flags.update(flagObj.flagId, adminUid, {
state: 'rejected',
});
await Flags.update(flagObj.flagId, adminUid, {
state: 'resolved',
userNotifs = await User.notifications.getAll(adminUid);
assert(!userNotifs.includes(`flag:post:${result.postData.pid}`));
});
userNotifs = await User.notifications.getAll(adminUid);
assert(!userNotifs.includes(`flag:post:${result.postData.pid}`));
it('should do nothing if flag is resolved but ACP action is not "rescind"', async () => {
Meta.config['flags:actionOnResolve'] = '';
let userNotifs = await User.notifications.getAll(adminUid);
assert(userNotifs.includes(`flag:post:${result.postData.pid}`));
await Flags.update(flagObj.flagId, adminUid, {
state: 'resolved',
});
userNotifs = await User.notifications.getAll(adminUid);
assert(userNotifs.includes(`flag:post:${result.postData.pid}`));
delete Meta.config['flags:actionOnResolve'];
});
it('should do nothing if flag is rejected but ACP action is not "rescind"', async () => {
Meta.config['flags:actionOnReject'] = '';
let userNotifs = await User.notifications.getAll(adminUid);
assert(userNotifs.includes(`flag:post:${result.postData.pid}`));
await Flags.update(flagObj.flagId, adminUid, {
state: 'rejected',
});
userNotifs = await User.notifications.getAll(adminUid);
assert(userNotifs.includes(`flag:post:${result.postData.pid}`));
delete Meta.config['flags:actionOnReject'];
});
});
});

Loading…
Cancel
Save