Skip to content

Commit

Permalink
fix: FORMS-1081 handle invalid form version in export (bcgov#1353)
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterMoar authored May 14, 2024
1 parent c4608a0 commit a8839f3
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 75 deletions.
68 changes: 3 additions & 65 deletions app/src/forms/form/exportService.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,71 +21,6 @@ const service = {
* @param {Object} schema A form.io schema
* @returns {String[]} An array of strings
*/
_readSchemaFieldsV2: (schema) => {
/**
* @function findFields
* Recursively traverses the form.io schema to extract all relevant content field names
* @param {Object} obj A form.io schema or subset of it
* @returns {String[]} An array of strings
*/
const findFields = (obj) => {
const fields = [];
const fieldsDefinedInSubmission = ['datamap', 'tree'];

// if an input component (not hidden or a button)
if (obj.key && obj.input && !obj.hidden && obj.type !== 'button') {
// if the fieldname we want is defined in component's sub-values
const componentsWithSubValues = ['simplecheckboxes', 'selectboxes', 'survey', 'address'];
if (obj.type && componentsWithSubValues.includes(obj.type)) {
// for survey component, get field name from obj.questions.value
if (obj.type === 'survey') {
obj.questions.forEach((e) => fields.push(`${obj.key}.${e.value}`));
}
// for checkboxes and selectboxes, get field name from obj.values.value
else if (obj.values) obj.values.forEach((e) => fields.push(`${obj.key}.${e.value}`));
// else push the parent field
else {
fields.push(obj.key);
}
}

// get these sub-vales so they appear in ordered columns
else if (obj.type === 'simplefile') {
fields.push(`${obj.key}.url`, `${obj.key}.url`, `${obj.key}.data.id`, `${obj.key}.size`, `${obj.key}.storage`, `${obj.key}.originalName`);
} else if (!obj.tree && !fieldsDefinedInSubmission.includes(obj.type)) {
/**
* component's 'tree' property is true for input components with child inputs,
* which we get recursively.
* also exclude fieldnames defined in submission
* eg datagrid, container, tree
*/
// Add current field key
fields.push(obj.key);
}
}

// Recursively traverse children array levels
Object.entries(obj).forEach(([k, v]) => {
if (Array.isArray(v) && v.length) {
// Enumerate children fields
const children = obj[k].flatMap((e) => {
const cFields = findFields(e);
// Prepend current key to field name if component's 'tree' property is true
// eg: datagrid1.textFieldInDataGrid1
// TODO: find fields in 'table' component
return obj.tree && !fieldsDefinedInSubmission.includes(obj.type) ? cFields.flatMap((c) => `${obj.key}.${c}`) : cFields;
});
if (children.length) {
Array.prototype.push.apply(fields, children); // concat into first argument
}
}
});

return fields;
};

return findFields(schema);
},
_readSchemaFields: async (schema) => {
return await flattenComponents(schema.components);
},
Expand Down Expand Up @@ -146,6 +81,9 @@ const service = {

// get correctly ordered field names (keys) from latest form version
const latestFormDesign = await service._readLatestFormSchema(form.id, version);
if (!latestFormDesign) {
throw new Problem(400, `Form ${form.id} does not have version #${version}`);
}

const fieldNames = await service._readSchemaFields(latestFormDesign, data);
// get meta properties in 'form.<child.key>' string format
Expand Down
58 changes: 48 additions & 10 deletions app/tests/unit/forms/form/exportService.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,52 @@ const getCsvRow = (result, index) => {

describe('export', () => {
describe('csv', () => {
describe('type 3', () => {
const currentUser = {
usernameIdp: 'PAT_TEST',
};
const form = {
snake: () => {
'form';
},
const currentUser = {
usernameIdp: 'PAT_TEST',
};
const form = {
snake: () => {
'form';
},
};
exportService._getForm = jest.fn().mockReturnValue(form);

describe('type 1', () => {
const params = {
emailExport: false,
fields: ['form.submissionId', 'form.confirmationId', 'form.formName', 'form.version', 'form.createdAt', 'form.fullName', 'form.username', 'form.email', 'simpletextfield'],
template: 'multiRowEmptySpacesCSVExport',
};

test('invalid form version', async () => {
const submission = [
{
submissionId: 'd5a40f00-ee5e-49ab-9bd7-b34f7f7b9c1b',
confirmationId: 'D5A40F00',
formName: 'form',
version: 1,
createdAt: '2024-05-03T20:56:31.270Z',
fullName: 'Pat Test',
username: 'PAT_TEST',
email: '[email protected]',
submission: {
dataGrid: [
{
simpletextfield: 'simple text field 1-1',
},
],
lateEntry: false,
},
},
];
exportService._getData = jest.fn().mockReturnValueOnce(submission);
exportService._readLatestFormSchema = jest.fn().mockReturnValueOnce();

await expect(exportService.export(formId, params, currentUser)).rejects.toThrow('400');
});
});

describe('type 3', () => {
const latestFormSchema = {
display: 'form',
type: 'form',
Expand Down Expand Up @@ -68,8 +105,6 @@ describe('export', () => {
template: 'singleRowCSVExport',
};

exportService._getForm = jest.fn().mockReturnValue(form);
exportService._readLatestFormSchema = jest.fn().mockReturnValue(latestFormSchema);
emailService.submissionExportLink = jest.fn();
fileService.create = jest.fn().mockReturnValue({});

Expand All @@ -95,6 +130,7 @@ describe('export', () => {
},
];
exportService._getData = jest.fn().mockReturnValue(submission);
exportService._readLatestFormSchema = jest.fn().mockReturnValueOnce(latestFormSchema);

const result = await exportService.export(formId, params, currentUser);

Expand Down Expand Up @@ -128,6 +164,7 @@ describe('export', () => {
},
];
exportService._getData = jest.fn().mockReturnValue(submission);
exportService._readLatestFormSchema = jest.fn().mockReturnValueOnce(latestFormSchema);

const result = await exportService.export(formId, params, currentUser);

Expand Down Expand Up @@ -181,6 +218,7 @@ describe('export', () => {
},
];
exportService._getData = jest.fn().mockReturnValue(submission);
exportService._readLatestFormSchema = jest.fn().mockReturnValueOnce(latestFormSchema);

const result = await exportService.export(formId, params, currentUser);

Expand Down

0 comments on commit a8839f3

Please sign in to comment.