feat: reapply storage policies to session recording (#2095)
* refactor: 💡 add global settings link ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12257 * fix: 🐛 route ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12257 * fix: 🐛 comment ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12257 * feat: 🎸 add reapply sp to session recording page * fix: 🐛 normalize * feat: 🎸 upates * fix: 🐛 logs * fix: 🐛 comment * test: 💍 add tests * fix: 🐛 normalizer, style * fix: 🐛 normalize * fix: 🐛 normalizw * fix: 🐛 normalize * test: 💍 add tests for serializer n normalizer * fix: 🐛 name * fix: 🐛 do not delete, send null * fix: 🐛 return --------- Co-authored-by: Lisbet Alvarez <lisbet.alvarez@hashicorp.com>
This commit is contained in:
1 parent
9e0467cbf0
commit
fb9a080d2e
19 files changed
+314
-3
No files matched your search
@@ -24,4 +24,11 @@ export default class SessionRecordingAbility extends ModelAbility {
|
||||
get canDownload() {
|
||||
return this.hasAuthorizedAction('download');
|
||||
}
|
||||
|
||||
/* Permission that checks whether a policy can be reapplied to a session recording
|
||||
* @type {boolean}
|
||||
*/
|
||||
get canReapplyStoragePolicy() {
|
||||
return this.hasAuthorizedAction('reapply-storage-policy');
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export default class GeneratedChannelRecordingModel extends BaseModel {
|
||||
'The total number of errors that occurred during the use of this Channel.',
|
||||
readOnly: true,
|
||||
})
|
||||
errors;
|
||||
errors_number;
|
||||
|
||||
@attr('date', {
|
||||
description: 'The time the Channel started.',
|
||||
|
||||
@@ -38,7 +38,7 @@ export default class GeneratedConnectionRecordingModel extends BaseModel {
|
||||
'The total number of errors that occurred during the use of this Connection.',
|
||||
readOnly: true,
|
||||
})
|
||||
errors;
|
||||
errors_number;
|
||||
|
||||
@attr('date', {
|
||||
description: 'The time the Connection started.',
|
||||
|
||||
@@ -70,7 +70,7 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
|
||||
'The total number of errors that occurred during the use of the Session.',
|
||||
readOnly: true,
|
||||
})
|
||||
errors;
|
||||
errors_number;
|
||||
|
||||
@attr('date', {
|
||||
description: 'The time the Session started.',
|
||||
@@ -109,4 +109,15 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
|
||||
readOnly: true,
|
||||
})
|
||||
error_details;
|
||||
|
||||
@attr('date', {
|
||||
description: 'The time until a session recording is required to be stored.',
|
||||
})
|
||||
retain_until;
|
||||
|
||||
@attr('date', {
|
||||
description:
|
||||
'The time a session recording is scheduled to be automatically deleted.',
|
||||
})
|
||||
delete_after;
|
||||
}
|
||||
@@ -69,4 +69,23 @@ export default class SessionRecordingModel extends GeneratedSessionRecordingMode
|
||||
this.create_time_values?.user?.name || this.create_time_values?.user?.id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reapply policy dates via the `reapply-staorage-policy` method.
|
||||
* @param {object} options
|
||||
* @param {object} options.adapterOptions
|
||||
* @return {Promise}
|
||||
*/
|
||||
reapplyStoragePolicy(options = { adapterOptions: {} }) {
|
||||
const defaultAdapterOptions = {
|
||||
method: 'reapply-storage-policy',
|
||||
};
|
||||
return this.save({
|
||||
...options,
|
||||
adapterOptions: {
|
||||
...defaultAdapterOptions,
|
||||
...options.adapterOptions,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
||||
|
||||
export default class ChannelSerializer extends ApplicationSerializer.extend(
|
||||
EmbeddedRecordsMixin,
|
||||
) {
|
||||
normalize(typeClass, hash, ...rest) {
|
||||
const normalizedHash = structuredClone(hash);
|
||||
const err = normalizedHash.errors;
|
||||
delete normalizedHash.errors;
|
||||
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
|
||||
// we should not override the ember models errors field,
|
||||
// so we rename the errors field from the api
|
||||
normalized.data.attributes.errors_number = err;
|
||||
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
@@ -12,4 +12,16 @@ export default class ConnectionSerializer extends ApplicationSerializer.extend(
|
||||
attrs = {
|
||||
channel_recordings: { embedded: 'always' },
|
||||
};
|
||||
|
||||
normalize(typeClass, hash, ...rest) {
|
||||
const normalizedHash = structuredClone(hash);
|
||||
const err = normalizedHash.errors;
|
||||
delete normalizedHash.errors;
|
||||
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
|
||||
// we should not override the ember models errors field,
|
||||
// so we rename the errors field from the api
|
||||
normalized.data.attributes.errors_number = err;
|
||||
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
@@ -11,4 +11,26 @@ export default class RecordingSerializer extends ApplicationSerializer.extend(
|
||||
attrs = {
|
||||
connection_recordings: { embedded: 'always' },
|
||||
};
|
||||
|
||||
serialize(snapshot) {
|
||||
let serialized = super.serialize(...arguments);
|
||||
// The post request for reapply-storage-policy doesn't expect a payload,
|
||||
// so we return nothing
|
||||
if (snapshot?.adapterOptions?.method === 'reapply-storage-policy') {
|
||||
return {};
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
|
||||
normalize(typeClass, hash, ...rest) {
|
||||
const normalizedHash = structuredClone(hash);
|
||||
const err = normalizedHash.errors;
|
||||
delete normalizedHash.errors;
|
||||
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
|
||||
// we should not override the ember models errors field,
|
||||
// so we rename the errors field from the api
|
||||
normalized.data.attributes.errors_number = err;
|
||||
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
export { default } from 'api/serializers/channel-recording';
|
||||
@@ -780,6 +780,24 @@ function routes() {
|
||||
},
|
||||
);
|
||||
|
||||
this.post(
|
||||
'/session-recordings/:idMethod',
|
||||
function ({ sessionRecordings }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const record = sessionRecordings.find(id);
|
||||
const updatedAttrs = {
|
||||
version: attrs.version,
|
||||
};
|
||||
if (method === 'reapply-storage-policy') {
|
||||
updatedAttrs.retain_until = faker.date.recent();
|
||||
updatedAttrs.delete_after = faker.date.recent();
|
||||
}
|
||||
return record.update(updatedAttrs);
|
||||
},
|
||||
);
|
||||
|
||||
/* Uncomment the following line and the Response import above
|
||||
* Then change the response code to simulate error responses.
|
||||
* this.get('/scopes', () => new Response(505));
|
||||
|
||||
@@ -43,11 +43,23 @@ export default factory.extend({
|
||||
: null;
|
||||
},
|
||||
|
||||
retain_until() {
|
||||
return this.state === STATE_SESSION_RECORDING_AVAILABLE
|
||||
? faker.date.recent()
|
||||
: null;
|
||||
},
|
||||
delete_after() {
|
||||
return this.state === STATE_SESSION_RECORDING_AVAILABLE
|
||||
? faker.date.recent()
|
||||
: null;
|
||||
},
|
||||
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('session-recording') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'download',
|
||||
'reapply-storage-policy',
|
||||
],
|
||||
|
||||
withNonExistingUserAndTarget: trait({
|
||||
|
||||
@@ -25,4 +25,45 @@ module('Unit | Serializer | session-recording', function (hooks) {
|
||||
|
||||
assert.ok(serializedRecord);
|
||||
});
|
||||
|
||||
test('it serializes only version when `adapterOptions.method` is `reapply-storage-policy`', function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('session-recording');
|
||||
const record = store.createRecord('session-recording', {
|
||||
version: 1,
|
||||
retain_until: 1,
|
||||
delete_after: 2,
|
||||
});
|
||||
const snapshot = record._createSnapshot();
|
||||
snapshot.adapterOptions = {
|
||||
method: 'reapply-storage-policy',
|
||||
};
|
||||
const serializedRecord = serializer.serialize(snapshot);
|
||||
assert.deepEqual(serializedRecord, {});
|
||||
});
|
||||
|
||||
test('it normalizes correctly', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('session-recording');
|
||||
|
||||
let record = store.createRecord('session-recording').constructor;
|
||||
const payload = {
|
||||
id: '1',
|
||||
type: 'session-recording',
|
||||
errors: 2,
|
||||
};
|
||||
const normalized = serializer.normalize(record, payload);
|
||||
|
||||
assert.deepEqual(normalized, {
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'session-recording',
|
||||
attributes: {
|
||||
errors_number: 2,
|
||||
type: 'session-recording',
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user