From 879a58dcb86bb8769ae430c6018356932a71ee44 Mon Sep 17 00:00:00 2001 From: Dharini Jeeva Date: Fri, 15 Mar 2024 14:24:20 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20mirage=20support=20and?= =?UTF-8?q?=20initial=20route=20for=20aliases=20(#2181)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 mirage support and initial route for aliases --- addons/api/addon/generated/models/alias.js | 58 +++++++++++++++++++ addons/api/addon/models/alias.js | 10 ++++ addons/api/app/models/alias.js | 6 ++ addons/api/mirage/config.js | 16 +++++ addons/api/mirage/factories/alias.js | 22 +++++++ addons/api/mirage/factories/scope.js | 5 +- .../api/mirage/generated/factories/alias.js | 21 +++++++ addons/api/mirage/models/alias.js | 11 ++++ addons/api/mirage/scenarios/default.js | 3 + addons/api/tests/unit/models/alias-test.js | 17 ++++++ ui/admin/app/router.js | 5 ++ ui/admin/app/routes/scopes/scope/aliases.js | 42 ++++++++++++++ 12 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 addons/api/addon/generated/models/alias.js create mode 100644 addons/api/addon/models/alias.js create mode 100644 addons/api/app/models/alias.js create mode 100644 addons/api/mirage/factories/alias.js create mode 100644 addons/api/mirage/generated/factories/alias.js create mode 100644 addons/api/mirage/models/alias.js create mode 100644 addons/api/tests/unit/models/alias-test.js create mode 100644 ui/admin/app/routes/scopes/scope/aliases.js diff --git a/addons/api/addon/generated/models/alias.js b/addons/api/addon/generated/models/alias.js new file mode 100644 index 000000000..98a8767ee --- /dev/null +++ b/addons/api/addon/generated/models/alias.js @@ -0,0 +1,58 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import BaseModel from '../../models/base'; +import { attr } from '@ember-data/model'; + +/** + * Alias contains all fields related to an Alias resource + */ +export default class GeneratedAliasModel extends BaseModel { + // =attributes + + @attr('string', { + description: 'The type of the resource, to help differentiate schemas', + }) + type; + + @attr('string', { + description: 'Optional name for identification purposes.', + }) + name; + + @attr('string', { + description: 'Optional user-set description for identification purposes.', + }) + description; + + @attr('date', { + description: 'The time this resource was created\nOutput only.', + readOnly: true, + }) + created_time; + + @attr('date', { + description: 'The time this resource was last updated\nOutput only.', + readOnly: true, + }) + updated_time; + + @attr('number', { + description: 'Current version number of this resource.', + }) + version; + + @attr('string', { + description: 'This is the id of the resource that this Alias points to.', + }) + destination_id; + + @attr('object', { + isNestedAttribute: true, + description: + 'This contains a host_id which is the id of the host that the session will be authorized for.', + }) + authorize_session_arguments; +} diff --git a/addons/api/addon/models/alias.js b/addons/api/addon/models/alias.js new file mode 100644 index 000000000..0f7e8311e --- /dev/null +++ b/addons/api/addon/models/alias.js @@ -0,0 +1,10 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import GeneratedAliasModel from '../generated/models/alias'; + +export const TYPE_ALIAS_TARGET = 'target'; +export const TYPES_ALIAS = Object.freeze([TYPE_ALIAS_TARGET]); +export default class AliasModel extends GeneratedAliasModel {} diff --git a/addons/api/app/models/alias.js b/addons/api/app/models/alias.js new file mode 100644 index 000000000..abf038afa --- /dev/null +++ b/addons/api/app/models/alias.js @@ -0,0 +1,6 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +export { default } from 'api/models/alias'; diff --git a/addons/api/mirage/config.js b/addons/api/mirage/config.js index cd4de1f31..9121f0d0f 100644 --- a/addons/api/mirage/config.js +++ b/addons/api/mirage/config.js @@ -753,6 +753,22 @@ function routes() { return policies.create(attrs); }); + // Alias + this.get( + '/aliases', + ({ aliases }, { queryParams: { scope_id: scopeId } }) => { + return aliases.where({ scopeId }); + }, + ); + this.get('/aliases/:id'); + this.del('/aliases/:id'); + this.patch('/aliases/:id'); + this.post('/aliases', function ({ aliases }) { + const attrs = this.normalizedRequestAttrs(); + + return aliases.create(attrs); + }); + // session recordings this.get( '/session-recordings', diff --git a/addons/api/mirage/factories/alias.js b/addons/api/mirage/factories/alias.js new file mode 100644 index 000000000..295046786 --- /dev/null +++ b/addons/api/mirage/factories/alias.js @@ -0,0 +1,22 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import factory from '../generated/factories/alias'; +import permissions from '../helpers/permissions'; +import generateId from '../helpers/id'; + +const destinationIDs = ['', generateId('t_')]; + +export default factory.extend({ + id: () => generateId('alt_'), + destination_id: (i) => destinationIDs[i % destinationIDs.length], + authorized_actions: () => + permissions.authorizedActionsFor('alias') || [ + 'no-op', + 'read', + 'update', + 'delete', + ], +}); diff --git a/addons/api/mirage/factories/scope.js b/addons/api/mirage/factories/scope.js index 6bedf3406..89e3afca8 100644 --- a/addons/api/mirage/factories/scope.js +++ b/addons/api/mirage/factories/scope.js @@ -33,12 +33,13 @@ export default factory.extend({ roles: ['create', 'list'], }; - // Worker permissions only available on the global scope + // Resources that are available only on the global scope if (this.type === 'global') { collectionActions.workers = ['create:worker-led', 'list']; + collectionActions.aliases = ['create', 'list']; } - // Session recording resources are only available on global or org scope + // Resources that are only available on the global or the org scope if (this.type === 'global' || this.type === 'org') { collectionActions['storage-buckets'] = ['create', 'list']; collectionActions['session-recordings'] = ['list']; diff --git a/addons/api/mirage/generated/factories/alias.js b/addons/api/mirage/generated/factories/alias.js new file mode 100644 index 000000000..47eca51e5 --- /dev/null +++ b/addons/api/mirage/generated/factories/alias.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { Factory } from 'miragejs'; +import { faker } from '@faker-js/faker'; +import { TYPE_ALIAS_TARGET } from 'api/models/alias'; + +/** + * GeneratedAliasModelFactory + */ +export default Factory.extend({ + name: () => faker.word.words(), + type: TYPE_ALIAS_TARGET, + value: () => faker.word.words(), + description: () => faker.word.words(), + created_time: () => faker.date.recent(), + updated_time: () => faker.date.recent(), + version: () => faker.number.int(), +}); diff --git a/addons/api/mirage/models/alias.js b/addons/api/mirage/models/alias.js new file mode 100644 index 000000000..b576cfe2f --- /dev/null +++ b/addons/api/mirage/models/alias.js @@ -0,0 +1,11 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { belongsTo } from 'miragejs'; +import Model from './base'; + +export default Model.extend({ + scope: belongsTo(), +}); diff --git a/addons/api/mirage/scenarios/default.js b/addons/api/mirage/scenarios/default.js index 351f1dec0..712dc8db4 100644 --- a/addons/api/mirage/scenarios/default.js +++ b/addons/api/mirage/scenarios/default.js @@ -108,6 +108,9 @@ export default function (server) { server.createList('policy', 3, { scope: globalScope }); server.createList('policy', 3, { scope: orgScope }); + // Aliases + server.createList('alias', 3, { scope: globalScope }); + // Other resources server.schema.scopes.where({ type: 'project' }).models.forEach((scope) => { server.createList('host-catalog', 8, { scope }, 'withChildren'); diff --git a/addons/api/tests/unit/models/alias-test.js b/addons/api/tests/unit/models/alias-test.js new file mode 100644 index 000000000..ab4fd4f53 --- /dev/null +++ b/addons/api/tests/unit/models/alias-test.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Model | alias', function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let store = this.owner.lookup('service:store'); + let model = store.createRecord('alias', {}); + assert.ok(model); + }); +}); diff --git a/ui/admin/app/router.js b/ui/admin/app/router.js index 785431c8f..7effc0c4e 100644 --- a/ui/admin/app/router.js +++ b/ui/admin/app/router.js @@ -95,6 +95,11 @@ Router.map(function () { this.route('new'); }); + this.route('aliases', function () { + this.route('new'); + this.route('alias', { path: ':alias_id' }, function () {}); + }); + this.route('host-catalogs', function () { this.route('new'); this.route('host-catalog', { path: ':host_catalog_id' }, function () { diff --git a/ui/admin/app/routes/scopes/scope/aliases.js b/ui/admin/app/routes/scopes/scope/aliases.js new file mode 100644 index 000000000..63e3ec5de --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/aliases.js @@ -0,0 +1,42 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeAliasesRoute extends Route { + // =services + + @service store; + @service session; + @service can; + @service router; + + // =methods + + /** + * If arriving here unauthenticated, redirect to index for further processing. + */ + beforeModel() { + if (!this.session.isAuthenticated) this.router.transitionTo('index'); + } + + /** + * Load all aliases in current scope + * @return {Promise<[AliasModel]>} + */ + async model() { + const scope = this.modelFor('scopes.scope'); + const { id: scope_id } = scope; + + if ( + this.can.can('list model', scope, { + collection: 'aliases', + }) + ) { + return this.store.query('alias', { scope_id }); + } + } +}