new model things for secret-v2 and secret-v2 versions: get list, queryRecord, and version find working

This commit is contained in:
Matthew Irish 2018-10-03 23:32:55 -05:00
parent ce5a373137
commit a8302b47e0
7 changed files with 142 additions and 25 deletions

View File

@ -0,0 +1,23 @@
import { isEmpty } from '@ember/utils';
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
namespace: 'v1',
_url(backend, id) {
let url = `${this.buildURL()}/${backend}/data/`;
if (!isEmpty(id)) {
url = url + id;
}
return url;
},
urlForFindRecord(id) {
let [backend, path, version] = JSON.parse(id);
return this._url(backend, path) + `?version=${version}`;
},
deleteRecord(store, type, snapshot) {
// use adapterOptions to determine if it's delete or destroy for the version
return this._super(...arguments);
},
});

View File

@ -1,34 +1,41 @@
/* eslint-disable */
import { isEmpty } from '@ember/utils';
import SecretAdapter from './secret';
import ApplicationAdapter from './application';
export default SecretAdapter.extend({
createOrUpdate(store, type, snapshot) {
const serializer = store.serializerFor(type.modelName);
const data = serializer.serialize(snapshot);
const { id } = snapshot;
return this.ajax(this.urlForSecret(snapshot.attr('backend'), id), 'POST', {
data: { data },
});
},
urlForSecret(backend, id, infix = 'data') {
let url = `${this.buildURL()}/${backend}/${infix}/`;
export default ApplicationAdapter.extend({
namespace: 'v1',
_url(backend, id) {
let url = `${this.buildURL()}/${backend}/metadata/`;
if (!isEmpty(id)) {
url = url + id;
}
return url;
},
fetchByQuery(query, methodCall) {
// we override query here because the query object has a bunch of client-side
// concerns and we only want to send "list" to the server
query(store, type, query) {
let { backend, id } = query;
return this.ajax(this._url(backend, id), 'GET', { data: { list: true } });
},
urlForQueryRecord(query) {
let { id, backend } = query;
let args = [backend, id];
if (methodCall === 'query') {
args.push('metadata');
}
return this.ajax(this.urlForSecret(...args), 'GET', this.optionsForQuery(id, methodCall)).then(resp => {
return this._url(backend) + id;
},
queryRecord(store, type, query) {
let { backend, id } = query;
return this._super(...arguments).then(resp => {
resp.id = id;
resp.backend = backend;
return resp;
});
},
urlForDeleteRecord(store, type, snapshot) {
let backend = snapshot.belongsTo('secret-engine', { id: true });
let { id } = snapshot;
return this.urlForQueryRecord({ id, backend });
},
});

View File

@ -0,0 +1,8 @@
import Secret from './secret';
import DS from 'ember-data';
const { attr } = DS;
export default Secret.extend({
version: attr('number'),
});

View File

@ -1,3 +1,15 @@
import Secret from './secret';
import DS from 'ember-data';
export default Secret.extend();
const { attr, hasMany, belongsTo, Model } = DS;
export default Model.extend({
engine: belongsTo('secret-engine'),
versions: hasMany('secret-v2-version', { async: false }),
createdTime: attr(),
updatedTime: attr(),
currentVersion: attr('number'),
oldestVersion: attr('number'),
maxVersions: attr('number'),
casRequired: attr('boolean'),
});

View File

@ -72,7 +72,14 @@ export default Route.extend(UnloadModelRoute, {
secret = secret.replace('cert/', '');
}
return hash({
secret: this.store.queryRecord(modelType, { id: secret, backend }),
secret: this.store.queryRecord(modelType, { id: secret, backend }).then(resp => {
if (modelType === 'secret-v2') {
// TODO, find by query param to enable viewing versions
let version = resp.versions.findBy('version', resp.currentVersion);
version.reload();
}
return resp;
}),
capabilities: this.capabilities(secret),
});
},

View File

@ -0,0 +1,25 @@
import { get } from '@ember/object';
import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
secretDataPath: 'data.data',
normalizeItems(payload, requestType) {
let path = this.secretDataPath;
// move response that is the contents of the secret from the dataPath
// to `secret_data` so it will be `secretData` in the model
payload.secret_data = get(payload, path);
payload = Object.assign({}, payload, payload.data.metadata);
delete payload.data;
// return the payload if it's expecting a single object or wrap
// it as an array if not
return payload;
},
serialize(snapshot) {
return {
data: snapshot.attr('secretData'),
options: {
cas: snapshot.attr('currentVerion'),
},
};
},
});

View File

@ -1,5 +1,40 @@
import SecretSerializer from './secret';
import ApplicationSerializer from './application';
import DS from 'ember-data';
export default SecretSerializer.extend({
secretDataPath: 'data.data',
export default ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
versions: { embedded: 'always' },
},
secretDataPath: 'data',
normalizeItems(payload, requestType) {
if (payload.data.keys && Array.isArray(payload.data.keys)) {
// if we have data.keys, it's a list of ids, so we map over that
// and create objects with id's
return payload.data.keys.map(secret => {
// secrets don't have an id in the response, so we need to concat the full
// path of the secret here - the id in the payload is added
// in the adapter after making the request
let fullSecretPath = payload.id ? payload.id + secret : secret;
// if there is no path, it's a "top level" secret, so add
// a unicode space for the id
// https://github.com/hashicorp/vault/issues/3348
if (!fullSecretPath) {
fullSecretPath = '\u0020';
}
return { id: fullSecretPath };
});
}
if (payload.data.versions) {
payload.data.versions = Object.keys(payload.data.versions).map(version => {
let body = payload.data.versions[version];
body.version = version;
body.id = JSON.stringify([payload.backend, payload.id, version]);
return body;
});
console.log(payload);
}
payload.data.id = payload.id;
return requestType === 'queryRecord' ? payload.data : [payload.data];
},
});