diff --git a/addons/api/addon/abilities/target.js b/addons/api/addon/abilities/target.js new file mode 100644 index 000000000..12b35044e --- /dev/null +++ b/addons/api/addon/abilities/target.js @@ -0,0 +1,15 @@ +import ModelAbility from './model'; + +/** + * Provides a `connect` ability for targets. + */ +export default class TargetAbility extends ModelAbility { + // =permissions + + /** + * @type {boolean} + */ + get canConnect() { + return this.hasAuthorizedAction('authorize-session'); + } +} diff --git a/addons/api/app/abilities/target.js b/addons/api/app/abilities/target.js new file mode 100644 index 000000000..971fa065d --- /dev/null +++ b/addons/api/app/abilities/target.js @@ -0,0 +1 @@ +export { default } from 'api/abilities/target'; diff --git a/addons/api/mirage/factories/target.js b/addons/api/mirage/factories/target.js index 94a15d0bb..138d53671 100644 --- a/addons/api/mirage/factories/target.js +++ b/addons/api/mirage/factories/target.js @@ -13,6 +13,7 @@ export default factory.extend({ 'read', 'update', 'delete', + 'authorize-session', ], /** * -1 means "unlimited" and we want to generate these on occasion. diff --git a/addons/api/tests/unit/abilities/target-test.js b/addons/api/tests/unit/abilities/target-test.js new file mode 100644 index 000000000..09b64c9c8 --- /dev/null +++ b/addons/api/tests/unit/abilities/target-test.js @@ -0,0 +1,17 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Abilities | Target', function (hooks) { + setupTest(hooks); + + test('it reflects when a given target may connect based on authorized_actions', function (assert) { + assert.expect(2); + const service = this.owner.lookup('service:can'); + const model = { + authorized_actions: ['authorize-session'], + }; + assert.ok(service.can('connect target', model)); + model.authorized_actions = []; + assert.notOk(service.can('connect target', model)); + }); +}); diff --git a/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs b/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs index f7fd23120..a7c726fee 100644 --- a/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs +++ b/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs @@ -74,12 +74,14 @@ - - {{t 'resources.session.actions.connect'}} - + {{#if (can 'connect target' model)}} + + {{t 'resources.session.actions.connect'}} + + {{/if}} {{/each}} diff --git a/ui/desktop/tests/acceptance/projects/targets-test.js b/ui/desktop/tests/acceptance/projects/targets-test.js index bb253dd45..fc40f6611 100644 --- a/ui/desktop/tests/acceptance/projects/targets-test.js +++ b/ui/desktop/tests/acceptance/projects/targets-test.js @@ -100,7 +100,9 @@ module('Acceptance | projects | targets', function (hooks) { ); instances.target = this.server.create( 'target', - { scope: instances.scopes.project }, + { + scope: instances.scopes.project, + }, 'withAssociations' ); @@ -253,6 +255,24 @@ module('Acceptance | projects | targets', function (hooks) { await visit(urls.targets); }); + test('cannot connect to a target without proper authorization', async function (assert) { + assert.expect(3); + instances.target.update({ + authorized_actions: instances.target.authorized_actions.filter( + (action) => action != 'authorize-session' + ), + }); + assert.notOk( + instances.target.authorized_actions.includes('authorize-session') + ); + later(async () => { + run.cancelTimers(); + assert.ok(find('tbody tr:first-child')); + assert.notOk(find('tbody tr:first-child td:last-child button')); + }, 750); + await visit(urls.targets); + }); + test('handles cli error on connect', async function (assert) { assert.expect(4); stubs.ipcService.withArgs('cliExists').returns(true);