From dfab231afd7e42835649000c4a82f1a7571caa31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 15 May 2019 20:56:23 -0400 Subject: [PATCH] Copy group privs (#7610) * 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 --- .../en-GB/admin/manage/categories.json | 5 +++ public/src/admin/manage/privileges.js | 44 ++++++++++++++++--- src/categories/create.js | 32 +++++++++++++- src/socket.io/admin/categories.js | 26 ++++++++--- .../admin/partials/categories/privileges.tpl | 20 +++++++-- test/categories.js | 32 +++++++++++++- 6 files changed, 139 insertions(+), 20 deletions(-) diff --git a/public/language/en-GB/admin/manage/categories.json b/public/language/en-GB/admin/manage/categories.json index 7e49aef36b..1eda6ea080 100644 --- a/public/language/en-GB/admin/manage/categories.json +++ b/public/language/en-GB/admin/manage/categories.json @@ -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 registered-users group is granted a specific privilege, all other groups receive an implicit privilege, even if they are not explicitly defined/checked. This implicit privilege is shown to you because all users are part of the registered-users 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", diff --git a/public/src/admin/manage/privileges.js b/public/src/admin/manage/privileges.js index f43ebef04f..86b2351d36 100644 --- a/public/src/admin/manage/privileges.js +++ b/public/src/admin/manage/privileges.js @@ -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(); }; @@ -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); } @@ -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; }); diff --git a/src/categories/create.js b/src/categories/create.js index 4836db2d0b..3c1c23a354 100644 --- a/src/categories/create.js +++ b/src/categories/create.js @@ -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); @@ -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); + } }; diff --git a/src/socket.io/admin/categories.js b/src/socket.io/admin/categories.js index d585318f17..9497abed61 100644 --- a/src/socket.io/admin/categories.js +++ b/src/socket.io/admin/categories.js @@ -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) { @@ -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); }; diff --git a/src/views/admin/partials/categories/privileges.tpl b/src/views/admin/partials/categories/privileges.tpl index 9e0b8632d2..be5d892545 100644 --- a/src/views/admin/partials/categories/privileges.tpl +++ b/src/views/admin/partials/categories/privileges.tpl @@ -94,7 +94,18 @@ {privileges.groups.name} - + + + {function.spawnPrivilegeStates, privileges.groups.name, ../privileges} @@ -104,11 +115,14 @@ + - diff --git a/test/categories.js b/test/categories.js index 69e5fddbee..30e5c30842 100644 --- a/test/categories.js +++ b/test/categories.js @@ -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); @@ -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([ @@ -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) {