fix: issue where a end time can be overflowing (#761)

This commit is contained in:
Carlos Valente
2024-02-06 11:42:28 +01:00
committed by GitHub
parent 965a7092d9
commit 467b595375
10 changed files with 94 additions and 13 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ontime-ui", "name": "ontime-ui",
"version": "2.28.12", "version": "2.28.13",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@chakra-ui/react": "^2.7.0", "@chakra-ui/react": "^2.7.0",
@@ -1,7 +1,7 @@
import { memo } from 'react'; import { memo } from 'react';
import { Select, Switch } from '@chakra-ui/react'; import { Select, Switch } from '@chakra-ui/react';
import { EndAction, OntimeEvent, TimerType } from 'ontime-types'; import { EndAction, OntimeEvent, TimerType } from 'ontime-types';
import { calculateDuration, millisToString } from 'ontime-utils'; import { calculateDuration, dayInMs, millisToString } from 'ontime-utils';
import TimeInput from '../../../common/components/input/time-input/TimeInput'; import TimeInput from '../../../common/components/input/time-input/TimeInput';
import { useEventAction } from '../../../common/hooks/useEventAction'; import { useEventAction } from '../../../common/hooks/useEventAction';
@@ -28,14 +28,13 @@ const EventEditorTimes = (props: EventEditorTimesProps) => {
const { eventId, timeStart, timeEnd, duration, delay, isPublic, endAction, timerType } = props; const { eventId, timeStart, timeEnd, duration, delay, isPublic, endAction, timerType } = props;
const { updateEvent } = useEventAction(); const { updateEvent } = useEventAction();
const handleSubmit = (field: TimeActions, value: number | string | boolean) => { const handleSubmit = (field: TimeActions, value: number | string | boolean) => {
const newEventData: Partial<OntimeEvent> = { id: eventId }; const newEventData: Partial<OntimeEvent> = { id: eventId };
switch (field) { switch (field) {
case 'durationOverride': { case 'durationOverride': {
// duration defines timeEnd // duration defines timeEnd
newEventData.duration = value as number; newEventData.duration = value as number;
newEventData.timeEnd = timeStart + (value as number); newEventData.timeEnd = timeStart + ((value as number) % dayInMs);
break; break;
} }
case 'timeStart': { case 'timeStart': {
@@ -1,6 +1,6 @@
import { memo } from 'react'; import { memo } from 'react';
import { OntimeEvent } from 'ontime-types'; import { OntimeEvent } from 'ontime-types';
import { calculateDuration, millisToString } from 'ontime-utils'; import { calculateDuration, dayInMs, millisToString } from 'ontime-utils';
import TimeInput from '../../../../common/components/input/time-input/TimeInput'; import TimeInput from '../../../../common/components/input/time-input/TimeInput';
import { useEventAction } from '../../../../common/hooks/useEventAction'; import { useEventAction } from '../../../../common/hooks/useEventAction';
@@ -29,7 +29,7 @@ const EventBlockTimers = (props: EventBlockTimerProps) => {
case 'durationOverride': { case 'durationOverride': {
// duration defines timeEnd // duration defines timeEnd
newEventData.duration = value; newEventData.duration = value;
newEventData.timeEnd = timeStart + value; newEventData.timeEnd = timeStart + ((value as number) % dayInMs);
break; break;
} }
case 'timeStart': { case 'timeStart': {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ontime", "name": "ontime",
"version": "2.28.12", "version": "2.28.13",
"author": "Carlos Valente", "author": "Carlos Valente",
"description": "Time keeping for live events", "description": "Time keeping for live events",
"repository": "https://github.com/cpvalente/ontime", "repository": "https://github.com/cpvalente/ontime",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "ontime-server", "name": "ontime-server",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"version": "2.28.12", "version": "2.28.13",
"exports": "./src/index.js", "exports": "./src/index.js",
"dependencies": { "dependencies": {
"@googleapis/sheets": "^5.0.5", "@googleapis/sheets": "^5.0.5",
@@ -528,6 +528,76 @@ describe('test that roll behaviour multi day event edge cases', () => {
}); });
}); });
// test getRollTimers() on issue #757
describe('it handles timeEnd over day', () => {
it('ignores events with timeEnd larger than a day', () => {
const testRundown = [
{
title: 'Setup',
subtitle: '',
presenter: '',
note: 'BMA, Nebelfluid, Shooter, Akkus, UHF11, Getränke, Kaffee, Strom, ELA, Text für Holger',
endAction: 'play-next',
timerType: 'count-down',
timeStart: 66600000,
timeEnd: 68400000,
duration: 1800000,
isPublic: false,
skip: false,
colour: '#2fa9e5',
user0: '',
user1: '',
user2: '',
user3: '',
user4: '',
user5: '',
user6: '',
user7: '',
user8: '',
user9: '',
type: 'event',
revision: 0,
cue: 'PRE',
id: 'b2f8d',
},
{
title: 'Künstliche Intelligenz',
subtitle: ' -> Vorstellung Maske',
presenter: 'Engel und Teufel',
note: 'Melli Kleben! Sofa',
endAction: 'play-next',
timerType: 'count-down',
timeStart: 86100000,
// timeEnd: 1020000, <--- this would have been equivalent
timeEnd: 87420000,
duration: 1320000,
isPublic: true,
skip: false,
colour: '#a8ec31',
user0: 'UHF1 Melli (Korsett)',
user1: 'UHF2 Reinhold (unter Flügel)',
user2: 'UHF3 Oli (Sport-Unterhose Rechts)',
user3: '',
user4: '',
user5: '',
user6: '',
user7: '',
user8: '',
user9: '',
type: 'event',
revision: 0,
cue: '16',
id: '8b970',
},
];
const timeNow = 64488675; // 17:55-something
const timers = getRollTimers(testRundown as OntimeEvent[], timeNow);
expect(timers.currentEvent).toBeNull();
});
});
// test normaliseEndTime() on issue #58 // test normaliseEndTime() on issue #58
test('test typical scenarios', () => { test('test typical scenarios', () => {
const t1 = { const t1 = {
+2 -1
View File
@@ -79,7 +79,8 @@ export const getRollTimers = (rundown: OntimeEvent[], timeNow: number) => {
const normalEnd = normaliseEndTime(event.timeStart, event.timeEnd); const normalEnd = normaliseEndTime(event.timeStart, event.timeEnd);
const hasNotEnded = normalEnd > timeNow; const hasNotEnded = normalEnd > timeNow;
const isFromDayBefore = normalEnd > dayInMs && timeNow < event.timeEnd; // TODO: we will likely want a better solution than the modulus here
const isFromDayBefore = normalEnd > dayInMs && timeNow < event.timeEnd % dayInMs;
const hasStarted = isFromDayBefore || timeNow >= event.timeStart; const hasStarted = isFromDayBefore || timeNow >= event.timeStart;
if (normalEnd <= timeNow) { if (normalEnd <= timeNow) {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ontime", "name": "ontime",
"version": "2.28.12", "version": "2.28.13",
"description": "Time keeping for live events", "description": "Time keeping for live events",
"keywords": [ "keywords": [
"lightdev", "lightdev",
@@ -93,6 +93,17 @@ describe('validateTimes()', () => {
expect(timeEnd).toBe(10); expect(timeEnd).toBe(10);
expect(duration).toBe(10); expect(duration).toBe(10);
}); });
it('ensures values dont overflow dayMs', () => {
const start = 86100000;
const endOverDay = 87420000;
const durationNormal = 1320000;
const { timeStart, timeEnd, duration } = validateTimes(start, endOverDay, durationNormal);
expect(timeStart).toBe(start);
expect(timeEnd).toBe(1020000);
expect(duration).toBe(durationNormal);
});
}); });
describe('calculateDuration()', () => { describe('calculateDuration()', () => {
@@ -52,9 +52,9 @@ function convertToInteger(value: unknown): number {
* @param _duration * @param _duration
*/ */
export function validateTimes(_start?: unknown, _end?: unknown, _duration?: unknown) { export function validateTimes(_start?: unknown, _end?: unknown, _duration?: unknown) {
const timeStart = convertToInteger(_start); const timeStart = convertToInteger(_start) % dayInMs;
const timeEnd = convertToInteger(_end); const timeEnd = convertToInteger(_end) % dayInMs;
const duration = convertToInteger(_duration); const duration = convertToInteger(_duration) % dayInMs;
if (_start != null && _end != null) { if (_start != null && _end != null) {
// Case 1. if we have start and end, duration must be derived // Case 1. if we have start and end, duration must be derived