From accdf2c396c8249351e37df29b18f26ecc8091ea Mon Sep 17 00:00:00 2001 From: Alex Christoffer Rasmussen Date: Mon, 29 Apr 2024 22:33:58 +0200 Subject: [PATCH] Fix: custom fields with undefined colour is not accepted by `parseCustomFields` (#925) --- .../utils/__tests__/parserFunctions.test.ts | 88 ++++++++++++++++++- apps/server/src/utils/parserFunctions.ts | 14 +-- 2 files changed, 95 insertions(+), 7 deletions(-) diff --git a/apps/server/src/utils/__tests__/parserFunctions.test.ts b/apps/server/src/utils/__tests__/parserFunctions.test.ts index b750bd443..83b135e76 100644 --- a/apps/server/src/utils/__tests__/parserFunctions.test.ts +++ b/apps/server/src/utils/__tests__/parserFunctions.test.ts @@ -1,5 +1,5 @@ -import { HttpSubscription, OscSubscription } from 'ontime-types'; -import { sanitiseHttpSubscriptions, sanitiseOscSubscriptions } from '../parserFunctions.js'; +import { CustomFields, HttpSubscription, OscSubscription } from 'ontime-types'; +import { sanitiseCustomFields, sanitiseHttpSubscriptions, sanitiseOscSubscriptions } from '../parserFunctions.js'; describe('sanitiseOscSubscriptions()', () => { it('returns an empty array if not an array', () => { @@ -71,3 +71,87 @@ describe('sanitiseHttpSubscriptions()', () => { expect(sanitationResult.length).toBe(0); }); }); + +describe('sanitiseCustomFields()', () => { + it('returns an empty array if not an array', () => { + expect(sanitiseCustomFields({})).toEqual({}); + }); + + it('returns an object of valid entries', () => { + const customFields: CustomFields = { + test: { label: 'test', type: 'string', colour: 'red' }, + test2: { label: 'test2', type: 'string', colour: 'green' }, + test3: { label: 'Test3', type: 'string', colour: '' }, + }; + const sanitationResult = sanitiseCustomFields(customFields); + expect(sanitationResult).toStrictEqual(customFields); + }); + + it('type is forced to be string', () => { + const customFields: CustomFields = { + // @ts-expect-error intentional bad data + test: { label: 'test', type: 'another', colour: 'red' }, + }; + const expectedCustomFields: CustomFields = { + test: { label: 'test', type: 'string', colour: 'red' }, + }; + const sanitationResult = sanitiseCustomFields(customFields); + expect(sanitationResult).toStrictEqual(expectedCustomFields); + }); + + it('colour must be a string', () => { + const customFields: CustomFields = { + // @ts-expect-error intentional bad data + test: { label: 'test', type: 'string', colour: 5 }, + }; + const sanitationResult = sanitiseCustomFields(customFields); + expect(sanitationResult).toStrictEqual({}); + }); + + it('label can not be empty', () => { + const customFields: CustomFields = { + ['']: { label: '', type: 'string', colour: 'red' }, + }; + const sanitationResult = sanitiseCustomFields(customFields); + expect(sanitationResult).toStrictEqual({}); + }); + + it('remove extra stuff', () => { + const customFields: CustomFields = { + // @ts-expect-error intentional bad data + test: { label: 'test', type: 'string', colour: 'red', extra: 'should be removed' }, + }; + const expectedCustomFields: CustomFields = { + test: { label: 'test', type: 'string', colour: 'red' }, + }; + const sanitationResult = sanitiseCustomFields(customFields); + expect(sanitationResult).toStrictEqual(expectedCustomFields); + }); + + it('enforece name cohesion', () => { + const customFields: CustomFields = { + test: { label: 'New Name', type: 'string', colour: 'red' }, + }; + const expectedCustomFields: CustomFields = { + ['new name']: { label: 'New Name', type: 'string', colour: 'red' }, + }; + const sanitationResult = sanitiseCustomFields(customFields); + expect(sanitationResult).toStrictEqual(expectedCustomFields); + }); + + it('filters invalid entries', () => { + const customFields: CustomFields = { + test: { label: 'test', type: 'string', colour: 'red' }, + test2: { label: 'test2', type: 'string', colour: 'green' }, + bad: { label: '', type: 'string', colour: '' }, + test3: { label: 'Test3', type: 'string', colour: '' }, + }; + const expectedCustomFields: CustomFields = { + test: { label: 'test', type: 'string', colour: 'red' }, + test2: { label: 'test2', type: 'string', colour: 'green' }, + test3: { label: 'Test3', type: 'string', colour: '' }, + }; + const sanitationResult = sanitiseCustomFields(customFields); + expect(sanitationResult).toStrictEqual(expectedCustomFields); + }); +}); diff --git a/apps/server/src/utils/parserFunctions.ts b/apps/server/src/utils/parserFunctions.ts index 6aed650c6..504e12644 100644 --- a/apps/server/src/utils/parserFunctions.ts +++ b/apps/server/src/utils/parserFunctions.ts @@ -248,20 +248,24 @@ export const parseCustomFields = (data: Partial): CustomFields => if (typeof data.customFields !== 'object') { return { ...dbModel.customFields }; } - console.log('Found Custom Fields, importing...'); + return sanitiseCustomFields(data.customFields); +}; + +export const sanitiseCustomFields = (data: object): CustomFields => { const newCustomFields: CustomFields = {}; - for (const fieldLabel in data.customFields) { - const field = data.customFields[fieldLabel]; - if (!field.label || !field.type || !field.colour) { + for (const fieldLabel in data) { + const field = data[fieldLabel]; + if (!('label' in field) || field.label === '' || !('colour' in field) || typeof field.colour != 'string') { console.log('ERROR: missing required field, skipping'); continue; } + const key = field.label.toLowerCase(); newCustomFields[key] = { - type: field.type, + type: 'string', colour: field.colour, label: field.label, };