mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-31 19:15:58 +01:00
feat: #7743, privileges
This commit is contained in:
@@ -1,212 +1,137 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var _ = require('lodash');
|
||||
const _ = require('lodash');
|
||||
|
||||
var groups = require('../groups');
|
||||
var user = require('../user');
|
||||
var plugins = require('../plugins');
|
||||
const groups = require('../groups');
|
||||
const user = require('../user');
|
||||
const plugins = require('../plugins');
|
||||
|
||||
var helpers = module.exports;
|
||||
const helpers = module.exports;
|
||||
|
||||
var uidToSystemGroup = {
|
||||
const uidToSystemGroup = {
|
||||
0: 'guests',
|
||||
'-1': 'spiders',
|
||||
};
|
||||
|
||||
helpers.some = function (tasks, callback) {
|
||||
async.some(tasks, function (task, next) {
|
||||
task(next);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
helpers.isUserAllowedTo = function (privilege, uid, cid, callback) {
|
||||
helpers.isUserAllowedTo = async function (privilege, uid, cid) {
|
||||
if (Array.isArray(privilege) && !Array.isArray(cid)) {
|
||||
isUserAllowedToPrivileges(privilege, uid, cid, callback);
|
||||
return await isUserAllowedToPrivileges(privilege, uid, cid);
|
||||
} else if (Array.isArray(cid) && !Array.isArray(privilege)) {
|
||||
isUserAllowedToCids(privilege, uid, cid, callback);
|
||||
} else {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
return await isUserAllowedToCids(privilege, uid, cid);
|
||||
}
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
};
|
||||
|
||||
function isUserAllowedToCids(privilege, uid, cids, callback) {
|
||||
async function isUserAllowedToCids(privilege, uid, cids) {
|
||||
if (parseInt(uid, 10) <= 0) {
|
||||
return isSystemGroupAllowedToCids(privilege, uid, cids, callback);
|
||||
return await isSystemGroupAllowedToCids(privilege, uid, cids);
|
||||
}
|
||||
|
||||
var userKeys = [];
|
||||
var groupKeys = [];
|
||||
const userKeys = [];
|
||||
const groupKeys = [];
|
||||
cids.forEach(function (cid) {
|
||||
userKeys.push('cid:' + cid + ':privileges:' + privilege);
|
||||
groupKeys.push('cid:' + cid + ':privileges:groups:' + privilege);
|
||||
});
|
||||
|
||||
checkIfAllowed(uid, userKeys, groupKeys, callback);
|
||||
return await checkIfAllowed(uid, userKeys, groupKeys);
|
||||
}
|
||||
|
||||
function isUserAllowedToPrivileges(privileges, uid, cid, callback) {
|
||||
async function isUserAllowedToPrivileges(privileges, uid, cid) {
|
||||
if (parseInt(uid, 10) <= 0) {
|
||||
return isSystemGroupAllowedToPrivileges(privileges, uid, cid, callback);
|
||||
return await isSystemGroupAllowedToPrivileges(privileges, uid, cid);
|
||||
}
|
||||
|
||||
var userKeys = [];
|
||||
var groupKeys = [];
|
||||
const userKeys = [];
|
||||
const groupKeys = [];
|
||||
privileges.forEach(function (privilege) {
|
||||
userKeys.push('cid:' + cid + ':privileges:' + privilege);
|
||||
groupKeys.push('cid:' + cid + ':privileges:groups:' + privilege);
|
||||
});
|
||||
|
||||
checkIfAllowed(uid, userKeys, groupKeys, callback);
|
||||
return await checkIfAllowed(uid, userKeys, groupKeys);
|
||||
}
|
||||
|
||||
function checkIfAllowed(uid, userKeys, groupKeys, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
hasUserPrivilege: function (next) {
|
||||
groups.isMemberOfGroups(uid, userKeys, next);
|
||||
},
|
||||
hasGroupPrivilege: function (next) {
|
||||
groups.isMemberOfGroupsList(uid, groupKeys, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
var result = userKeys.map(function (key, index) {
|
||||
return results.hasUserPrivilege[index] || results.hasGroupPrivilege[index];
|
||||
});
|
||||
|
||||
next(null, result);
|
||||
},
|
||||
], callback);
|
||||
async function checkIfAllowed(uid, userKeys, groupKeys) {
|
||||
const [hasUserPrivilege, hasGroupPrivilege] = await Promise.all([
|
||||
groups.isMemberOfGroups(uid, userKeys),
|
||||
groups.isMemberOfGroupsList(uid, groupKeys),
|
||||
]);
|
||||
return userKeys.map((key, index) => hasUserPrivilege[index] || hasGroupPrivilege[index]);
|
||||
}
|
||||
|
||||
helpers.isUsersAllowedTo = function (privilege, uids, cid, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
hasUserPrivilege: function (next) {
|
||||
groups.isMembers(uids, 'cid:' + cid + ':privileges:' + privilege, next);
|
||||
},
|
||||
hasGroupPrivilege: function (next) {
|
||||
groups.isMembersOfGroupList(uids, 'cid:' + cid + ':privileges:groups:' + privilege, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
var result = uids.map(function (uid, index) {
|
||||
return results.hasUserPrivilege[index] || results.hasGroupPrivilege[index];
|
||||
});
|
||||
|
||||
next(null, result);
|
||||
},
|
||||
], callback);
|
||||
helpers.isUsersAllowedTo = async function (privilege, uids, cid) {
|
||||
const [hasUserPrivilege, hasGroupPrivilege] = await Promise.all([
|
||||
groups.isMembers(uids, 'cid:' + cid + ':privileges:' + privilege),
|
||||
groups.isMembersOfGroupList(uids, 'cid:' + cid + ':privileges:groups:' + privilege),
|
||||
]);
|
||||
return uids.map((uid, index) => hasUserPrivilege[index] || hasGroupPrivilege[index]);
|
||||
};
|
||||
|
||||
function isSystemGroupAllowedToCids(privilege, uid, cids, callback) {
|
||||
async function isSystemGroupAllowedToCids(privilege, uid, cids) {
|
||||
const groupKeys = cids.map(cid => 'cid:' + cid + ':privileges:groups:' + privilege);
|
||||
groups.isMemberOfGroups(uidToSystemGroup[uid], groupKeys, callback);
|
||||
return await groups.isMemberOfGroups(uidToSystemGroup[uid], groupKeys);
|
||||
}
|
||||
|
||||
function isSystemGroupAllowedToPrivileges(privileges, uid, cid, callback) {
|
||||
async function isSystemGroupAllowedToPrivileges(privileges, uid, cid) {
|
||||
const groupKeys = privileges.map(privilege => 'cid:' + cid + ':privileges:groups:' + privilege);
|
||||
groups.isMemberOfGroups(uidToSystemGroup[uid], groupKeys, callback);
|
||||
return await groups.isMemberOfGroups(uidToSystemGroup[uid], groupKeys);
|
||||
}
|
||||
|
||||
helpers.getUserPrivileges = function (cid, hookName, userPrivilegeList, callback) {
|
||||
var userPrivileges;
|
||||
var memberSets;
|
||||
async.waterfall([
|
||||
async.apply(plugins.fireHook, hookName, userPrivilegeList.slice()),
|
||||
function (_privs, next) {
|
||||
userPrivileges = _privs;
|
||||
groups.getMembersOfGroups(userPrivileges.map(privilege => 'cid:' + cid + ':privileges:' + privilege), next);
|
||||
},
|
||||
function (_memberSets, next) {
|
||||
memberSets = _memberSets.map(function (set) {
|
||||
return set.map(uid => parseInt(uid, 10));
|
||||
});
|
||||
helpers.getUserPrivileges = async function (cid, hookName, userPrivilegeList) {
|
||||
const userPrivileges = await plugins.fireHook(hookName, userPrivilegeList.slice());
|
||||
let memberSets = await groups.getMembersOfGroups(userPrivileges.map(privilege => 'cid:' + cid + ':privileges:' + privilege));
|
||||
memberSets = memberSets.map(function (set) {
|
||||
return set.map(uid => parseInt(uid, 10));
|
||||
});
|
||||
|
||||
var members = _.uniq(_.flatten(memberSets));
|
||||
const members = _.uniq(_.flatten(memberSets));
|
||||
const memberData = await user.getUsersFields(members, ['picture', 'username']);
|
||||
|
||||
user.getUsersFields(members, ['picture', 'username'], next);
|
||||
},
|
||||
function (memberData, next) {
|
||||
memberData.forEach(function (member) {
|
||||
member.privileges = {};
|
||||
for (var x = 0, numPrivs = userPrivileges.length; x < numPrivs; x += 1) {
|
||||
member.privileges[userPrivileges[x]] = memberSets[x].includes(parseInt(member.uid, 10));
|
||||
}
|
||||
});
|
||||
memberData.forEach(function (member) {
|
||||
member.privileges = {};
|
||||
for (var x = 0, numPrivs = userPrivileges.length; x < numPrivs; x += 1) {
|
||||
member.privileges[userPrivileges[x]] = memberSets[x].includes(parseInt(member.uid, 10));
|
||||
}
|
||||
});
|
||||
|
||||
next(null, memberData);
|
||||
},
|
||||
], callback);
|
||||
return memberData;
|
||||
};
|
||||
|
||||
helpers.getGroupPrivileges = function (cid, hookName, groupPrivilegeList, callback) {
|
||||
var groupPrivileges;
|
||||
async.waterfall([
|
||||
async.apply(plugins.fireHook, hookName, groupPrivilegeList.slice()),
|
||||
function (_privs, next) {
|
||||
groupPrivileges = _privs;
|
||||
async.parallel({
|
||||
memberSets: function (next) {
|
||||
groups.getMembersOfGroups(groupPrivileges.map(privilege => 'cid:' + cid + ':privileges:' + privilege), next);
|
||||
},
|
||||
groupNames: function (next) {
|
||||
groups.getGroups('groups:createtime', 0, -1, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
var memberSets = results.memberSets;
|
||||
var uniqueGroups = _.uniq(_.flatten(memberSets));
|
||||
helpers.getGroupPrivileges = async function (cid, hookName, groupPrivilegeList) {
|
||||
const groupPrivileges = await plugins.fireHook(hookName, groupPrivilegeList.slice());
|
||||
const [memberSets, allGroupNames] = await Promise.all([
|
||||
groups.getMembersOfGroups(groupPrivileges.map(privilege => 'cid:' + cid + ':privileges:' + privilege)),
|
||||
groups.getGroups('groups:createtime', 0, -1),
|
||||
]);
|
||||
|
||||
var groupNames = results.groupNames.filter(groupName => !groupName.includes(':privileges:') && uniqueGroups.includes(groupName));
|
||||
const uniqueGroups = _.uniq(_.flatten(memberSets));
|
||||
|
||||
groupNames = groups.ephemeralGroups.concat(groupNames);
|
||||
moveToFront(groupNames, 'Global Moderators');
|
||||
moveToFront(groupNames, 'registered-users');
|
||||
let groupNames = allGroupNames.filter(groupName => !groupName.includes(':privileges:') && uniqueGroups.includes(groupName));
|
||||
|
||||
var adminIndex = groupNames.indexOf('administrators');
|
||||
if (adminIndex !== -1) {
|
||||
groupNames.splice(adminIndex, 1);
|
||||
}
|
||||
groupNames = groups.ephemeralGroups.concat(groupNames);
|
||||
moveToFront(groupNames, 'Global Moderators');
|
||||
moveToFront(groupNames, 'registered-users');
|
||||
|
||||
var memberPrivs;
|
||||
const adminIndex = groupNames.indexOf('administrators');
|
||||
if (adminIndex !== -1) {
|
||||
groupNames.splice(adminIndex, 1);
|
||||
}
|
||||
const groupData = await groups.getGroupsFields(groupNames, ['private']);
|
||||
const memberData = groupNames.map(function (member, index) {
|
||||
const memberPrivs = {};
|
||||
|
||||
var memberData = groupNames.map(function (member) {
|
||||
memberPrivs = {};
|
||||
|
||||
for (var x = 0, numPrivs = groupPrivileges.length; x < numPrivs; x += 1) {
|
||||
memberPrivs[groupPrivileges[x]] = memberSets[x].includes(member);
|
||||
}
|
||||
return {
|
||||
name: member,
|
||||
privileges: memberPrivs,
|
||||
};
|
||||
});
|
||||
|
||||
next(null, memberData);
|
||||
},
|
||||
function (memberData, next) {
|
||||
// Grab privacy info for the groups as well
|
||||
async.map(memberData, function (member, next) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
groups.isPrivate(member.name, next);
|
||||
},
|
||||
function (isPrivate, next) {
|
||||
member.isPrivate = isPrivate;
|
||||
next(null, member);
|
||||
},
|
||||
], next);
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
for (var x = 0, numPrivs = groupPrivileges.length; x < numPrivs; x += 1) {
|
||||
memberPrivs[groupPrivileges[x]] = memberSets[x].includes(member);
|
||||
}
|
||||
return {
|
||||
name: member,
|
||||
privileges: memberPrivs,
|
||||
isPrivate: groupData[index] && !!groupData[index].private,
|
||||
};
|
||||
});
|
||||
return memberData;
|
||||
};
|
||||
|
||||
function moveToFront(groupNames, groupToMove) {
|
||||
@@ -218,16 +143,19 @@ function moveToFront(groupNames, groupToMove) {
|
||||
}
|
||||
}
|
||||
|
||||
helpers.giveOrRescind = function (method, privileges, cids, groupNames, callback) {
|
||||
helpers.giveOrRescind = async function (method, privileges, cids, groupNames) {
|
||||
groupNames = Array.isArray(groupNames) ? groupNames : [groupNames];
|
||||
cids = Array.isArray(cids) ? cids : [cids];
|
||||
async.eachSeries(groupNames, function (groupName, next) {
|
||||
var groupKeys = [];
|
||||
for (const groupName of groupNames) {
|
||||
const groupKeys = [];
|
||||
cids.forEach((cid) => {
|
||||
privileges.forEach((privilege) => {
|
||||
groupKeys.push('cid:' + cid + ':privileges:groups:' + privilege);
|
||||
});
|
||||
});
|
||||
method(groupKeys, groupName, next);
|
||||
}, callback);
|
||||
/* eslint-disable no-await-in-loop */
|
||||
await method(groupKeys, groupName);
|
||||
}
|
||||
};
|
||||
|
||||
require('../promisify')(helpers);
|
||||
|
||||
Reference in New Issue
Block a user