mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 19:15:58 +01:00 
			
		
		
		
	feat: introduce ACP defined option to rescind notif or do nothing on flag resolve/reject
/cc #10867
This commit is contained in:
		| @@ -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', | ||||
| 			}); | ||||
| 			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}`)); | ||||
|  | ||||
| 			await Flags.update(flagObj.flagId, adminUid, { | ||||
| 				state: 'resolved', | ||||
| 		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); | ||||
| 			}); | ||||
|  | ||||
| 			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', | ||||
| 				}); | ||||
|  | ||||
| 				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']; | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user