diff --git a/addons/api/addon/abilities/user.js b/addons/api/addon/abilities/user.js new file mode 100644 index 000000000..dd2440fe7 --- /dev/null +++ b/addons/api/addon/abilities/user.js @@ -0,0 +1,22 @@ +import ModelAbility from './model'; + +/** + * Provides abilities for users. + */ +export default class UserAbility extends ModelAbility { + // =permissions + + /** + * @type {boolean} + */ + get canAddAccounts() { + return this.hasAuthorizedAction('add-accounts'); + } + + /** + * @type {boolean} + */ + get canRemoveAccounts() { + return this.hasAuthorizedAction('remove-accounts'); + } +} diff --git a/addons/api/app/abilities/user.js b/addons/api/app/abilities/user.js new file mode 100644 index 000000000..b02ba6ee2 --- /dev/null +++ b/addons/api/app/abilities/user.js @@ -0,0 +1 @@ +export { default } from 'api/abilities/user'; diff --git a/addons/api/mirage/factories/user.js b/addons/api/mirage/factories/user.js index b8463506d..837adba44 100644 --- a/addons/api/mirage/factories/user.js +++ b/addons/api/mirage/factories/user.js @@ -8,6 +8,8 @@ export default factory.extend({ 'read', 'update', 'delete', + 'add-accounts', + 'remove-accounts', ], id: (i) => `user-${i}`, }); diff --git a/addons/api/tests/unit/abilities/role-test.js b/addons/api/tests/unit/abilities/role-test.js index ffaf6a11d..fc927c92a 100644 --- a/addons/api/tests/unit/abilities/role-test.js +++ b/addons/api/tests/unit/abilities/role-test.js @@ -4,7 +4,7 @@ import { setupTest } from 'ember-qunit'; module('Unit | Abilities | Account', function (hooks) { setupTest(hooks); - test('it reflects when a given account may set grants based on authorized_actions', function (assert) { + test('it reflects when a given role may set grants based on authorized_actions', function (assert) { assert.expect(2); const service = this.owner.lookup('service:can'); const model = { @@ -15,7 +15,7 @@ module('Unit | Abilities | Account', function (hooks) { assert.notOk(service.can('setGrants role', model)); }); - test('it reflects when a given account may add principals based on authorized_actions', function (assert) { + test('it reflects when a given role may add principals based on authorized_actions', function (assert) { assert.expect(2); const service = this.owner.lookup('service:can'); const model = { @@ -26,7 +26,7 @@ module('Unit | Abilities | Account', function (hooks) { assert.notOk(service.can('addPrincipals role', model)); }); - test('it reflects when a given account may remove principals based on authorized_actions', function (assert) { + test('it reflects when a given role may remove principals based on authorized_actions', function (assert) { assert.expect(2); const service = this.owner.lookup('service:can'); const model = { diff --git a/addons/api/tests/unit/abilities/user-test.js b/addons/api/tests/unit/abilities/user-test.js new file mode 100644 index 000000000..23c60ac82 --- /dev/null +++ b/addons/api/tests/unit/abilities/user-test.js @@ -0,0 +1,28 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Abilities | Account', function (hooks) { + setupTest(hooks); + + test('it reflects when a given user resource may add accounts based on authorized_actions', function (assert) { + assert.expect(2); + const service = this.owner.lookup('service:can'); + const model = { + authorized_actions: ['add-accounts'], + }; + assert.ok(service.can('addAccounts user', model)); + model.authorized_actions = []; + assert.notOk(service.can('addAccounts user', model)); + }); + + test('it reflects when a given user resource may remove accounts based on authorized_actions', function (assert) { + assert.expect(2); + const service = this.owner.lookup('service:can'); + const model = { + authorized_actions: ['remove-accounts'], + }; + assert.ok(service.can('removeAccounts user', model)); + model.authorized_actions = []; + assert.notOk(service.can('removeAccounts user', model)); + }); +}); diff --git a/ui/admin/app/templates/scopes/scope/users/user/-actions.hbs b/ui/admin/app/templates/scopes/scope/users/user/-actions.hbs index 280fd98bb..998af871b 100644 --- a/ui/admin/app/templates/scopes/scope/users/user/-actions.hbs +++ b/ui/admin/app/templates/scopes/scope/users/user/-actions.hbs @@ -3,9 +3,11 @@ @dropdownRight={{true}} as |dropdown| > - - {{t 'resources.user.actions.add-accounts'}} - + {{#if (can 'addAccounts user' @model)}} + + {{t 'resources.user.actions.add-accounts'}} + + {{/if}} {{#if (can 'delete model' @model)}} - - - {{t 'actions.remove'}} - - + + {{t 'actions.remove'}} + + + {{/if}} {{/each}} diff --git a/ui/admin/tests/acceptance/users/accounts-test.js b/ui/admin/tests/acceptance/users/accounts-test.js index 8b7caaba6..01bd014e1 100644 --- a/ui/admin/tests/acceptance/users/accounts-test.js +++ b/ui/admin/tests/acceptance/users/accounts-test.js @@ -61,7 +61,7 @@ module('Acceptance | users | accounts', function (hooks) { assert.equal(findAll('tbody tr').length, accountsCount); }); - test('can remove a account', async function (assert) { + test('can remove an account', async function (assert) { assert.expect(2); await visit(urls.accounts); assert.equal(findAll('tbody tr').length, accountsCount); @@ -69,6 +69,16 @@ module('Acceptance | users | accounts', function (hooks) { assert.equal(findAll('tbody tr').length, accountsCount - 1); }); + test('cannot remove an account without proper authorization', async function (assert) { + assert.expect(1); + const authorized_actions = instances.user.authorized_actions.filter( + (item) => item !== 'remove-accounts' + ); + instances.user.update({ authorized_actions }); + await visit(urls.accounts); + assert.notOk(find('tbody tr .rose-dropdown-button-danger')); + }); + test('shows error message on account remove', async function (assert) { assert.expect(2); this.server.post('/users/:idMethod', () => { @@ -92,10 +102,27 @@ module('Acceptance | users | accounts', function (hooks) { test('visiting account add accounts', async function (assert) { assert.expect(1); await visit(urls.addAccounts); + await visit(urls.addAccounts); await a11yAudit(); assert.equal(currentURL(), urls.addAccounts); }); + test('can navigate to add accounts without proper authorization', async function (assert) { + assert.expect(1); + await visit(urls.accounts); + assert.ok(find(`[href="${urls.addAccounts}"]`)); + }); + + test('cannot navigate to add accounts without proper authorization', async function (assert) { + assert.expect(1); + const authorized_actions = instances.user.authorized_actions.filter( + (item) => item !== 'add-accounts' + ); + instances.user.update({ authorized_actions }); + await visit(urls.accounts); + assert.notOk(find(`[href="${urls.addAccounts}"]`)); + }); + test('select and save accounts to add', async function (assert) { assert.expect(3); instances.user.update({ accountIds: [] });