mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-09 01:13:55 +00:00
fix: api change custom fields (#1888)
* fix: validate nested custom path * chore: add test
This commit is contained in:
committed by
GitHub
parent
80ec2d1186
commit
f128f7acd2
@@ -0,0 +1,91 @@
|
||||
import { EntryCustomFields, OntimeEvent } from 'ontime-types';
|
||||
import { isValidChangeProperty } from '../integration.utils.js';
|
||||
|
||||
describe('isValidChangeProperty()', () => {
|
||||
test('correct value and property', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'duration', 123)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('correct property and undefined value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'duration', undefined)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('missing property and undefined value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'missing', 123)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('non existing custom value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
field: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:test', 123)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('existing custom value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:test', 123)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('empty custom definition', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:', 123)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('build-in in custom', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:toString', 123)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('build-in in top object', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'toString', 123)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,7 @@ import { validateMessage, validateTimerMessage } from '../services/message-servi
|
||||
import { runtimeService } from '../services/runtime-service/runtime.service.js';
|
||||
import { eventStore } from '../stores/EventStore.js';
|
||||
import * as assert from '../utils/assert.js';
|
||||
import { parseProperty } from './integration.utils.js';
|
||||
import { parseProperty, isValidChangeProperty } from './integration.utils.js';
|
||||
import { socket } from '../adapters/WebsocketAdapter.js';
|
||||
import { throttle } from '../utils/throttle.js';
|
||||
import { coerceEnum } from '../utils/coerceType.js';
|
||||
@@ -77,10 +77,9 @@ const actionHandlers: Record<ApiActionTag, ActionHandler> = {
|
||||
let shouldThrottle = false;
|
||||
|
||||
Object.entries(data).forEach(([property, value]) => {
|
||||
if (typeof property !== 'string' || value === undefined || !(property in targetEntry)) {
|
||||
if (!isValidChangeProperty(targetEntry, property, value)) {
|
||||
throw new Error('Invalid property or value');
|
||||
}
|
||||
// parseProperty is async because of the data lock
|
||||
const newObjectProperty = parseProperty(property, value);
|
||||
const key = Object.keys(newObjectProperty)[0];
|
||||
shouldThrottle = shouldThrottle || willCauseRegeneration(key);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { EndAction, TimeStrategy, TimerType, isKeyOfType } from 'ontime-types';
|
||||
import { EndAction, OntimeEntry, TimeStrategy, TimerType, isKeyOfType } from 'ontime-types';
|
||||
import { maxDuration } from 'ontime-utils';
|
||||
|
||||
import { coerceBoolean, coerceColour, coerceEnum, coerceNumber, coerceString } from '../utils/coerceType.js';
|
||||
@@ -60,3 +60,14 @@ export function parseProperty(property: string, value: unknown) {
|
||||
const parserFn = propertyConversion[property];
|
||||
return { [property]: parserFn(value) };
|
||||
}
|
||||
|
||||
export function isValidChangeProperty(target: OntimeEntry, property: string, value: unknown): boolean {
|
||||
if (typeof property !== 'string') return false;
|
||||
if (value === undefined) return false;
|
||||
if (property.startsWith('custom:') && 'custom' in target) {
|
||||
const customProperty = property.slice('custom:'.length);
|
||||
if (!customProperty) return false;
|
||||
return Object.hasOwn(target.custom, customProperty);
|
||||
}
|
||||
return Object.hasOwn(target, property);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user