refactor: 💡 implement new pathing for users

This commit is contained in:
Randall Morey committed 2020-09-09 16:53:41 -04:00
1 parent e80708eeb4
commit 4a63c6484f
17 files changed
+154 -78

No files matched your search

+13
View File
@@ -0,0 +1,13 @@
import ApplicationAdapter from './application';
export default class UserAdapter extends ApplicationAdapter {
// =attributes
/**
* Users use the new, unprefixed pathing style.
* @override
*/
hasScopePrefix = false;
}
+13
View File
@@ -0,0 +1,13 @@
import ApplicationSerializer from './application';
export default class UserSerializer extends ApplicationSerializer {
// =attributes
/**
* Serialized the scope ID into the `scope_id` field.
* @type {boolean}
*/
serializeScopeID = true;
}
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/adapters/user';
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/serializers/user';
@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Adapter | user', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let adapter = this.owner.lookup('adapter:user');
assert.ok(adapter);
});
});
+7 -7
View File
@@ -97,17 +97,17 @@ module('Unit | Model | base', function (hooks) {
assert.expect(3);
const store = this.owner.lookup('service:store');
const model = store.createRecord('user', { scopeID: 'o_123' });
this.server.post('/v1/scopes/o_123/users', () => {
this.server.post('/v1/users', () => {
assert.ok(true, 'Correctly scoped create record URL was requested.')
return {};
});
await model.save();
this.server.patch('/v1/scopes/o_123/users', () => {
this.server.patch('/v1/users', () => {
assert.ok(true, 'Correctly scoped update record URL was requested.')
return {};
});
await model.save();
this.server.delete('/v1/scopes/o_123/users', () => {
this.server.delete('/v1/users', () => {
assert.ok(true, 'Correctly scoped delete record URL was requested.')
return {};
});
@@ -120,17 +120,17 @@ module('Unit | Model | base', function (hooks) {
const customScopeID = 'global';
const scope = {scope_id: 'o_123'};
const model = store.createRecord('user', { scope });
this.server.post('/v1/scopes/global/users', () => {
this.server.post('/v1/users', () => {
assert.ok(true, 'Correctly scoped create record URL was requested.')
return {};
});
await model.save({adapterOptions: {scopeID: customScopeID}});
this.server.patch('/v1/scopes/global/users', () => {
this.server.patch('/v1/users', () => {
assert.ok(true, 'Correctly scoped update record URL was requested.')
return {};
});
await model.save({adapterOptions: {scopeID: customScopeID}});
this.server.delete('/v1/scopes/global/users', () => {
this.server.delete('/v1/users', () => {
assert.ok(true, 'Correctly scoped delete record URL was requested.')
return {};
});
@@ -143,7 +143,7 @@ module('Unit | Model | base', function (hooks) {
const method = 'my-custom-method';
const scope = {scope_id: 'o_123'};
const model = store.createRecord('user', { scope });
this.server.post(`/v1/scopes/o_123/users:${method}`, () => {
this.server.post(`/v1/users:${method}`, () => {
assert.ok(true, 'Correctly scoped create record URL was requested.')
return {};
});
@@ -25,7 +25,8 @@ module('Unit | Serializer | application', function (hooks) {
const serializedRecord = record.serialize();
assert.deepEqual(serializedRecord, {
name: 'User',
description: 'Description'
description: 'Description',
scope_id: 'global'
});
});
@@ -33,6 +34,7 @@ module('Unit | Serializer | application', function (hooks) {
assert.expect(2);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('user');
serializer.serializeScopeID = false;
const record = store.createRecord('user', {
name: 'User',
description: 'Description',
@@ -0,0 +1,23 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Serializer | user', 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('user');
assert.ok(serializer);
});
test('it serializes records', function(assert) {
let store = this.owner.lookup('service:store');
let record = store.createRecord('user', {});
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});
});
@@ -24,10 +24,11 @@ export default class ScopesScopeGroupsGroupAddMembersRoute extends Route {
* @return {Promise{GroupModel, [UserModel]}}
*/
model() {
const { id: scopeID } = this.modelFor('scopes.scope');
const group = this.modelFor('scopes.scope.groups.group');
const { scopeID: scope_id } = group;
return hash({
group: this.modelFor('scopes.scope.groups.group'),
users: this.store.findAll('user', { adapterOptions: { scopeID } })
users: this.store.query('user', { scope_id })
});
}
@@ -12,27 +12,17 @@ export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
// =methods
/**
* Empty out any previously loaded users and groups.
* (collectively, principals).
*/
beforeModel() {
this.store.unloadAll('user');
//this.store.unloadAll('group');
}
/**
* Returns the current role, all users, and all groups
* @return {{role: RoleModel, users: [UserModel], groups: [GroupModel]}}
*/
model() {
const role = this.modelFor('scopes.scope.roles.role');
const { scopeID } = role;
const options = { adapterOptions: { scopeID } };
const { scopeID: scope_id } = role;
return hash({
role,
users: this.store.findAll('user', options),
groups: this.store.query('group', { scope_id: scopeID })
users: this.store.query('user', { scope_id }),
groups: this.store.query('group', { scope_id })
});
}
+2 -2
View File
@@ -23,8 +23,8 @@ export default class ScopesScopeUsersRoute extends Route {
* @return {Promise{[UserModel]}}
*/
async model() {
const { id: scopeID } = this.modelFor('scopes.scope');
return this.store.findAll('user', { adapterOptions: { scopeID } });
const { id: scope_id } = this.modelFor('scopes.scope');
return this.store.query('user', { scope_id });
}
// =actions
@@ -10,9 +10,6 @@ export default class ScopesScopeUsersUserRoute extends Route {
* @return {UserModel}
*/
async model({ user_id }) {
const { id: scopeID } = this.modelFor('scopes.scope');
return this.store.findRecord('user', user_id, {
adapterOptions: { scopeID },
});
return this.store.findRecord('user', user_id);
}
}
+41 -39
View File
@@ -54,11 +54,47 @@ export default function() {
this.post('/scopes/:id_method', deauthHandler);
// IAM : Users
this.get('/scopes/:scope_id/users');
this.post('/scopes/:scope_id/users');
this.get('/scopes/:scope_id/users/:id');
this.patch('/scopes/:scope_id/users/:id');
this.del('/scopes/:scope_id/users/:id');
this.get('/users', ({ users }, { queryParams: { scope_id: scopeId } }) => {
return users.where({ scopeId });
});
this.post('/users');
this.get('/users/:id');
this.patch('/users/:id');
this.del('/users/:id');
// IAM: Groups
this.get('/groups', ({ groups }, { queryParams: { scope_id: scopeId } }) => {
return groups.where({ scopeId });
});
this.post('/groups');
this.get('/groups/:id');
this.patch('/groups/:id');
this.del('/groups/:id');
this.post('/groups/:idMethod', function ({ groups }, { params: { idMethod } }) {
const attrs = this.normalizedRequestAttrs();
const id = idMethod.split(':')[0];
const method = idMethod.split(':')[1];
const group = groups.find(id);
const updatedAttrs = {
version: attrs.version,
memberIds: group.memberIds
};
// If adding members, push them into the array
if (method === 'add-members') {
attrs.memberIds.forEach(id => {
if (!updatedAttrs.memberIds.includes(id)) {
updatedAttrs.memberIds.push(id);
}
});
}
// If deleting members, filter them out of the array
if (method === 'remove-members') {
updatedAttrs.memberIds = updatedAttrs.memberIds.filter(id => {
return !attrs.memberIds.includes(id);
});
}
return group.update(updatedAttrs);
});
// IAM: Roles
this.get('/scopes/:scope_id/roles');
@@ -106,40 +142,6 @@ export default function() {
return role.update(updatedAttrs);
});
// IAM: Groups
this.get('/groups', ({ groups }, { queryParams: { scope_id: scopeId } }) => {
return groups.where({ scopeId });
});
this.post('/groups');
this.get('/groups/:id');
this.patch('/groups/:id');
this.del('/groups/:id');
this.post('/groups/:idMethod', function ({ groups }, { params: { idMethod } }) {
const attrs = this.normalizedRequestAttrs();
const id = idMethod.split(':')[0];
const method = idMethod.split(':')[1];
const group = groups.find(id);
const updatedAttrs = {
version: attrs.version,
memberIds: group.memberIds
};
// If adding members, push them into the array
if (method === 'add-members') {
attrs.memberIds.forEach(id => {
if (!updatedAttrs.memberIds.includes(id)) {
updatedAttrs.memberIds.push(id);
}
});
}
// If deleting members, filter them out of the array
if (method === 'remove-members') {
updatedAttrs.memberIds = updatedAttrs.memberIds.filter(id => {
return !attrs.memberIds.includes(id);
});
}
return group.update(updatedAttrs);
});
// Other resources
// host-catalog
+7
View File
@@ -0,0 +1,7 @@
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo()
});
+18 -1
View File
@@ -1,5 +1,22 @@
import ApplicationSerializer from './application';
import { underscore } from '@ember/string';
export default ApplicationSerializer.extend({
modelName: 'user'
modelName: 'user',
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;
}
});
@@ -42,7 +42,7 @@ module('Acceptance | breadcrumbs', function (hooks) {
this.server.schema.scopes.where({ type: 'project' }).models[0];
project = getProjectScope();
user = this.server.create('user');
user = this.server.create('user', { scope: orgScope });
role = this.server.create('role');
group = this.server.create('group', { scope: orgScope });
hostCatalog = this.server.create('host-catalog', {
+5 -8
View File
@@ -30,10 +30,7 @@ module('Acceptance | users', function (hooks) {
);
const user = this.server.create('user', {
scope: {
id: orgScope.id,
type: orgScope.type,
},
scope: orgScope
});
usersURL = `/scopes/${orgScope.id}/users`;
@@ -78,7 +75,7 @@ module('Acceptance | users', function (hooks) {
test('saving a new user with invalid fields displays error messages', async function (assert) {
assert.expect(2);
this.server.post('scopes/:scope_id/users', () => {
this.server.post('/users', () => {
return new Response(
400,
{},
@@ -139,7 +136,7 @@ module('Acceptance | users', function (hooks) {
test('saving an existing user with invalid fields displays error messages', async function (assert) {
assert.expect(2);
this.server.patch('/scopes/:scope_id/users/:id', () => {
this.server.patch('/users/:id', () => {
return new Response(
400,
{},
@@ -175,7 +172,7 @@ module('Acceptance | users', function (hooks) {
test('errors are displayed when saving user fails', async function (assert) {
assert.expect(1);
this.server.patch('/scopes/:scope_id/users/:id', () => {
this.server.patch('/users/:id', () => {
return new Response(
490,
{},
@@ -198,7 +195,7 @@ module('Acceptance | users', function (hooks) {
test('errors are displayed when user deletion fails', async function (assert) {
assert.expect(1);
this.server.del('/scopes/:scope_id/users/:id', () => {
this.server.del('/users/:id', () => {
return new Response(
490,
{},