diff --git a/addons/api/addon/adapters/auth-method.js b/addons/api/addon/adapters/auth-method.js new file mode 100644 index 000000000..8aa06ee68 --- /dev/null +++ b/addons/api/addon/adapters/auth-method.js @@ -0,0 +1,13 @@ +import ApplicationAdapter from './application'; + +export default class AuthMethodAdapter extends ApplicationAdapter { + + // =attributes + + /** + * Auth methods use the new, unprefixed pathing style. + * @override + */ + hasScopePrefix = false; + +} diff --git a/addons/api/addon/serializers/auth-method.js b/addons/api/addon/serializers/auth-method.js new file mode 100644 index 000000000..d0c3c9312 --- /dev/null +++ b/addons/api/addon/serializers/auth-method.js @@ -0,0 +1,13 @@ +import ApplicationSerializer from './application'; + +export default class AuthMethodSerializer extends ApplicationSerializer { + + // =attributes + + /** + * Serialized the scope ID into the `scope_id` field. + * @type {boolean} + */ + serializeScopeID = true; + +} diff --git a/addons/api/app/adapters/auth-method.js b/addons/api/app/adapters/auth-method.js new file mode 100644 index 000000000..02c325d6e --- /dev/null +++ b/addons/api/app/adapters/auth-method.js @@ -0,0 +1 @@ +export { default } from 'api/adapters/auth-method'; diff --git a/addons/api/app/serializers/auth-method.js b/addons/api/app/serializers/auth-method.js new file mode 100644 index 000000000..39dadcf9d --- /dev/null +++ b/addons/api/app/serializers/auth-method.js @@ -0,0 +1 @@ +export { default } from 'api/serializers/auth-method'; diff --git a/addons/api/tests/unit/adapters/auth-method-test.js b/addons/api/tests/unit/adapters/auth-method-test.js new file mode 100644 index 000000000..06921d04c --- /dev/null +++ b/addons/api/tests/unit/adapters/auth-method-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Adapter | auth method', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:auth-method'); + assert.ok(adapter); + }); +}); diff --git a/addons/api/tests/unit/serializers/auth-method-test.js b/addons/api/tests/unit/serializers/auth-method-test.js new file mode 100644 index 000000000..3ea3b3a32 --- /dev/null +++ b/addons/api/tests/unit/serializers/auth-method-test.js @@ -0,0 +1,24 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Serializer | auth method', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let serializer = store.serializerFor('auth-method'); + + assert.ok(serializer); + }); + + test('it serializes records', function(assert) { + let store = this.owner.lookup('service:store'); + let record = store.createRecord('auth-method', {}); + + let serializedRecord = record.serialize(); + + assert.ok(serializedRecord); + }); + +}); diff --git a/ui/core/app/routes/scopes/scope/auth-methods.js b/ui/core/app/routes/scopes/scope/auth-methods.js index 7527ac784..ca382d686 100644 --- a/ui/core/app/routes/scopes/scope/auth-methods.js +++ b/ui/core/app/routes/scopes/scope/auth-methods.js @@ -23,8 +23,8 @@ export default class ScopesScopeAuthMethodsRoute extends Route { * @return {Promise[AuthMethodModel]} */ async model() { - const { id: scopeID} = this.modelFor('scopes.scope'); - return this.store.findAll('auth-method', { adapterOptions: { scopeID } }); + const { id: scope_id } = this.modelFor('scopes.scope'); + return this.store.query('auth-method', { scope_id }); } // =actions @@ -48,11 +48,12 @@ export default class ScopesScopeAuthMethodsRoute extends Route { const { isNew } = authMethod; try { await authMethod.save(); + await this + .transitionTo('scopes.scope.auth-methods.auth-method', authMethod); this.refresh(); this.notify.success( this.intl.t(isNew ? 'notify.create-success' : 'notify.save-success') ); - this.transitionTo('scopes.scope.auth-methods.auth-method', authMethod); } catch (error) { //TODO: replace with translated strings this.notify.error(error.message, { closeAfter: null }); @@ -67,9 +68,9 @@ export default class ScopesScopeAuthMethodsRoute extends Route { async delete(authMethod) { try { await authMethod.destroyRecord(); + await this.transitionTo('scopes.scope.auth-methods'); this.refresh(); this.notify.success(this.intl.t('notify.delete-success')); - this.transitionTo('scopes.scope.auth-methods'); } catch (error) { //TODO: replace with translated strings this.notify.error(error.message, { closeAfter: null }); diff --git a/ui/core/app/routes/scopes/scope/auth-methods/auth-method.js b/ui/core/app/routes/scopes/scope/auth-methods/auth-method.js index 5cc752eac..e75ba7cb3 100644 --- a/ui/core/app/routes/scopes/scope/auth-methods/auth-method.js +++ b/ui/core/app/routes/scopes/scope/auth-methods/auth-method.js @@ -9,8 +9,7 @@ export default class ScopesScopeAuthMethodsAuthMethodRoute extends Route { * @param {string} params.auth_method_id * @return {authMethodModel} */ - async model({ auth_method_id}) { - const { id: scopeID } = this.modelFor('scopes.scope'); - return this.store.findRecord('auth-method', auth_method_id, { adapterOptions: { scopeID }}); + async model({ auth_method_id }) { + return this.store.findRecord('auth-method', auth_method_id); } } diff --git a/ui/core/app/routes/scopes/scope/auth-methods/new.js b/ui/core/app/routes/scopes/scope/auth-methods/new.js index ceeb6a5d7..09fa7d445 100644 --- a/ui/core/app/routes/scopes/scope/auth-methods/new.js +++ b/ui/core/app/routes/scopes/scope/auth-methods/new.js @@ -1,6 +1,7 @@ import Route from '@ember/routing/route'; export default class ScopesScopeAuthMethodsNewRoute extends Route { + // =methods /** @@ -9,6 +10,10 @@ export default class ScopesScopeAuthMethodsNewRoute extends Route { */ model() { const scopeModel = this.modelFor('scopes.scope'); - return this.store.createRecord('auth-method', { type: 'password', scopeModel }); + return this.store.createRecord('auth-method', { + scopeModel, + type: 'password' + }); } + } diff --git a/ui/core/app/routes/scopes/scope/authenticate.js b/ui/core/app/routes/scopes/scope/authenticate.js index ef08a1566..d011a6b45 100644 --- a/ui/core/app/routes/scopes/scope/authenticate.js +++ b/ui/core/app/routes/scopes/scope/authenticate.js @@ -15,11 +15,11 @@ export default class ScopesScopeAuthenticateRoute extends Route { * @return {Promise} `{scope, scopes, authMethods}` */ model() { - const adapterOptions = { scopeID: this.modelFor('scopes.scope').id }; + const { id: scope_id } = this.modelFor('scopes.scope'); return hash({ scope: this.modelFor('scopes.scope'), scopes: this.modelFor('scopes'), - authMethods: this.store.findAll('auth-method', { adapterOptions }), + authMethods: this.store.query('auth-method', { scope_id }), // for integration testing: // authMethods: A([{ diff --git a/ui/core/mirage/config.js b/ui/core/mirage/config.js index cd9b48928..7d33d0b89 100644 --- a/ui/core/mirage/config.js +++ b/ui/core/mirage/config.js @@ -41,11 +41,13 @@ export default function() { // Auth & IAM resources - this.get('/scopes/:scope_id/auth-methods'); - this.post('/scopes/:scope_id/auth-methods'); - this.get('/scopes/:scope_id/auth-methods/:id'); - this.patch('/scopes/:scope_id/auth-methods/:id'); - this.del('/scopes/:scope_id/auth-methods/:id'); + this.get('/auth-methods', ({ authMethods }, { queryParams: { scope_id: scopeId } }) => { + return authMethods.where({ scopeId }); + }); + this.post('/auth-methods'); + this.get('/auth-methods/:id'); + this.patch('/auth-methods/:id'); + this.del('/auth-methods/:id'); // Authenticate/deauthenticate routes this.post('/scopes/:scope_id/auth-methods/:id_method', authHandler); diff --git a/ui/core/mirage/models/auth-method.js b/ui/core/mirage/models/auth-method.js new file mode 100644 index 000000000..08b1f5ad3 --- /dev/null +++ b/ui/core/mirage/models/auth-method.js @@ -0,0 +1,7 @@ +import { Model, belongsTo } from 'ember-cli-mirage'; + +export default Model.extend({ + + scope: belongsTo() + +}); diff --git a/ui/core/mirage/scenarios/default.js b/ui/core/mirage/scenarios/default.js index d08c2fb75..84d6708d8 100644 --- a/ui/core/mirage/scenarios/default.js +++ b/ui/core/mirage/scenarios/default.js @@ -15,7 +15,8 @@ export default function(server) { const scopePojo = { id: orgScope.id, type: orgScope.type }; // Auth - server.createList('auth-method', 3, { scope: scopePojo }); + server.createList('auth-method', 3, { scope: globalScope }); + server.createList('auth-method', 3, { scope: orgScope }); // Groups and Users server.createList('group', 5, { scope: scopePojo }, 'withMembers'); diff --git a/ui/core/mirage/serializers/auth-method.js b/ui/core/mirage/serializers/auth-method.js index cabe9ee7b..3d0c37374 100644 --- a/ui/core/mirage/serializers/auth-method.js +++ b/ui/core/mirage/serializers/auth-method.js @@ -1,5 +1,22 @@ import ApplicationSerializer from './application'; +import { underscore } from '@ember/string'; export default ApplicationSerializer.extend({ - modelName: 'auth-method' + modelName: 'auth-method', + + keyForRelationshipId(relationshipName) { + return `${this._container.inflector.singularize( + underscore(relationshipName) + )}_id`; + }, + + _hashForModel(model) { + const json = ApplicationSerializer.prototype._hashForModel.apply(this, arguments); + json.scope = { + id: model.scope.id, + type: model.scope.type + }; + return json; + } + }); diff --git a/ui/core/mirage/serializers/org.js b/ui/core/mirage/serializers/org.js deleted file mode 100644 index 43404176b..000000000 --- a/ui/core/mirage/serializers/org.js +++ /dev/null @@ -1,5 +0,0 @@ -import ApplicationSerializer from './application'; - -export default ApplicationSerializer.extend({ - modelName: 'org' -}); diff --git a/ui/core/mirage/serializers/project.js b/ui/core/mirage/serializers/project.js deleted file mode 100644 index 370fb5cf9..000000000 --- a/ui/core/mirage/serializers/project.js +++ /dev/null @@ -1,5 +0,0 @@ -import ApplicationSerializer from './application'; - -export default ApplicationSerializer.extend({ - modelName: 'project' -}); diff --git a/ui/core/tests/acceptance/authentication-test.js b/ui/core/tests/acceptance/authentication-test.js index f7abb618b..86425d6fa 100644 --- a/ui/core/tests/acceptance/authentication-test.js +++ b/ui/core/tests/acceptance/authentication-test.js @@ -21,7 +21,9 @@ module('Acceptance | authentication', function (hooks) { let scopesURL; let orgScopeURL; let scope; + let globalAuthMethod; let authMethod; + let globalAuthMethodID; let authMethodID; let globalAuthenticateURL; let authenticateURL; @@ -43,14 +45,16 @@ module('Acceptance | authentication', function (hooks) { 'withChildren' ); scope = { id: orgScope.id, type: orgScope.type }; - authMethod = this.server.create('auth-method', { scope }); + globalAuthMethod = this.server.create('auth-method', { scope: globalScope }); + authMethod = this.server.create('auth-method', { scope: orgScope }); orgScopeID = orgScope.id; + globalAuthMethodID = globalAuthMethod.id; authMethodID = authMethod.id; scopesURL = `/scopes`; orgScopeURL = `/scopes/${orgScopeID}`; globalAuthenticateURL = `/scopes/global/authenticate`; authenticateURL = `/scopes/${orgScopeID}/authenticate`; - authMethodGlobalAuthenticateURL = `/scopes/global/authenticate/${authMethodID}`; + authMethodGlobalAuthenticateURL = `/scopes/global/authenticate/${globalAuthMethodID}`; authMethodAuthenticateURL = `/scopes/${orgScopeID}/authenticate/${authMethodID}`; orgsURL = `/scopes/global/orgs`; projectsURL = `/scopes/${orgScopeID}/projects`; @@ -74,18 +78,8 @@ module('Acceptance | authentication', function (hooks) { test('visiting auth method when the scope cannot be loaded is still allowed', async function (assert) { assert.expect(1); - orgScope.destroy(); - this.server.get('/scopes', ({ scopes }, { queryParams: { scope_id } }) => { - // Default parent scope is global - if (!scope_id) scope_id = 'global'; - const results = scopes.where(scope => { - return scope.scope ? scope.scope.id === scope_id : false - }); - if (!results.length) { - return new Response(404); - } else { - return results; - } + this.server.get('/scopes', () => { + return new Response(404); }); await visit(authMethodAuthenticateURL); await a11yAudit();