From ac8a6054b0a8a48f80321d7029e5830173c6a8b0 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Wed, 24 Mar 2021 18:36:34 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20API=20and=20mock?= =?UTF-8?q?=20support=20for=20primary=20auth=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/addon/generated/models/auth-method.js | 6 ++ addons/api/addon/generated/models/scope.js | 6 ++ addons/api/addon/models/auth-method.js | 5 +- addons/api/addon/serializers/auth-method.js | 18 +++++ addons/api/app/serializers/auth-method.js | 1 + addons/api/mirage/scenarios/default.js | 8 ++- addons/api/mirage/serializers/auth-method.js | 13 ++++ .../unit/serializers/auth-method-test.js | 66 +++++++++++++++++++ 8 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 addons/api/addon/serializers/auth-method.js create mode 100644 addons/api/app/serializers/auth-method.js create mode 100644 addons/api/tests/unit/serializers/auth-method-test.js diff --git a/addons/api/addon/generated/models/auth-method.js b/addons/api/addon/generated/models/auth-method.js index 8c68a8f53..4ba4158da 100644 --- a/addons/api/addon/generated/models/auth-method.js +++ b/addons/api/addon/generated/models/auth-method.js @@ -7,6 +7,12 @@ import { attr } from '@ember-data/model'; export default class GeneratedAuthMethodModel extends BaseModel { // =attributes + @attr('boolean', { + description: 'Specifies if this is the primary auth method for its scope.', + readOnly: true, + }) + primary; + @attr('string', { description: 'The type of the resource, to help differentiate schemas', }) diff --git a/addons/api/addon/generated/models/scope.js b/addons/api/addon/generated/models/scope.js index 2fff1057b..35f534087 100644 --- a/addons/api/addon/generated/models/scope.js +++ b/addons/api/addon/generated/models/scope.js @@ -7,6 +7,12 @@ import { attr } from '@ember-data/model'; export default class GeneratedScopeModel extends BaseModel { // =attributes + @attr('string', { + description: + 'The ID of the primary auth method for this scope. A primary auth method\nis allowed to vivify users when new accounts are created and is the source for the users account info.', + }) + primary_auth_method_id; + @attr('string', { description: 'The type of the resource', }) diff --git a/addons/api/addon/models/auth-method.js b/addons/api/addon/models/auth-method.js index ad795fd7d..2c5b708ea 100644 --- a/addons/api/addon/models/auth-method.js +++ b/addons/api/addon/models/auth-method.js @@ -1,3 +1,6 @@ import GeneratedAuthMethodModel from '../generated/models/auth-method'; +import { equal } from '@ember/object/computed'; -export default class AuthMethodModel extends GeneratedAuthMethodModel {} +export default class AuthMethodModel extends GeneratedAuthMethodModel { + @equal('primary', true) isPrimary; +} diff --git a/addons/api/addon/serializers/auth-method.js b/addons/api/addon/serializers/auth-method.js new file mode 100644 index 000000000..d707f4839 --- /dev/null +++ b/addons/api/addon/serializers/auth-method.js @@ -0,0 +1,18 @@ +import ApplicationSerializer from './application'; + +export default class AuthMethodSerializer extends ApplicationSerializer { + /** + * Sorts the array in order of "primary" such that the primary method appears + * first. The "natural" order of auth methods places primary first. + * + * @override + * @return {object} + */ + normalizeArrayResponse() { + const normalized = super.normalizeArrayResponse(...arguments); + normalized.data = normalized.data.sort((a) => + a.attributes.primary ? -1 : 1 + ); + return normalized; + } +} 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/mirage/scenarios/default.js b/addons/api/mirage/scenarios/default.js index fe5297ea2..b5a5c88d3 100644 --- a/addons/api/mirage/scenarios/default.js +++ b/addons/api/mirage/scenarios/default.js @@ -20,18 +20,22 @@ export default function (server) { server.create('user', { id: 'authenticateduser' }); // Auth - server.createList( + const globalAuthMethods = server.createList( 'auth-method', 1, { scope: globalScope }, 'withAccountsAndUsers' ); - server.createList( + const orgAuthMethods = server.createList( 'auth-method', 3, { scope: orgScope }, 'withAccountsAndUsers' ); + // Assign primary auth methods per scope + // TODO make this generic + globalScope.update({ primary_auth_method_id: globalAuthMethods[0].id }); + orgScope.update({ primary_auth_method_id: orgAuthMethods[1].id }); // Groups and Users server.createList('group', 1, { scope: globalScope }, 'withMembers'); diff --git a/addons/api/mirage/serializers/auth-method.js b/addons/api/mirage/serializers/auth-method.js index 4bc89ef3b..058487279 100644 --- a/addons/api/mirage/serializers/auth-method.js +++ b/addons/api/mirage/serializers/auth-method.js @@ -2,4 +2,17 @@ import ApplicationSerializer from './application'; export default ApplicationSerializer.extend({ modelName: 'auth-method', + + _hashForModel(model) { + const json = ApplicationSerializer.prototype._hashForModel.apply( + this, + arguments + ); + // If the scope marks this auth method as primary, designate it + // as such with a read-only boolean field (this is how the API behaves). + if (model.scope && model.scope.primary_auth_method_id === model.id) { + json.primary = true; + } + return json; + }, }); 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..c5e63af76 --- /dev/null +++ b/addons/api/tests/unit/serializers/auth-method-test.js @@ -0,0 +1,66 @@ +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); + }); + + test('it sorts primary first in normalizeArrayResponse', function (assert) { + assert.expect(2); + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('auth-method'); + const modelClass = store.createRecord('auth-method').constructor; + const payload = { + items: [{ id: 1 }, { id: 2, primary: true }, { id: 3 }], + }; + const normalizedArray = serializer.normalizeArrayResponse( + store, + modelClass, + payload + ); + assert.ok(payload.items[1].primary, 'Second payload item is primary'); + assert.deepEqual( + normalizedArray, + { + included: [], + data: [ + { + id: '2', + type: 'auth-method', + attributes: { primary: true }, + relationships: {}, + }, + { + id: '1', + type: 'auth-method', + attributes: {}, + relationships: {}, + }, + { + id: '3', + type: 'auth-method', + attributes: {}, + relationships: {}, + }, + ], + }, + 'First normalized itme is primary' + ); + }); +});