Merge pull request #180 from hashicorp/ICU-580-account-model

Add account model
This commit is contained in:
Randall Morey authored and GitHub committed 2020-09-16 08:25:29 -04:00
commit d0eb164d58
17 files changed
+325 -2

No files matched your search

@@ -0,0 +1,46 @@
import BaseModel from '../../models/base';
import { attr } from '@ember-data/model';
/**
* Account contains all fields related to an account resource
*/
export default class GeneratedAccountModel extends BaseModel {
// =attributes
@attr('string', {
description: 'The type of the resource, to help differentiate schemas'
}) type;
@attr('string', {
description: 'The owning auth method ID.',
}) auth_method_id;
@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\nOutput only.',
readOnly: true,
})
created_time;
@attr('date', {
description: 'The time this resource was last updated\nOutput only.',
readOnly: true,
})
updated_time;
@attr('number', {
description: 'Current version number of this resource.',
})
version;
}
+36
View File
@@ -0,0 +1,36 @@
import GeneratedAccountModel from '../generated/models/account';
import { fragment } from 'ember-data-model-fragments/attributes';
export default class AccountModel extends GeneratedAccountModel {
/**
* Attributes of this resource, if any, represented as a JSON fragment.
* @type {FragmentAccountAttributesModel}
*/
@fragment('fragment-account-attributes', { defaultValue: {} }) attributes;
// =methods
/**
* Save account password via the `set-password` method.
* See serializer and adapter for more information.
* @param {string} password
* @param {object} options
* @param {object} options.adapterOptions
* @return {Promise}
*/
setPassword(password, options={ adapterOptions: {} }) {
const defaultAdapterOptions = {
method: 'set-password',
password
};
return this.save({
...options,
adapterOptions: {
...defaultAdapterOptions,
...options.adapterOptions
}
});
}
}
@@ -0,0 +1,10 @@
import Fragment from 'ember-data-model-fragments/fragment';
import { attr } from '@ember-data/model';
export default class FragmentAccountAttributesModel extends Fragment {
@attr('string', {
description: 'The account login name'
}) login_name;
}
@@ -6,4 +6,5 @@ export default class FragmentHostAttributesModel extends Fragment {
@attr('string', {
description: 'The address (DNS or IP name) used to reach the host'
}) address;
}
+39
View File
@@ -0,0 +1,39 @@
import ApplicationSerializer from './application';
export default class AccountSerializer extends ApplicationSerializer {
// =methods
/**
* If `adapterOptions.method` is `set-password`, the serialization should
* include only **password** and the version.
* If `adapterOptions.password` is set, the serialization should
* include **password** in it's `attributes`.
* @override
* @param {Snapshot} snapshot
* @return {object}
*/
serialize(snapshot) {
const password = snapshot?.adapterOptions?.password;
let serialized = super.serialize(...arguments);
if (password && snapshot?.record?.isNew) serialized.attributes.password = password;
if (snapshot?.adapterOptions?.method === 'set-password') {
serialized = this.serializeForSetPassword(snapshot, password);
}
return serialized;
}
/**
* Returns a payload containing only new password.
* @param {Snapshot} snapshot
* @param {string} password
* @return {object}
*/
serializeForSetPassword(snapshot, password) {
return {
version: snapshot.attr('version'),
password,
};
}
}
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/models/account';
@@ -0,0 +1 @@
export { default } from 'api/models/fragment-account-attributes';
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/serializers/account';
@@ -0,0 +1,13 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Model | account', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('account', {});
assert.ok(model);
});
});
@@ -0,0 +1,97 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Serializer | account', function(hooks) {
setupTest(hooks);
test('it serializes normally', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('account');
const record = store.createRecord('account', {
type: 'password',
name: 'Name',
auth_method_id: '1',
description: 'Description',
attributes: {
login_name: 'Login Name',
},
version: 1
});
const snapshot = record._createSnapshot();
snapshot.adapterOptions = {};
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
type: 'password',
name: 'Name',
auth_method_id: '1',
description: 'Description',
attributes: {
login_name: 'Login Name'
},
version: 1
});
});
test('it serializes password attribute when `adapterOptions.password` is true', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('account');
const record = store.createRecord('account', {
type: 'password',
name: 'Name',
auth_method_id: '1',
description: 'Description',
attributes: {
login_name: 'Login Name',
},
version: 1
});
const snapshot = record._createSnapshot();
snapshot.adapterOptions = {
password: 'Password'
};
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
type: 'password',
name: 'Name',
auth_method_id: '1',
description: 'Description',
attributes: {
login_name: 'Login Name',
password: 'Password'
},
version: 1
});
});
test('it does not serialize password for non-new records', function (assert) {
assert.expect(0);
});
test('it serializes only password when `adapterOptions.method` is set to `set-password`', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('account');
const record = store.createRecord('account', {
type: 'password',
name: 'Name',
description: 'Description',
attributes: {
login_name: 'Login Name'
},
auth_method_id: '1',
version: 1
});
const snapshot = record._createSnapshot();
snapshot.adapterOptions = {
method: 'set-password',
password: 'Password'
};
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
password: 'Password',
version: 1
});
});
});
+24
View File
@@ -49,6 +49,30 @@ export default function() {
this.patch('/auth-methods/:id');
this.del('/auth-methods/:id');
// Auth Method Accounts
this.get('/accounts', ({ accounts }, { queryParams: { auth_method_id: authMethodId } }) => {
return accounts.where({ authMethodId });
});
this.post('/accounts');
this.get('/accounts/:id');
this.patch('/accounts/:id');
this.del('/accounts/:id');
this.post('/accounts/:idMethod', function ({ accounts }, { params: { idMethod } }) {
const attrs = this.normalizedRequestAttrs();
const id = idMethod.split(':')[0];
const method = idMethod.split(':')[1];
const account = accounts.find(id);
const updatedAttrs = {
version: attrs.version,
attributes: account.attributes
};
// Set new password
if (method === 'set-password') {
updatedAttrs.attributes.password = attrs.password;
}
return account.update(updatedAttrs);
});
// Authenticate/deauthenticate routes
this.post('/auth-methods/:id_method', authHandler);
this.post('/scopes/:id_method', deauthHandler);
+3
View File
@@ -0,0 +1,3 @@
import factory from '../generated/factories/account';
export default factory.extend();
+15 -1
View File
@@ -1,3 +1,17 @@
import factory from '../generated/factories/auth-method';
import { trait } from 'ember-cli-mirage';
export default factory.extend();
export default factory.extend({
id: (i) => `auth-method-id-${i}`,
/**
* Adds accounts to auth method.
*/
withAccounts: trait({
afterCreate(authMethod, server) {
const { scope } = authMethod;
server.createList('account', 5, { scope, authMethod });
}
})
});
@@ -0,0 +1,17 @@
import { Factory } from 'ember-cli-mirage';
import { random, date } from 'faker';
/**
* GeneratedAccountFactory
*/
export default Factory.extend({
type: 'password',
name: () => random.words(),
description: () => random.words(),
created_time: () => date.recent(),
updated_time: () => date.recent(),
version: () => random.number(),
attributes: () => ({ login_name: random.words() }),
});
+8
View File
@@ -0,0 +1,8 @@
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
authMethod: belongsTo()
});
+1 -1
View File
@@ -15,7 +15,7 @@ export default function(server) {
// Auth
server.createList('auth-method', 3, { scope: globalScope });
server.createList('auth-method', 3, { scope: orgScope });
server.createList('auth-method', 3, { scope: orgScope }, 'withAccounts');
// Groups and Users
server.createList('group', 5, { scope: orgScope }, 'withMembers');
+12
View File
@@ -0,0 +1,12 @@
import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
modelName: 'account',
_hashForModel(model) {
const json = ApplicationSerializer.prototype._hashForModel.apply(this, arguments);
json.auth_method_id = model.authMethodId;
delete json.attributes?.password;
return json;
}
});