mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-08-02 03:49:32 +02:00
restrict flags interface so that moderators only see flags from cids they can actually moderate
This commit is contained in:
@@ -27,6 +27,7 @@ modsController.flags.list = function (req, res, next) {
|
||||
}
|
||||
|
||||
// Parse query string params for filters
|
||||
var hasFilter = false;
|
||||
var valid = ['assignee', 'state', 'reporterId', 'type', 'targetUid', 'cid', 'quick'];
|
||||
var filters = valid.reduce(function (memo, cur) {
|
||||
if (req.query.hasOwnProperty(cur)) {
|
||||
@@ -35,6 +36,24 @@ modsController.flags.list = function (req, res, next) {
|
||||
|
||||
return memo;
|
||||
}, {});
|
||||
hasFilter = !!Object.keys(filters).length;
|
||||
|
||||
if (res.locals.cids) {
|
||||
if (!filters.cid) {
|
||||
// If mod and no cid filter, add filter for their modded categories
|
||||
filters.cid = res.locals.cids;
|
||||
} else {
|
||||
// Remove cids they do not moderate
|
||||
if (Array.isArray(filters.cid)) {
|
||||
filters.cid = filters.cid.filter(function (cid) {
|
||||
return res.locals.cids.indexOf(String(cid)) !== -1;
|
||||
});
|
||||
} else if (res.locals.cids.indexOf(String(filters.cid)) === -1) {
|
||||
filters.cid = res.locals.cids;
|
||||
hasFilter = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async.parallel({
|
||||
flags: async.apply(flags.list, filters, req.uid),
|
||||
@@ -45,9 +64,25 @@ modsController.flags.list = function (req, res, next) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// If res.locals.cids is populated, then slim down the categories list
|
||||
if (res.locals.cids) {
|
||||
data.categories = data.categories.filter(function (category) {
|
||||
return res.locals.cids.indexOf(String(category.cid)) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
// Minimal returned set for templates.js
|
||||
data.categories = data.categories.reduce(function (memo, cur) {
|
||||
memo[cur.cid] = cur.name;
|
||||
if (!res.locals.cids) {
|
||||
memo[cur.cid] = cur.name;
|
||||
return memo;
|
||||
}
|
||||
|
||||
// If mod, remove categories they can't moderate
|
||||
if (res.locals.cids.indexOf(String(cur.cid)) !== -1) {
|
||||
memo[cur.cid] = cur.name;
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, {});
|
||||
|
||||
@@ -55,7 +90,7 @@ modsController.flags.list = function (req, res, next) {
|
||||
flags: data.flags,
|
||||
analytics: data.analytics,
|
||||
categories: data.categories,
|
||||
hasFilter: !!Object.keys(filters).length,
|
||||
hasFilter: hasFilter,
|
||||
filters: filters,
|
||||
title: '[[pages:flags]]'
|
||||
});
|
||||
|
||||
52
src/flags.js
52
src/flags.js
@@ -53,31 +53,45 @@ Flags.list = function (filters, uid, callback) {
|
||||
}
|
||||
|
||||
var sets = [];
|
||||
var orSets = [];
|
||||
var prepareSets = function (setPrefix, value) {
|
||||
if (!Array.isArray(value)) {
|
||||
sets.push(setPrefix + value);
|
||||
} else if (value.length) {
|
||||
value.forEach(function (x) {
|
||||
orSets.push(setPrefix + x);
|
||||
});
|
||||
} else {
|
||||
// Empty array, do nothing
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if (Object.keys(filters).length > 0) {
|
||||
for (var type in filters) {
|
||||
switch (type) {
|
||||
case 'type':
|
||||
sets.push('flags:byType:' + filters[type]);
|
||||
prepareSets('flags:byType:', filters[type]);
|
||||
break;
|
||||
|
||||
case 'state':
|
||||
sets.push('flags:byState:' + filters[type]);
|
||||
prepareSets('flags:byState:', filters[type]);
|
||||
break;
|
||||
|
||||
case 'reporterId':
|
||||
sets.push('flags:byReporter:' + filters[type]);
|
||||
prepareSets('flags:byReporter:', filters[type]);
|
||||
break;
|
||||
|
||||
case 'assignee':
|
||||
sets.push('flags:byAssignee:' + filters[type]);
|
||||
prepareSets('flags:byAssignee:', filters[type]);
|
||||
break;
|
||||
|
||||
case 'targetUid':
|
||||
sets.push('flags:byTargetUid:' + filters[type]);
|
||||
prepareSets('flags:byTargetUid:', filters[type]);
|
||||
break;
|
||||
|
||||
case 'cid':
|
||||
sets.push('flags:byCid:' + filters[type]);
|
||||
prepareSets('flags:byCid:', filters[type]);
|
||||
break;
|
||||
|
||||
case 'quick':
|
||||
@@ -90,14 +104,36 @@ Flags.list = function (filters, uid, callback) {
|
||||
}
|
||||
}
|
||||
}
|
||||
sets = sets.length ? sets : ['flags:datetime']; // No filter default
|
||||
sets = (sets.length || orSets.length) ? sets : ['flags:datetime']; // No filter default
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
if (sets.length === 1) {
|
||||
db.getSortedSetRevRange(sets[0], 0, -1, next);
|
||||
} else if (sets.length > 1) {
|
||||
db.getSortedSetRevIntersect({ sets: sets, start: 0, stop: -1, aggregate: 'MAX' }, next);
|
||||
} else {
|
||||
db.getSortedSetRevIntersect({sets: sets, start: 0, stop: -1, aggregate: 'MAX'}, next);
|
||||
next(null, []);
|
||||
}
|
||||
},
|
||||
function (flagIds, next) {
|
||||
// Find flags according to "or" rules, if any
|
||||
if (orSets.length) {
|
||||
db.getSortedSetRevUnion({ sets: orSets, start: 0, stop: -1, aggregate: 'MAX' }, function (err, _flagIds) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (sets.length) {
|
||||
// If flag ids are already present, return a subset of flags that are in both sets
|
||||
next(null, _.intersection(flagIds, _flagIds));
|
||||
} else {
|
||||
// Otherwise, return all flags returned via orSets
|
||||
next(null, _.union(flagIds, _flagIds));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setImmediate(next, null, flagIds);
|
||||
}
|
||||
},
|
||||
function (flagIds, next) {
|
||||
|
||||
@@ -203,6 +203,41 @@ describe('Flags', function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a flag when filtered by both cid 1 and 2', function (done) {
|
||||
Flags.list({
|
||||
cid: [1, 2]
|
||||
}, 1, function (err, flags) {
|
||||
assert.ifError(err);
|
||||
assert.ok(Array.isArray(flags));
|
||||
assert.strictEqual(1, flags.length);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return one flag if filtered by both cid 1 and 2 and open state', function (done) {
|
||||
Flags.list({
|
||||
cid: [1, 2],
|
||||
state: 'open'
|
||||
}, 1, function (err, flags) {
|
||||
assert.ifError(err);
|
||||
assert.ok(Array.isArray(flags));
|
||||
assert.strictEqual(1, flags.length);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return no flag if filtered by both cid 1 and 2 and non-open state', function (done) {
|
||||
Flags.list({
|
||||
cid: [1, 2],
|
||||
state: 'resolved'
|
||||
}, 1, function (err, flags) {
|
||||
assert.ifError(err);
|
||||
assert.ok(Array.isArray(flags));
|
||||
assert.strictEqual(0, flags.length);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user