Merge branch 'main' into filterable-store-api-addon
This commit is contained in:
63 files changed
+739
-796
No files matched your search
@@ -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;
|
||||
}
|
||||
@@ -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';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'api/models/managed-group';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'api/serializers/fragment-managed-group-attributes';
|
||||
@@ -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));
|
||||
|
||||
@@ -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(),
|
||||
});
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
});
|
||||
@@ -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",
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user