Skip to content

Commit

Permalink
Copy group privs (NodeBB#7610)
Browse files Browse the repository at this point in the history
* feat: ability to copy a groups privileges

ability to copy a group's privileges to all categories, or children of current category

* feat: switch to dropdown

added copy from category to groups

* fix: indents
  • Loading branch information
barisusakli authored May 16, 2019
1 parent 183b0ed commit dfab231
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 20 deletions.
5 changes: 5 additions & 0 deletions public/language/en-GB/admin/manage/categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@
"privileges.search-group": "Add Group",
"privileges.copy-to-children": "Copy to Children",
"privileges.copy-from-category": "Copy from Category",
"privileges.copy-privileges-to-all-categories": "Copy to All Categories",
"privileges.copy-group-privileges-to-children": "Copy this group's privileges to the children of this category.",
"privileges.copy-group-privileges-to-all-categories": "Copy this group's privileges to all categories.",
"privileges.copy-group-privileges-from": "Copy this group's privileges from another category.",
"privileges.inherit": "If the <code>registered-users</code> group is granted a specific privilege, all other groups receive an <strong>implicit privilege</strong>, even if they are not explicitly defined/checked. This implicit privilege is shown to you because all users are part of the <code>registered-users</code> user group, and so, privileges for additional groups need not be explicitly granted.",
"privileges.copy-success": "Privileges copied!",

"analytics.back": "Back to Categories List",
"analytics.title": "Analytics for \"%1\" category",
Expand Down
44 changes: 37 additions & 7 deletions public/src/admin/manage/privileges.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,29 @@ define('admin/manage/privileges', [

$('.privilege-table-container').on('click', '[data-action="search.user"]', Privileges.addUserToPrivilegeTable);
$('.privilege-table-container').on('click', '[data-action="search.group"]', Privileges.addGroupToPrivilegeTable);
$('.privilege-table-container').on('click', '[data-action="copyToChildren"]', Privileges.copyPrivilegesToChildren);
$('.privilege-table-container').on('click', '[data-action="copyPrivilegesFrom"]', Privileges.copyPrivilegesFromCategory);
$('.privilege-table-container').on('click', '[data-action="copyToChildren"]', function () {
Privileges.copyPrivilegesToChildren(cid, '');
});
$('.privilege-table-container').on('click', '[data-action="copyToChildrenGroup"]', function () {
var groupName = $(this).parents('[data-group-name]').attr('data-group-name');
Privileges.copyPrivilegesToChildren(cid, groupName);
});

$('.privilege-table-container').on('click', '[data-action="copyPrivilegesFrom"]', function () {
Privileges.copyPrivilegesFromCategory(cid, '');
});
$('.privilege-table-container').on('click', '[data-action="copyPrivilegesFromGroup"]', function () {
var groupName = $(this).parents('[data-group-name]').attr('data-group-name');
Privileges.copyPrivilegesFromCategory(cid, groupName);
});

$('.privilege-table-container').on('click', '[data-action="copyToAll"]', function () {
Privileges.copyPrivilegesToAllCategories(cid, '');
});
$('.privilege-table-container').on('click', '[data-action="copyToAllGroup"]', function () {
var groupName = $(this).parents('[data-group-name]').attr('data-group-name');
Privileges.copyPrivilegesToAllCategories(cid, groupName);
});

Privileges.exposeAssumedPrivileges();
};
Expand Down Expand Up @@ -168,18 +189,18 @@ define('admin/manage/privileges', [
});
};

Privileges.copyPrivilegesToChildren = function () {
socket.emit('admin.categories.copyPrivilegesToChildren', cid, function (err) {
Privileges.copyPrivilegesToChildren = function (cid, group) {
socket.emit('admin.categories.copyPrivilegesToChildren', { cid: cid, group: group }, function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('Privileges copied!');
app.alertSuccess('[[admin/manage/categories:privileges.copy-success]]');
});
};

Privileges.copyPrivilegesFromCategory = function () {
Privileges.copyPrivilegesFromCategory = function (cid, group) {
categorySelector.modal(ajaxify.data.categories.slice(1), function (fromCid) {
socket.emit('admin.categories.copyPrivilegesFrom', { toCid: cid, fromCid: fromCid }, function (err) {
socket.emit('admin.categories.copyPrivilegesFrom', { toCid: cid, fromCid: fromCid, group: group }, function (err) {
if (err) {
return app.alertError(err.message);
}
Expand All @@ -188,5 +209,14 @@ define('admin/manage/privileges', [
});
};

Privileges.copyPrivilegesToAllCategories = function (cid, group) {
socket.emit('admin.categories.copyPrivilegesToAllCategories', { cid: cid, group: group }, function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[admin/manage/categories:privileges.copy-success]]');
});
};

return Privileges;
});
32 changes: 30 additions & 2 deletions src/categories/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,18 +208,28 @@ module.exports = function (Categories) {
], callback);
}

Categories.copyPrivilegesFrom = function (fromCid, toCid, callback) {
Categories.copyPrivilegesFrom = function (fromCid, toCid, group, callback) {
if (typeof group === 'function') {
callback = group;
group = '';
}

async.waterfall([
function (next) {
plugins.fireHook('filter:categories.copyPrivilegesFrom', {
privileges: privileges.privilegeList.slice(),
fromCid: fromCid,
toCid: toCid,
group: group,
}, next);
},
function (data, next) {
async.each(data.privileges, function (privilege, next) {
copyPrivilege(privilege, data.fromCid, data.toCid, next);
if (group) {
copyPrivilegeByGroup(privilege, data.fromCid, data.toCid, group, next);
} else {
copyPrivilege(privilege, data.fromCid, data.toCid, next);
}
}, next);
},
], callback);
Expand Down Expand Up @@ -249,4 +259,22 @@ module.exports = function (Categories) {
},
], callback);
}

function copyPrivilegeByGroup(privilege, fromCid, toCid, group, callback) {
async.waterfall([
function (next) {
groups.leave('cid:' + toCid + ':privileges:' + privilege, group, next);
},
function (next) {
db.isSortedSetMember('group:cid:' + fromCid + ':privileges:' + privilege + ':members', group, next);
},
function (isMember, next) {
if (!isMember) {
return callback();
}

groups.join('cid:' + toCid + ':privileges:' + privilege, group, next);
},
], callback);
}
};
26 changes: 20 additions & 6 deletions src/socket.io/admin/categories.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,25 +101,25 @@ Categories.getPrivilegeSettings = function (socket, cid, callback) {
}
};

Categories.copyPrivilegesToChildren = function (socket, cid, callback) {
Categories.copyPrivilegesToChildren = function (socket, data, callback) {
async.waterfall([
function (next) {
categories.getChildren([cid], socket.uid, next);
categories.getChildren([data.cid], socket.uid, next);
},
function (children, next) {
children = children[0];

async.eachSeries(children, function (child, next) {
copyPrivilegesToChildrenRecursive(cid, child, next);
copyPrivilegesToChildrenRecursive(data.cid, child, data.group, next);
}, next);
},
], callback);
};

function copyPrivilegesToChildrenRecursive(parentCid, category, callback) {
function copyPrivilegesToChildrenRecursive(parentCid, category, group, callback) {
async.waterfall([
function (next) {
categories.copyPrivilegesFrom(parentCid, category.cid, next);
categories.copyPrivilegesFrom(parentCid, category.cid, group, next);
},
function (next) {
async.eachSeries(category.children, function (child, next) {
Expand All @@ -134,5 +134,19 @@ Categories.copySettingsFrom = function (socket, data, callback) {
};

Categories.copyPrivilegesFrom = function (socket, data, callback) {
categories.copyPrivilegesFrom(data.fromCid, data.toCid, callback);
categories.copyPrivilegesFrom(data.fromCid, data.toCid, data.group, callback);
};

Categories.copyPrivilegesToAllCategories = function (socket, data, callback) {
async.waterfall([
function (next) {
categories.getAllCidsFromSet('categories:cid', next);
},
function (cids, next) {
cids = cids.filter(cid => parseInt(cid, 10) !== parseInt(data.cid, 10));
async.eachSeries(cids, function (toCid, next) {
categories.copyPrivilegesFrom(data.cid, toCid, data.group, next);
}, next);
},
], callback);
};
20 changes: 17 additions & 3 deletions src/views/admin/partials/categories/privileges.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,18 @@
<!-- ENDIF privileges.groups.isPrivate -->
{privileges.groups.name}
</td>
<td></td>
<td>
<div class="dropdown">
<button class="btn btn-default btn-sm dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-copy"></i>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li data-action="copyToAllGroup"><a href="#">[[admin/manage/categories:privileges.copy-group-privileges-to-all-categories]]</a></li>
<li data-action="copyToChildrenGroup"><a href="#">[[admin/manage/categories:privileges.copy-group-privileges-to-children]]</a></li>
<li data-action="copyPrivilegesFromGroup"><a href="#">[[admin/manage/categories:privileges.copy-group-privileges-from]]</a></li>
</ul>
</div>
</td>
{function.spawnPrivilegeStates, privileges.groups.name, ../privileges}
</tr>
<!-- END privileges.groups -->
Expand All @@ -104,11 +115,14 @@
<button type="button" class="btn btn-primary pull-right" data-ajaxify="false" data-action="search.group">
[[admin/manage/categories:privileges.search-group]]
</button>
<button type="button" class="btn btn-info pull-right" data-ajaxify="false" data-action="copyPrivilegesFrom">
[[admin/manage/categories:privileges.copy-from-category]]
</button>
<button type="button" class="btn btn-info pull-right" data-ajaxify="false" data-action="copyToChildren">
[[admin/manage/categories:privileges.copy-to-children]]
</button>
<button type="button" class="btn btn-info pull-right" data-ajaxify="false" data-action="copyPrivilegesFrom">
[[admin/manage/categories:privileges.copy-from-category]]
<button type="button" class="btn btn-info pull-right" data-ajaxify="false" data-action="copyToAll">
[[admin/manage/categories:privileges.copy-privileges-to-all-categories]]
</button>
</div>
</td>
Expand Down
32 changes: 30 additions & 2 deletions test/categories.js
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ describe('Categories', function () {
socketCategories.setPrivilege({ uid: adminUid }, { cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users' }, next);
},
function (next) {
socketCategories.copyPrivilegesToChildren({ uid: adminUid }, parentCid, next);
socketCategories.copyPrivilegesToChildren({ uid: adminUid }, { cid: parentCid, group: '' }, next);
},
function (next) {
privileges.categories.can('topics:delete', child2Cid, posterUid, next);
Expand Down Expand Up @@ -561,7 +561,7 @@ describe('Categories', function () {
], done);
});

it('should copy privileges from', function (done) {
it('should copy privileges from another category', function (done) {
var child1Cid;
var parentCid;
async.waterfall([
Expand All @@ -588,6 +588,34 @@ describe('Categories', function () {
},
], done);
});

it('should copy privileges from another category for a single group', function (done) {
var child1Cid;
var parentCid;
async.waterfall([
function (next) {
Categories.create({ name: 'parent', description: 'copy me' }, next);
},
function (category, next) {
parentCid = category.cid;
Categories.create({ name: 'child1' }, next);
},
function (category, next) {
child1Cid = category.cid;
socketCategories.setPrivilege({ uid: adminUid }, { cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users' }, next);
},
function (next) {
socketCategories.copyPrivilegesFrom({ uid: adminUid }, { fromCid: parentCid, toCid: child1Cid, group: 'registered-users' }, next);
},
function (next) {
privileges.categories.can('topics:delete', child1Cid, 0, next);
},
function (canDelete, next) {
assert(!canDelete);
next();
},
], done);
});
});

it('should get active users', function (done) {
Expand Down

0 comments on commit dfab231

Please sign in to comment.