Merge branch 'main' into filterable-store-api-addon

This commit is contained in:
Randall Morey authored and GitHub committed 2021-11-09 12:44:49 -05:00
commit 27e0daaee0
63 files changed
+739 -796

No files matched your search

+20 -3
View File
@@ -2,7 +2,7 @@ import RESTAdapter from '@ember-data/adapter/rest';
import { serializeIntoHash } from '@ember-data/adapter/-private';
/* eslint-disable-next-line ember/no-mixins */
import AdapterBuildURLMixin from '../mixins/adapter-build-url';
import config from 'ember-get-config';
import { getOwner } from '@ember/application';
import { get } from '@ember/object';
import { InvalidError } from '@ember-data/adapter/error';
import { dasherize } from '@ember/string';
@@ -44,19 +44,36 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
) {
// =attributes
#host;
#namespace;
/**
* Sets host to the `api.host` string in the application's config,
* if set.
* @type {string}
*/
host = get(config, 'api.host');
get host() {
const config = getOwner(this).resolveRegistration('config:environment');
return this.#host || get(config, 'api.host');
}
set host(value) {
// Setting this value is useful for testing purposes.
this.#host = value;
}
/**
* Sets namespace to the `api.namespace` string in the application's config,
* if set.
* @type {string}
*/
namespace = get(config, 'api.namespace');
get namespace() {
const config = getOwner(this).resolveRegistration('config:environment');
return this.#namespace || get(config, 'api.namespace');
}
set namespace(value) {
// Setting this value is useful for testing purposes.
this.#namespace = value;
}
// =methods
@@ -0,0 +1,47 @@
import BaseModel from '../../models/base';
import { attr } from '@ember-data/model';
/**
* A managed group is a resource that represents a collection of accounts.
*/
export default class GeneratedManagedGroupModel extends BaseModel {
// =attributes
@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',
readOnly: true,
})
created_time;
@attr('date', {
description: 'The time this resource was last updated.',
readOnly: true,
})
updated_time;
@attr('number', {
description: 'Current version number of this resource.',
})
version;
@attr('string', {
description: 'The type of this ManagedGroup.',
})
type;
@attr('string', {
description:
'The ID of the Auth Method that is associated with this ManagedGroup',
})
auth_method_id;
}
@@ -0,0 +1,12 @@
import Fragment from 'ember-data-model-fragments/fragment';
import { attr } from '@ember-data/model';
export default class FragmentManagedGroupAttributesModel extends Fragment {
// =attributes (OIDC)
@attr('string', {
description:
'The boolean expression filter to use to determine membership.',
})
filter;
}
+21
View File
@@ -0,0 +1,21 @@
import GeneratedManagedGroupModel from '../generated/models/managed-group';
import { attr } from '@ember-data/model';
import { fragment } from 'ember-data-model-fragments/attributes';
import { A } from '@ember/array';
export default class ManagedGroupModel extends GeneratedManagedGroupModel {
// =attributes
/**
* Members is read-only under normal circumstances. But members can
* be persisted via calls to `addMembers()` or `removeMembers()`.
*/
@attr({
readOnly: true,
defaultValue: () => A(),
emptyArrayIfMissing: true,
})
member_ids;
@fragment('fragment-managed-group-attributes', { defaultValue: {} })
attributes;
}
@@ -0,0 +1,27 @@
import JSONSerializer from '@ember-data/serializer/json';
export default class FragmentManagedGroupAttributesSerializer extends JSONSerializer {
/**
* If an attribute is annotated as readOnly in the model, don't serialize it.
* Otherwise delegate to default attribute serializer.
* @override
* @method serializeAttribute
* @param {Snapshot} snapshot
* @param {Object} json
* @param {String} key
* @param {Object} attribute
*/
serializeAttribute(snapshot, json, key, attribute) {
const { type, options } = attribute;
let value = super.serializeAttribute(...arguments);
// Convert empty string to null.
if (type === 'string' && json[key] === '') json[key] = null;
// Do not serialize read-only attributes.
if (options.readOnly) delete json[key];
// Version is sent only if it has a non-nullish value
if (key === 'version') {
if (json[key] === null || json[key] === undefined) delete json[key];
}
return value;
}
}
@@ -0,0 +1,3 @@
import ApplicationSerializer from './application';
export default class ManagedGroupSerializer extends ApplicationSerializer {}
@@ -0,0 +1 @@
export { default } from 'api/models/fragment-managed-group-attributes';
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/models/managed-group';
@@ -0,0 +1 @@
export { default } from 'api/serializers/fragment-managed-group-attributes';
+9 -1
View File
@@ -8,7 +8,7 @@ import makeBooleanFilter from './helpers/bexpr-filter';
const isTesting = config.environment === 'test';
export default function () {
initializeMockIPC(this);
initializeMockIPC(this, config);
// make this `http://localhost:8080`, for example, if your API is on a different server
// this.urlPrefix = '';
@@ -514,6 +514,14 @@ export default function () {
this.del('/credential-libraries/:id');
this.patch('/credential-libraries/:id');
// managed-groups
this.get(
'/managed-groups',
({ managedGroups }, { queryParams: { auth_method_id: authMethodId } }) => {
return managedGroups.where({ authMethodId });
}
);
/* Uncomment the following line and the Response import above
* Then change the response code to simulate error responses.
* this.get('/scopes', () => new Response(505));
+5 -2
View File
@@ -23,15 +23,18 @@ export default factory.extend({
type: (i) => types[i % types.length],
/**
* Adds accounts (with associated users) to auth method.
* Adds accounts (with associated users) to auth method and managed groups.
*/
withAccountsAndUsers: trait({
withAccountsAndUsersAndManagedGroups: trait({
afterCreate(authMethod, server) {
const { scope, type } = authMethod;
server.createList('user', 5, { scope }).map((user) => {
const { id } = server.create('account', { scope, type, authMethod });
user.update({ accountIds: [id] });
});
server.createList('managed-group', 2, { scope, authMethod });
},
}),
});
@@ -0,0 +1,14 @@
import factory from '../generated/factories/managed-group';
import permissions from '../helpers/permissions';
export default factory.extend({
id: (i) => `managed-groups-id-${i}`,
authorized_actions: () =>
permissions.authorizedActionsFor('managed-group') || [
'no-op',
'read',
'update',
'delete',
],
});
@@ -0,0 +1,25 @@
import { Factory } from 'ember-cli-mirage';
import { random, date, datatype } from 'faker';
/**
* GeneratedManagedGroupFactory
* A managed group is a resource that represents a collection of accounts.
*/
export default Factory.extend({
name: () => random.words(),
description: () => random.words(),
created_time: () => date.recent(),
updated_time: () => date.recent(),
version: () => datatype.number(),
type: 'oidc',
attributes: function () {
switch (this.type) {
case 'oidc':
return {
filter: random.words(),
};
default:
return;
}
},
});
@@ -0,0 +1,6 @@
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
authMethod: belongsTo(),
});
+2 -2
View File
@@ -24,13 +24,13 @@ export default function (server) {
'auth-method',
1,
{ scope: globalScope },
'withAccountsAndUsers'
'withAccountsAndUsersAndManagedGroups'
);
const orgAuthMethods = server.createList(
'auth-method',
3,
{ scope: orgScope },
'withAccountsAndUsers'
'withAccountsAndUsersAndManagedGroups'
);
// Assign primary auth methods per scope
// TODO make this generic
+2 -3
View File
@@ -1,9 +1,8 @@
import config from 'ember-get-config';
import { datatype } from 'faker';
const isTesting = config.environment === 'test';
export default function initializeMockIPC(server, config) {
const isTesting = config.environment === 'test';
export default function initializeMockIPC(server) {
/**
* We strive to make this application runnable in a regular web browser, since
* it is a convenient environment for development and testing. But only an
@@ -0,0 +1,14 @@
import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
modelName: 'managed-group',
_hashForModel(model) {
const json = ApplicationSerializer.prototype._hashForModel.apply(
this,
arguments
);
json.auth_method_id = model.authMethodId;
return json;
},
});
-1
View File
@@ -51,7 +51,6 @@
"ember-copy": "^2.0.1",
"ember-disable-prototype-extensions": "^1.1.3",
"ember-export-application-global": "^2.0.1",
"ember-get-config": "^0.3.0",
"ember-load-initializers": "^2.1.2",
"ember-maybe-import-regenerator": "^1.0.0",
"ember-page-title": "^6.2.2",
-7
View File
@@ -6,13 +6,6 @@ const browsers = [
'last 1 Safari versions',
];
const isCI = Boolean(process.env.CI);
const isProduction = process.env.EMBER_ENV === 'production';
if (isCI || isProduction) {
browsers.push('ie 11');
}
module.exports = {
browsers,
};
@@ -1,6 +1,5 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import config from 'ember-get-config';
import RESTAdapter from '@ember-data/adapter/rest';
import { InvalidError } from '@ember-data/adapter/error';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
@@ -10,6 +9,12 @@ module('Unit | Adapter | application', function (hooks) {
setupTest(hooks);
setupMirage(hooks);
let config;
hooks.beforeEach(function () {
config = this.owner.resolveRegistration('config:environment');
});
test('its namespace is equal to the configured namespace', function (assert) {
assert.expect(2);
const adapter = this.owner.lookup('adapter:application');
@@ -0,0 +1,13 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Model | fragment managed group attributes', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('fragment-managed-group-attributes', {});
assert.ok(model);
});
});
@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Model | managed group', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('managed-group', {});
assert.ok(model);
});
});
@@ -0,0 +1,21 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Serializer | fragment managed groups attributes',
function (hooks) {
setupTest(hooks);
test('it serializes empty string to null', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const record = store.createRecord('fragment-managed-group-attributes', {
filter: '',
});
const serializedRecord = record.serialize();
assert.deepEqual(serializedRecord, {
filter: null,
});
});
}
);
@@ -0,0 +1,161 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Serializer | Managed group', function (hooks) {
setupTest(hooks);
test('it serializes correctly on create with no filter provided', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('managed-group');
const record = store.createRecord('managed-group', {
name: 'Group',
description: 'Description',
member_ids: ['1', '2'],
version: 1,
auth_method_id: '1234',
});
const snapshot = record._createSnapshot();
snapshot.adapterOptions = {};
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
name: 'Group',
description: 'Description',
version: 1,
auth_method_id: '1234',
type: null,
attributes: {
filter: null,
},
});
});
test('it serializes correctly on create when filter provided', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('managed-group');
const record = store.createRecord('managed-group', {
name: 'Group',
description: 'Description',
member_ids: ['1', '2'],
version: 1,
auth_method_id: '1234',
type: 'oidc',
attributes: {
filter: 'key=value',
},
});
const snapshot = record._createSnapshot();
snapshot.adapterOptions = {};
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
name: 'Group',
description: 'Description',
version: 1,
auth_method_id: '1234',
type: 'oidc',
attributes: {
filter: 'key=value',
},
});
});
test('it does not serialize version when it has null or undefined value', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('managed-group');
store.push({
data: {
id: '1',
type: 'managed-group',
attributes: {
name: 'Group Test',
description: 'Description for the test',
member_ids: ['1', '2'],
version: undefined,
auth_method_id: '1234',
type: 'oidc',
attributes: {
filter: 'key=value',
},
},
},
});
const record = store.peekRecord('managed-group', '1');
const snapshot = record._createSnapshot();
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
name: 'Group Test',
description: 'Description for the test',
auth_method_id: '1234',
type: 'oidc',
attributes: {
filter: 'key=value',
},
});
});
test('it does not serialize readOnly attributes', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('managed-group');
const record = store.createRecord('managed-group', {
name: 'Group',
description: 'Description',
version: 1,
auth_method_id: '1234',
member_ids: ['1', '2'],
created_time: Date.now(),
updated_time: Date.now(),
});
const snapshot = record._createSnapshot();
snapshot.adapterOptions = {};
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
name: 'Group',
description: 'Description',
version: 1,
auth_method_id: '1234',
type: null,
attributes: {
filter: null,
},
});
});
test('it serializes correctly on update', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('managed-group');
store.push({
data: {
id: '1',
type: 'managed-group',
attributes: {
name: 'Group Test',
description: 'Description for the test',
member_ids: ['1', '2'],
version: 1,
auth_method_id: '1234',
type: 'oidc',
attributes: {
filter: 'key=value',
},
},
},
});
const record = store.peekRecord('managed-group', '1');
const snapshot = record._createSnapshot();
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
name: 'Group Test',
description: 'Description for the test',
version: 1,
auth_method_id: '1234',
type: 'oidc',
attributes: {
filter: 'key=value',
},
});
});
});