Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/definition/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import extractCollectionMember from './extract-collection-member.js';
import extractField from './extract-field.js';
import extractMember from './extract-member.js';
import {normaliseCreateActions, normaliseUpdateActions} from './normalise-actions.js';
import normaliseActionLayout from './normalise-action-layout.js';
import normaliseFields from './normalise-fields.js';
import {normaliseSearchInputsLayout, normaliseSearchResultsLayout} from './normalise-search-layout.js';
Expand All @@ -13,10 +14,12 @@ export {
extractField,
extractMember,
normaliseActionLayout,
normaliseCreateActions,
normaliseFields,
normaliseSearchInputsLayout,
normaliseSearchResultsLayout,
normaliseStates,
normaliseType,
normaliseUpdateActions,
normaliseViewLayout,
};
80 changes: 80 additions & 0 deletions src/definition/normalise-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import * as AclV2 from '../acl-v2.js';

const FROM_STATE_WILDCARD = '*';

export const normaliseCreateActions = (events) => Object.fromEntries(
events.filter(isCreateAction)
.map((event) => [event.id, normaliseCreate(event)])
);

export const normaliseUpdateActions = (events) => Object.fromEntries(
events.filter(isUpdateAction)
.map((event) => [event.id, normaliseUpdate(event)])
);

const isCreateAction = (event) => !event.pre_states?.length;

const isUpdateAction = (event) => event.pre_states?.length > 0;

const normaliseCreate = (event) => ({
id: event.id,
name: event.name,
description: orUndefined(event.description),
order: event.order,
toState: event.post_state,
postconditions: normalisePostconditions(event.postconditions),
acl: AclV2.fromLegacy(event.acls),
classification: event.security_classification,
webhooks: {
onStart: normaliseWebhook(event.callback_url_about_to_start_event, event.retries_timeout_about_to_start_event),
onSubmit: normaliseWebhook(event.callback_url_about_to_submit_event, event.retries_timeout_url_about_to_submit_event),
onSubmitted: normaliseWebhook(event.callback_url_submitted_event, event.retries_timeout_url_submitted_event),
},
});

const normaliseUpdate = (event) => ({
id: event.id,
name: event.name,
description: orUndefined(event.description),
order: event.order,
fromStates: normaliseFromStates(event.pre_states),
precondition: orUndefined(event.precondition),
toState: orUndefined(event.post_state),
postconditions: normalisePostconditions(event.postconditions),
acl: AclV2.fromLegacy(event.acls),
classification: event.security_classification,
webhooks: {
onStart: normaliseWebhook(event.callback_url_about_to_start_event, event.retries_timeout_about_to_start_event),
onSubmit: normaliseWebhook(event.callback_url_about_to_submit_event, event.retries_timeout_url_about_to_submit_event),
onSubmitted: normaliseWebhook(event.callback_url_submitted_event, event.retries_timeout_url_submitted_event),
},
});

const orUndefined = (value) => value ? value : undefined;

const normaliseFromStates = (fromStates) => {
if (fromStates.includes(FROM_STATE_WILDCARD)) return;

return fromStates;
}

/**
* Preserve postconditions as an ordered array in case postconditions application order becomes important in the future.
*/
const normalisePostconditions = (postconditions) => {
if (!postconditions?.length) return;

return postconditions.map(({field_id, value}) => ({
path: field_id,
value,
}));
};

const normaliseWebhook = (url, retries) => {
if (!url) return;

return {
url,
retries,
};
};
242 changes: 242 additions & 0 deletions src/definition/normalise-actions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
import * as AclV2 from '../acl-v2.js';
import {normaliseCreateActions, normaliseUpdateActions} from './normalise-actions.js';

const CR = AclV2.CREATE | AclV2.READ;

