From 61f75970a4abeecc6105be245f32af5db4e8c9b3 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Fri, 1 Oct 2021 17:00:36 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20group=20memb?= =?UTF-8?q?ers=20abilities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/addon/abilities/group.js | 22 +++++++++++++ addons/api/app/abilities/group.js | 1 + addons/api/mirage/factories/group.js | 2 ++ addons/api/tests/unit/abilities/group-test.js | 28 ++++++++++++++++ addons/api/tests/unit/abilities/role-test.js | 2 +- addons/api/tests/unit/abilities/user-test.js | 2 +- .../scopes/scope/groups/group/-actions.hbs | 8 +++-- .../scopes/scope/groups/group/members.hbs | 33 +++++++++++-------- .../tests/acceptance/groups/members-test.js | 26 +++++++++++++++ .../tests/acceptance/users/accounts-test.js | 2 +- 10 files changed, 106 insertions(+), 20 deletions(-) create mode 100644 addons/api/addon/abilities/group.js create mode 100644 addons/api/app/abilities/group.js create mode 100644 addons/api/tests/unit/abilities/group-test.js diff --git a/addons/api/addon/abilities/group.js b/addons/api/addon/abilities/group.js new file mode 100644 index 000000000..810cc82c2 --- /dev/null +++ b/addons/api/addon/abilities/group.js @@ -0,0 +1,22 @@ +import ModelAbility from './model'; + +/** + * Provides abilities for groups. + */ +export default class GroupAbility extends ModelAbility { + // =permissions + + /** + * @type {boolean} + */ + get canAddMembers() { + return this.hasAuthorizedAction('add-members'); + } + + /** + * @type {boolean} + */ + get canRemoveMembers() { + return this.hasAuthorizedAction('remove-members'); + } +} diff --git a/addons/api/app/abilities/group.js b/addons/api/app/abilities/group.js new file mode 100644 index 000000000..308aacba4 --- /dev/null +++ b/addons/api/app/abilities/group.js @@ -0,0 +1 @@ +export { default } from 'api/abilities/group'; diff --git a/addons/api/mirage/factories/group.js b/addons/api/mirage/factories/group.js index 1f7256543..6a16d3fb0 100644 --- a/addons/api/mirage/factories/group.js +++ b/addons/api/mirage/factories/group.js @@ -9,6 +9,8 @@ export default factory.extend({ 'read', 'update', 'delete', + 'add-members', + 'remove-members', ], id: (i) => `group-${i}`, diff --git a/addons/api/tests/unit/abilities/group-test.js b/addons/api/tests/unit/abilities/group-test.js new file mode 100644 index 000000000..a53be03c2 --- /dev/null +++ b/addons/api/tests/unit/abilities/group-test.js @@ -0,0 +1,28 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Abilities | Group', function (hooks) { + setupTest(hooks); + + test('it reflects when a given group resource may add members based on authorized_actions', function (assert) { + assert.expect(2); + const service = this.owner.lookup('service:can'); + const model = { + authorized_actions: ['add-members'], + }; + assert.ok(service.can('addMembers group', model)); + model.authorized_actions = []; + assert.notOk(service.can('addMembers group', model)); + }); + + test('it reflects when a given group resource may remove members based on authorized_actions', function (assert) { + assert.expect(2); + const service = this.owner.lookup('service:can'); + const model = { + authorized_actions: ['remove-members'], + }; + assert.ok(service.can('removeMembers group', model)); + model.authorized_actions = []; + assert.notOk(service.can('removeMembers group', model)); + }); +}); diff --git a/addons/api/tests/unit/abilities/role-test.js b/addons/api/tests/unit/abilities/role-test.js index fc927c92a..462743446 100644 --- a/addons/api/tests/unit/abilities/role-test.js +++ b/addons/api/tests/unit/abilities/role-test.js @@ -1,7 +1,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -module('Unit | Abilities | Account', function (hooks) { +module('Unit | Abilities | Role', function (hooks) { setupTest(hooks); test('it reflects when a given role may set grants based on authorized_actions', function (assert) { diff --git a/addons/api/tests/unit/abilities/user-test.js b/addons/api/tests/unit/abilities/user-test.js index 23c60ac82..33d8f78e7 100644 --- a/addons/api/tests/unit/abilities/user-test.js +++ b/addons/api/tests/unit/abilities/user-test.js @@ -1,7 +1,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -module('Unit | Abilities | Account', function (hooks) { +module('Unit | Abilities | User', function (hooks) { setupTest(hooks); test('it reflects when a given user resource may add accounts based on authorized_actions', function (assert) { diff --git a/ui/admin/app/templates/scopes/scope/groups/group/-actions.hbs b/ui/admin/app/templates/scopes/scope/groups/group/-actions.hbs index 253b39ab0..7dbbf977b 100644 --- a/ui/admin/app/templates/scopes/scope/groups/group/-actions.hbs +++ b/ui/admin/app/templates/scopes/scope/groups/group/-actions.hbs @@ -3,9 +3,11 @@ @dropdownRight={{true}} as |dropdown| > - - {{t 'resources.group.actions.add-members'}} - + {{#if (can 'addMembers group' @model)}} + + {{t 'resources.group.actions.add-members'}} + + {{/if}} {{#if (can 'delete model' @model)}} - - - {{t 'actions.remove'}} - - + + {{t 'actions.remove'}} + + + {{/if}} {{/each}} diff --git a/ui/admin/tests/acceptance/groups/members-test.js b/ui/admin/tests/acceptance/groups/members-test.js index 2d615b8ba..295db8404 100644 --- a/ui/admin/tests/acceptance/groups/members-test.js +++ b/ui/admin/tests/acceptance/groups/members-test.js @@ -68,6 +68,16 @@ module('Acceptance | groups | members', function (hooks) { assert.equal(findAll('tbody tr').length, membersCount - 1); }); + test('cannot remove a member without proper authorization', async function (assert) { + assert.expect(1); + const authorized_actions = instances.group.authorized_actions.filter( + (item) => item !== 'remove-members' + ); + instances.group.update({ authorized_actions }); + await visit(urls.members); + assert.notOk(find('tbody tr .rose-dropdown-button-danger')); + }); + test('shows error message on member remove', async function (assert) { assert.expect(2); this.server.post('/groups/:idMethod', () => { @@ -95,6 +105,22 @@ module('Acceptance | groups | members', function (hooks) { assert.equal(currentURL(), urls.addMembers); }); + test('can navigate to add members with proper authorization', async function (assert) { + assert.expect(1); + await visit(urls.group); + assert.ok(find(`[href="${urls.addMembers}"]`)); + }); + + test('cannot navigate to add members without proper authorization', async function (assert) { + assert.expect(1); + const authorized_actions = instances.group.authorized_actions.filter( + (item) => item !== 'add-members' + ); + instances.group.update({ authorized_actions }); + await visit(urls.group); + assert.notOk(find(`[href="${urls.addMembers}"]`)); + }); + test('select and save members to add', async function (assert) { assert.expect(3); instances.group.update({ memberIds: [] }); diff --git a/ui/admin/tests/acceptance/users/accounts-test.js b/ui/admin/tests/acceptance/users/accounts-test.js index 01bd014e1..fe556f84a 100644 --- a/ui/admin/tests/acceptance/users/accounts-test.js +++ b/ui/admin/tests/acceptance/users/accounts-test.js @@ -107,7 +107,7 @@ module('Acceptance | users | accounts', function (hooks) { assert.equal(currentURL(), urls.addAccounts); }); - test('can navigate to add accounts without proper authorization', async function (assert) { + test('can navigate to add accounts with proper authorization', async function (assert) { assert.expect(1); await visit(urls.accounts); assert.ok(find(`[href="${urls.addAccounts}"]`));