describe('normaliseCreateActions', () => {
const actions = [
{
id: 'action1',
name: 'Create action 1',
description: 'A first create action',
order: 1,
pre_states: [],
post_state: 'state1',
acls: [
{
role: 'caseworker-test-write',
create: true,
read: true,
},
{
role: 'caseworker-test-read',
create: false,
read: true,
}
],
security_classification: 'PUBLIC',
},
{
id: 'action2',
name: 'Create action 2',
description: null,
order: 2,
pre_states: [],
post_state: 'state2',
postconditions: [
{field_id: 'field1', value: 'value1'},
{field_id: 'field2', value: 'value2'},
],
acls: [
{
role: 'caseworker-test-write',
create: true,
read: false,
}
],
security_classification: 'PRIVATE',
callback_url_about_to_start_event: 'http://webhooks/start',
retries_timeout_about_to_start_event: [1,2,3],
callback_url_about_to_submit_event: 'http://webhooks/submit',
retries_timeout_url_about_to_submit_event: [4,5,6],
callback_url_submitted_event: 'http://webhooks/submitted',
retries_timeout_url_submitted_event: [7,8,9],
},
];

test('should return empty object when no actions', () => {
expect(normaliseCreateActions([])).toEqual({});
});

test('should transform array of events into object of normalised create actions', () => {
expect(normaliseCreateActions(actions)).toEqual({
'action1': {
id: 'action1',
name: 'Create action 1',
description: 'A first create action',
order: 1,
toState: 'state1',
acl: {
'caseworker-test-write': CR,
'caseworker-test-read': AclV2.READ,
},
classification: 'PUBLIC',
webhooks: {},
},
'action2': {
id: 'action2',
name: 'Create action 2',
order: 2,
toState: 'state2',
postconditions: [
{path: 'field1', value: 'value1'},
{path: 'field2', value: 'value2'},
],
acl: {
'caseworker-test-write': AclV2.CREATE,
},
classification: 'PRIVATE',
webhooks: {
onStart: {
url: 'http://webhooks/start',
retries: [1,2,3]
},
onSubmit: {
url: 'http://webhooks/submit',
retries: [4,5,6]
},
onSubmitted: {
url: 'http://webhooks/submitted',
retries: [7,8,9]
},
},
},
});
});

test('should filter out update actions', () => {
const createActions = normaliseCreateActions([
...actions,
{
id: 'updateAction1',
name: 'Update action',
pre_states: ['state1'],
acls: [],
}
]);

expect(createActions).not.toHaveProperty('updateAction1');
});
});

describe('normaliseUpdateActions', () => {
const actions = [
{
id: 'action1',
name: 'Update action 1',
description: 'A first update action',
order: 1,
pre_states: ['*'],
precondition: 'field1 EQUALS "value1"',
post_state: 'state1',
postconditions: [],
acls: [
{
role: 'caseworker-test-write',
create: true,
read: true,
},
{
role: 'caseworker-test-read',
create: false,
read: true,
}
],
security_classification: 'PUBLIC',
},
{
id: 'action2',
name: 'Update action 2',
description: null,
order: 2,
pre_states: ['state1', 'state3'],
precondition: null,
post_state: 'state2',
postconditions: [
{field_id: 'field1', value: 'value1'},
{field_id: 'field2', value: 'value2'},
],
acls: [
{
role: 'caseworker-test-write',
create: true,
read: false,
}
],
security_classification: 'PRIVATE',
callback_url_about_to_start_event: 'http://webhooks/start',
retries_timeout_about_to_start_event: [1,2,3],
callback_url_about_to_submit_event: 'http://webhooks/submit',
retries_timeout_url_about_to_submit_event: [4,5,6],
callback_url_submitted_event: 'http://webhooks/submitted',
retries_timeout_url_submitted_event: [7,8,9],
},
];

test('should return empty object when no actions', () => {
expect(normaliseUpdateActions([])).toEqual({});
});

test('should transform array of events into object of normalised update actions', () => {
expect(normaliseUpdateActions(actions)).toEqual({
'action1': {
id: 'action1',
name: 'Update action 1',
description: 'A first update action',
order: 1,
fromStates: undefined,
precondition: 'field1 EQUALS "value1"',
toState: 'state1',
acl: {
'caseworker-test-write': CR,
'caseworker-test-read': AclV2.READ,
},
classification: 'PUBLIC',
webhooks: {},
},
'action2': {
id: 'action2',
name: 'Update action 2',
order: 2,
fromStates: ['state1', 'state3'],
toState: 'state2',
postconditions: [
{path: 'field1', value: 'value1'},
{path: 'field2', value: 'value2'},
],
acl: {
'caseworker-test-write': AclV2.CREATE,
},
classification: 'PRIVATE',
webhooks: {
onStart: {
url: 'http://webhooks/start',
retries: [1,2,3]
},
onSubmit: {
url: 'http://webhooks/submit',
retries: [4,5,6]
},
onSubmitted: {
url: 'http://webhooks/submitted',
retries: [7,8,9]
},
},
},
});
});

test('should filter out update actions', () => {
const createActions = normaliseUpdateActions([
...actions,
{
id: 'createAction1',
name: 'Create action',
pre_states: [],
acls: [],
}
]);

expect(createActions).not.toHaveProperty('createAction1');
});
});
6 changes: 4 additions & 2 deletions src/definition/normalise-type.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as AclV2 from '../acl-v2.js';
import {normaliseCreateActions, normaliseUpdateActions} from './normalise-actions.js';
import normaliseFields from './normalise-fields.js';
import normaliseStates from './normalise-states.js';

Expand All @@ -18,9 +19,10 @@ const normaliseType = (type) => ({
description: type.description,
title: type.titleDisplay,
acl: AclV2.fromLegacy(type.acls),
events: {}, // TODO once normalisation of events implemented
fields: normaliseFields(type.case_fields),
createActions: normaliseCreateActions(type.events),
actions: normaliseUpdateActions(type.events),
states: normaliseStates(type.states),
});

export default normaliseType;
export default normaliseType;
Loading