mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-13 19:33:46 +00:00
Deps migration (#1988)
* chore: migrate eslint to oxlint * chore: migrate prettier to oxfmt * chore: migrate typescript * chore: toThrow should have a expected value * chore: cast test value as Day * chore: small title fix * chore: mocks should be hoisted * chore: incorrect async useage * chore: test should be inside description * chore: test sohuld include an expeced * chore: oxfmt --------- Co-authored-by: alex-Arc <omnivox@LAPTOP-RC5SNBVV.localdomain>
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
import { LogOrigin } from 'ontime-types';
|
||||
|
||||
import { fromBuffer, type OscPacketOutput } from 'osc-min';
|
||||
import * as dgram from 'node:dgram';
|
||||
|
||||
import { logger } from '../classes/Logger.js';
|
||||
import { dispatchFromAdapter } from '../api-integration/integration.controller.js';
|
||||
import { isOntimeCloud } from '../setup/environment.js';
|
||||
import { LogOrigin } from 'ontime-types';
|
||||
import { type OscPacketOutput, fromBuffer } from 'osc-min';
|
||||
|
||||
import { integrationPayloadFromPath } from './utils/parse.js';
|
||||
import { dispatchFromAdapter } from '../api-integration/integration.controller.js';
|
||||
import { logger } from '../classes/Logger.js';
|
||||
import { isOntimeCloud } from '../setup/environment.js';
|
||||
import type { IAdapter } from './IAdapter.js';
|
||||
import { integrationPayloadFromPath } from './utils/parse.js';
|
||||
|
||||
class OscServer implements IAdapter {
|
||||
private udpSocket: dgram.Socket | null = null;
|
||||
|
||||
@@ -14,26 +14,26 @@
|
||||
* Payload: adds necessary payload for the request to be completed
|
||||
*/
|
||||
|
||||
import type { Server } from 'http';
|
||||
|
||||
import {
|
||||
Client,
|
||||
LogOrigin,
|
||||
WsPacketToClient,
|
||||
WsPacketToServer,
|
||||
MaybeNumber,
|
||||
MessageTag,
|
||||
RefetchKey,
|
||||
MaybeNumber,
|
||||
WsPacketToClient,
|
||||
WsPacketToServer,
|
||||
} from 'ontime-types';
|
||||
|
||||
import { generateId } from 'ontime-utils';
|
||||
import { WebSocket, WebSocketServer } from 'ws';
|
||||
import type { Server } from 'http';
|
||||
|
||||
import { dispatchFromAdapter } from '../api-integration/integration.controller.js';
|
||||
import { logger } from '../classes/Logger.js';
|
||||
import { authenticateSocket } from '../middleware/authenticate.js';
|
||||
import { eventStore } from '../stores/EventStore.js';
|
||||
import getRandomName from '../utils/getRandomName.js';
|
||||
import type { IAdapter } from './IAdapter.js';
|
||||
import { eventStore } from '../stores/EventStore.js';
|
||||
import { logger } from '../classes/Logger.js';
|
||||
import { dispatchFromAdapter } from '../api-integration/integration.controller.js';
|
||||
import { generateId } from 'ontime-utils';
|
||||
import { authenticateSocket } from '../middleware/authenticate.js';
|
||||
|
||||
type ClientId = string;
|
||||
let instance: SocketServer | null = null;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
import { RefetchKey, type ErrorResponse } from 'ontime-types';
|
||||
import { validatePostCss, validatePostTranslation } from './assets.validation.js';
|
||||
import { readCssFile, writeCssFile, writeUserTranslation } from './assets.service.js';
|
||||
import { type ErrorResponse, RefetchKey } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
import { defaultCss } from '../../user/styles/bundledCss.js';
|
||||
|
||||
import { sendRefetch } from '../../adapters/WebsocketAdapter.js';
|
||||
import { defaultCss } from '../../user/styles/bundledCss.js';
|
||||
import { readCssFile, writeCssFile, writeUserTranslation } from './assets.service.js';
|
||||
import { validatePostCss, validatePostTranslation } from './assets.validation.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { TranslationObject } from 'ontime-types';
|
||||
|
||||
import { existsSync } from 'node:fs';
|
||||
import { readFile, writeFile } from 'node:fs/promises';
|
||||
|
||||
import type { TranslationObject } from 'ontime-types';
|
||||
|
||||
import { publicFiles } from '../../setup/index.js';
|
||||
import { defaultCss } from '../../user/styles/bundledCss.js';
|
||||
|
||||
|
||||
@@ -1,41 +1,37 @@
|
||||
import { TriggerDTO, TimerLifeCycle, AutomationDTO, Automation, ProjectRundowns } from 'ontime-types';
|
||||
import { Automation, AutomationDTO, ProjectRundowns, TimerLifeCycle, TriggerDTO } from 'ontime-types';
|
||||
|
||||
import { makeOntimeEvent } from '../../rundown/__mocks__/rundown.mocks.js';
|
||||
|
||||
import {
|
||||
addTrigger,
|
||||
addAutomation,
|
||||
addTrigger,
|
||||
deleteAll,
|
||||
deleteAllTriggers,
|
||||
deleteTrigger,
|
||||
deleteAutomation,
|
||||
editTrigger,
|
||||
deleteTrigger,
|
||||
editAutomation,
|
||||
editTrigger,
|
||||
getAutomationTriggers,
|
||||
getAutomations,
|
||||
} from '../automation.dao.js';
|
||||
import { makeHTTPAction, makeOSCAction } from './testUtils.js';
|
||||
|
||||
import { makeOSCAction, makeHTTPAction } from './testUtils.js';
|
||||
|
||||
beforeAll(() => {
|
||||
vi.mock('../../../classes/data-provider/DataProvider.js', () => {
|
||||
// Create a small mock store
|
||||
let automations = {
|
||||
enabledAutomations: true,
|
||||
enabledOscIn: true,
|
||||
oscPortIn: 8888,
|
||||
triggers: [],
|
||||
automations: {},
|
||||
};
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
getAutomation: vi.fn().mockImplementation(() => automations),
|
||||
setAutomation: vi.fn().mockImplementation((newData) => (automations = newData)),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
vi.mock('../../../classes/data-provider/DataProvider.js', () => {
|
||||
// Create a small mock store
|
||||
let automations = {
|
||||
enabledAutomations: true,
|
||||
enabledOscIn: true,
|
||||
oscPortIn: 8888,
|
||||
triggers: [],
|
||||
automations: {},
|
||||
};
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
getAutomation: vi.fn().mockImplementation(() => automations),
|
||||
setAutomation: vi.fn().mockImplementation((newData) => (automations = newData)),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
@@ -141,7 +137,7 @@ describe('addAutomation()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('editAutomation()', async () => {
|
||||
describe('editAutomation()', () => {
|
||||
// saving the ID of the added automation
|
||||
let firstAutomation: Automation;
|
||||
beforeEach(async () => {
|
||||
|
||||
@@ -1,35 +1,31 @@
|
||||
import { PlayableEvent, TimerLifeCycle } from 'ontime-types';
|
||||
|
||||
import { makeRuntimeStoreData } from '../../../stores/__mocks__/runtimeStore.mocks.js';
|
||||
|
||||
import { deleteAllTriggers, addTrigger, addAutomation } from '../automation.dao.js';
|
||||
import { testConditions, triggerAutomations } from '../automation.service.js';
|
||||
import * as oscClient from '../clients/osc.client.js';
|
||||
import * as httpClient from '../clients/http.client.js';
|
||||
|
||||
import { makeOSCAction, makeHTTPAction } from './testUtils.js';
|
||||
import { RuntimeState } from '../../../stores/runtimeState.js';
|
||||
import { makeOntimeEvent } from '../../rundown/__mocks__/rundown.mocks.js';
|
||||
import { addAutomation, addTrigger, deleteAllTriggers } from '../automation.dao.js';
|
||||
import { testConditions, triggerAutomations } from '../automation.service.js';
|
||||
import * as httpClient from '../clients/http.client.js';
|
||||
import * as oscClient from '../clients/osc.client.js';
|
||||
import { makeHTTPAction, makeOSCAction } from './testUtils.js';
|
||||
|
||||
beforeAll(() => {
|
||||
vi.mock('../../../classes/data-provider/DataProvider.js', () => {
|
||||
// Create a small mock store
|
||||
let automations = {
|
||||
enabledAutomations: true,
|
||||
enabledOscIn: true,
|
||||
oscPortIn: 8888,
|
||||
triggers: [],
|
||||
automations: {},
|
||||
};
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
getAutomation: vi.fn().mockImplementation(() => automations),
|
||||
setAutomation: vi.fn().mockImplementation((newData) => (automations = newData)),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
vi.mock('../../../classes/data-provider/DataProvider.js', () => {
|
||||
// Create a small mock store
|
||||
let automations = {
|
||||
enabledAutomations: true,
|
||||
enabledOscIn: true,
|
||||
oscPortIn: 8888,
|
||||
triggers: [],
|
||||
automations: {},
|
||||
};
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
getAutomation: vi.fn().mockImplementation(() => automations),
|
||||
setAutomation: vi.fn().mockImplementation((newData) => (automations = newData)),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
@@ -41,7 +37,7 @@ describe('triggerAction()', () => {
|
||||
let httpSpy = vi.spyOn(httpClient, 'emitHTTP');
|
||||
|
||||
beforeAll(() => {
|
||||
vi.mock('../../../stores/EventStore.js', () => {
|
||||
vi.doMock('../../../stores/EventStore.js', () => {
|
||||
// Create a small mock store
|
||||
return {
|
||||
eventStore: {
|
||||
@@ -49,11 +45,11 @@ describe('triggerAction()', () => {
|
||||
},
|
||||
};
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
oscSpy = vi.spyOn(oscClient, 'emitOSC').mockImplementation(() => { });
|
||||
httpSpy = vi.spyOn(httpClient, 'emitHTTP').mockImplementation(() => { });
|
||||
oscSpy = vi.spyOn(oscClient, 'emitOSC').mockImplementation(() => {});
|
||||
httpSpy = vi.spyOn(httpClient, 'emitHTTP').mockImplementation(() => {});
|
||||
|
||||
await deleteAllTriggers();
|
||||
const oscAutomation = await addAutomation({
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ProjectRundowns, TimerLifeCycle } from 'ontime-types';
|
||||
|
||||
import { makeOntimeEvent } from '../../rundown/__mocks__/rundown.mocks.js';
|
||||
|
||||
import { isAutomationUsed, parseTemplateNested, stringToOSCArgs } from '../automation.utils.js';
|
||||
|
||||
describe('parseTemplateNested()', () => {
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('parseOutput', () => {
|
||||
address: '/test',
|
||||
args: 'test',
|
||||
};
|
||||
expect(() => parseOutput(payload)).toThrow();
|
||||
expect(() => parseOutput(payload)).toThrow('Unexpected payload type:');
|
||||
});
|
||||
});
|
||||
describe('handles HTTP outputs', () => {
|
||||
@@ -39,7 +39,7 @@ describe('parseOutput', () => {
|
||||
const payload = {
|
||||
type: 'http',
|
||||
};
|
||||
expect(() => parseOutput(payload)).toThrow();
|
||||
expect(() => parseOutput(payload)).toThrow('Unexpected payload type:');
|
||||
});
|
||||
});
|
||||
describe('handles Ontime outputs', () => {
|
||||
@@ -79,7 +79,7 @@ describe('parseOutput', () => {
|
||||
type: 'ontime',
|
||||
action: 'not-exist',
|
||||
};
|
||||
expect(() => parseOutput(payload)).toThrow();
|
||||
expect(() => parseOutput(payload)).toThrow('Invalid Ontime action');
|
||||
});
|
||||
|
||||
it('parses message-set', () => {
|
||||
@@ -122,45 +122,46 @@ describe('parseOutput', () => {
|
||||
text: 123,
|
||||
visible: '',
|
||||
}),
|
||||
).toThrow();
|
||||
).toThrow('Unexpected payload type:');
|
||||
});
|
||||
|
||||
it('parses message-secondary', () => {});
|
||||
expect(
|
||||
parseOutput({
|
||||
type: 'ontime',
|
||||
action: 'message-secondary',
|
||||
secondarySource: 'test',
|
||||
}),
|
||||
).toMatchObject({
|
||||
secondarySource: null,
|
||||
});
|
||||
expect(
|
||||
parseOutput({
|
||||
type: 'ontime',
|
||||
action: 'message-secondary',
|
||||
secondarySource: '',
|
||||
}),
|
||||
).toMatchObject({
|
||||
secondarySource: null,
|
||||
});
|
||||
expect(
|
||||
parseOutput({
|
||||
type: 'ontime',
|
||||
action: 'message-secondary',
|
||||
it('parses message-secondary', () => {
|
||||
expect(
|
||||
parseOutput({
|
||||
type: 'ontime',
|
||||
action: 'message-secondary',
|
||||
secondarySource: 'test',
|
||||
}),
|
||||
).toMatchObject({
|
||||
secondarySource: null,
|
||||
});
|
||||
expect(
|
||||
parseOutput({
|
||||
type: 'ontime',
|
||||
action: 'message-secondary',
|
||||
secondarySource: '',
|
||||
}),
|
||||
).toMatchObject({
|
||||
secondarySource: null,
|
||||
});
|
||||
expect(
|
||||
parseOutput({
|
||||
type: 'ontime',
|
||||
action: 'message-secondary',
|
||||
secondarySource: 'aux1',
|
||||
}),
|
||||
).toMatchObject({
|
||||
secondarySource: 'aux1',
|
||||
}),
|
||||
).toMatchObject({
|
||||
secondarySource: 'aux1',
|
||||
});
|
||||
expect(
|
||||
parseOutput({
|
||||
type: 'ontime',
|
||||
action: 'message-secondary',
|
||||
});
|
||||
expect(
|
||||
parseOutput({
|
||||
type: 'ontime',
|
||||
action: 'message-secondary',
|
||||
secondarySource: 'secondary',
|
||||
}),
|
||||
).toMatchObject({
|
||||
secondarySource: 'secondary',
|
||||
}),
|
||||
).toMatchObject({
|
||||
secondarySource: 'secondary',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OSCOutput, HTTPOutput } from 'ontime-types';
|
||||
import { HTTPOutput, OSCOutput } from 'ontime-types';
|
||||
|
||||
export function makeOSCAction(action?: Partial<OSCOutput>): OSCOutput {
|
||||
return {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
import { Automation, AutomationSettings, ErrorResponse, Trigger } from 'ontime-types';
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import { Automation, AutomationSettings, ErrorResponse, Trigger } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import { oscServer } from '../../adapters/OscAdapter.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
|
||||
import * as automationDao from './automation.dao.js';
|
||||
import * as automationService from './automation.service.js';
|
||||
import { parseOutput } from './automation.validation.js';
|
||||
|
||||
@@ -10,7 +10,6 @@ import type {
|
||||
import { deleteAtIndex, generateId } from 'ontime-utils';
|
||||
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
|
||||
import { isAutomationUsed } from './automation.utils.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DatabaseModel, AutomationSettings, NormalisedAutomation, Trigger } from 'ontime-types';
|
||||
import { AutomationSettings, DatabaseModel, NormalisedAutomation, Trigger } from 'ontime-types';
|
||||
|
||||
import type { ErrorEmitter } from '../../utils/parserUtils.js';
|
||||
import { getPartialProject } from '../../models/dataModel.js';
|
||||
import type { ErrorEmitter } from '../../utils/parserUtils.js';
|
||||
|
||||
export function parseAutomationSettings(data: Partial<DatabaseModel>, emitError?: ErrorEmitter): AutomationSettings {
|
||||
const defaultAutomation: AutomationSettings = getPartialProject('automation');
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import express from 'express';
|
||||
|
||||
import { paramsWithId } from '../validation-utils/validationFunction.js';
|
||||
import {
|
||||
deleteTrigger,
|
||||
deleteAutomation,
|
||||
deleteTrigger,
|
||||
editAutomation,
|
||||
getAutomationSettings,
|
||||
postTrigger,
|
||||
postAutomation,
|
||||
putTrigger,
|
||||
postAutomationSettings,
|
||||
postTrigger,
|
||||
putTrigger,
|
||||
testOutput,
|
||||
} from './automation.controller.js';
|
||||
import {
|
||||
validateAutomationSettings,
|
||||
validateAutomation,
|
||||
validateAutomationPatch,
|
||||
validateAutomationSettings,
|
||||
validateTestPayload,
|
||||
validateTrigger,
|
||||
validateTriggerPatch,
|
||||
} from './automation.validation.js';
|
||||
import { paramsWithId } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
import {
|
||||
isHTTPOutput,
|
||||
isOntimeAction,
|
||||
isOSCOutput,
|
||||
LogOrigin,
|
||||
RuntimeStore,
|
||||
TimerLifeCycle,
|
||||
type AutomationFilter,
|
||||
type AutomationOutput,
|
||||
type FilterRule,
|
||||
LogOrigin,
|
||||
RuntimeStore,
|
||||
TimerLifeCycle,
|
||||
isHTTPOutput,
|
||||
isOSCOutput,
|
||||
isOntimeAction,
|
||||
} from 'ontime-types';
|
||||
import { getPropertyFromPath } from 'ontime-utils';
|
||||
|
||||
import { emitOSC } from './clients/osc.client.js';
|
||||
import { emitHTTP } from './clients/http.client.js';
|
||||
import { getAutomationsEnabled, getAutomations, getAutomationTriggers } from './automation.dao.js';
|
||||
import { isContained, isEquivalent, isGreaterThan, isLessThan } from './automation.utils.js';
|
||||
import { toOntimeAction } from './clients/ontime.client.js';
|
||||
|
||||
import { logger } from '../../classes/Logger.js';
|
||||
import { isOntimeCloud } from '../../setup/environment.js';
|
||||
import { eventStore } from '../../stores/EventStore.js';
|
||||
import { getAutomationTriggers, getAutomations, getAutomationsEnabled } from './automation.dao.js';
|
||||
import { isContained, isEquivalent, isGreaterThan, isLessThan } from './automation.utils.js';
|
||||
import { emitHTTP } from './clients/http.client.js';
|
||||
import { toOntimeAction } from './clients/ontime.client.js';
|
||||
import { emitOSC } from './clients/osc.client.js';
|
||||
|
||||
/**
|
||||
* Exposes a method for triggering actions based on a TimerLifeCycle event
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import {
|
||||
EntryId,
|
||||
FilterRule,
|
||||
isOntimeEvent,
|
||||
MaybeNumber,
|
||||
OntimeAction,
|
||||
ontimeActionKeyValues,
|
||||
ProjectRundowns,
|
||||
RundownEntries,
|
||||
isOntimeEvent,
|
||||
ontimeActionKeyValues,
|
||||
} from 'ontime-types';
|
||||
import { millisToString, removeLeadingZero, splitWhitespace, getPropertyFromPath } from 'ontime-utils';
|
||||
import type { OscArgOrArrayInput, OscArgInput } from 'osc-min';
|
||||
import { getPropertyFromPath, millisToString, removeLeadingZero, splitWhitespace } from 'ontime-utils';
|
||||
import type { OscArgInput, OscArgOrArrayInput } from 'osc-min';
|
||||
|
||||
type FilterOperator = 'equals' | 'not_equals' | 'greater_than' | 'less_than' | 'contains';
|
||||
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import { body, oneOf, param } from 'express-validator';
|
||||
import {
|
||||
Automation,
|
||||
AutomationFilter,
|
||||
AutomationOutput,
|
||||
HTTPOutput,
|
||||
OntimeAction,
|
||||
OSCOutput,
|
||||
OntimeAction,
|
||||
SecondarySource,
|
||||
timerLifecycleValues,
|
||||
} from 'ontime-types';
|
||||
|
||||
import { body, oneOf, param } from 'express-validator';
|
||||
|
||||
import * as assert from '../../utils/assert.js';
|
||||
|
||||
import { isFilterOperator, isFilterRule, isOntimeActionAction } from './automation.utils.js';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
import { isFilterOperator, isFilterRule, isOntimeActionAction } from './automation.utils.js';
|
||||
|
||||
export const validateAutomationSettings = [
|
||||
body('enabledAutomations').isBoolean(),
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { DeepReadonly } from 'ts-essentials';
|
||||
import { HTTPOutput, LogOrigin, RuntimeStore } from 'ontime-types';
|
||||
import { DeepReadonly } from 'ts-essentials';
|
||||
|
||||
import { logger } from '../../../classes/Logger.js';
|
||||
|
||||
import { parseTemplateNested } from '../automation.utils.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { LogOrigin, OntimeAction } from 'ontime-types';
|
||||
import { parseUserTime } from 'ontime-utils';
|
||||
|
||||
import { logger } from '../../../classes/Logger.js';
|
||||
import { auxTimerService } from '../../../services/aux-timer-service/AuxTimerService.js';
|
||||
import * as messageService from '../../../services/message-service/message.service.js';
|
||||
import { parseUserTime } from 'ontime-utils';
|
||||
|
||||
export function toOntimeAction(action: OntimeAction) {
|
||||
const actionType = action.action;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { LogOrigin, OSCOutput, RuntimeStore } from 'ontime-types';
|
||||
|
||||
import { type OscPacketInput, toBuffer as oscPacketToBuffer } from 'osc-min';
|
||||
import * as dgram from 'node:dgram';
|
||||
|
||||
import { LogOrigin, OSCOutput, RuntimeStore } from 'ontime-types';
|
||||
import { type OscPacketInput, toBuffer as oscPacketToBuffer } from 'osc-min';
|
||||
import { DeepReadonly } from 'ts-essentials';
|
||||
|
||||
import { logger } from '../../../classes/Logger.js';
|
||||
import { parseTemplateNested, stringToOSCArgs } from '../automation.utils.js';
|
||||
import { DeepReadonly } from 'ts-essentials';
|
||||
|
||||
const udpClient = dgram.createSocket('udp4');
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DatabaseModel, CustomFields, CustomField } from 'ontime-types';
|
||||
import { CustomField, CustomFields, DatabaseModel } from 'ontime-types';
|
||||
import { checkRegex, customFieldLabelToKey } from 'ontime-utils';
|
||||
|
||||
import type { ErrorEmitter } from '../../utils/parserUtils.js';
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
import { CustomField, CustomFields, ErrorResponse } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
|
||||
import { getProjectCustomFields } from '../rundown/rundown.dao.js';
|
||||
import { createCustomField, editCustomField, deleteCustomField } from '../rundown/rundown.service.js';
|
||||
|
||||
import { createCustomField, deleteCustomField, editCustomField } from '../rundown/rundown.service.js';
|
||||
import { validateCustomField, validateDeleteCustomField, validateEditCustomField } from './customFields.validation.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { body, param } from 'express-validator';
|
||||
import { checkRegex } from 'ontime-utils';
|
||||
|
||||
import { body, param } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const validateCustomField = [
|
||||
|
||||
@@ -3,21 +3,18 @@
|
||||
import { SupportedEntry } from 'ontime-types';
|
||||
|
||||
import { demoDb } from '../../../models/demoProject.js';
|
||||
|
||||
import { parseDatabaseModel } from '../db.parser.js';
|
||||
|
||||
// mock data provider
|
||||
beforeAll(() => {
|
||||
vi.mock('../../classes/data-provider/DataProvider.js', () => {
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
setRundown: vi.fn().mockImplementation((newData) => newData),
|
||||
setCustomFields: vi.fn().mockImplementation((newData) => newData),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
vi.mock('../../classes/data-provider/DataProvider.js', () => {
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
setRundown: vi.fn().mockImplementation((newData) => newData),
|
||||
setCustomFields: vi.fn().mockImplementation((newData) => newData),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
describe('test parseDatabaseModel() with demo project (valid)', () => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Request, Response } from 'express';
|
||||
import {
|
||||
DatabaseModel,
|
||||
ErrorResponse,
|
||||
@@ -7,17 +8,15 @@ import {
|
||||
TimeFormat,
|
||||
} from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import sanitize from 'sanitize-filename';
|
||||
|
||||
import { getPartialProject } from '../../models/dataModel.js';
|
||||
import * as projectService from '../../services/project-service/ProjectService.js';
|
||||
import {
|
||||
doesProjectExist,
|
||||
handleImageUpload,
|
||||
handleProjectUploaded,
|
||||
} from '../../services/project-service/projectServiceUtils.js';
|
||||
import * as projectService from '../../services/project-service/ProjectService.js';
|
||||
import { getPartialProject } from '../../models/dataModel.js';
|
||||
|
||||
export async function patchPartialProjectFile(req: Request, res: Response<DatabaseModel | ErrorResponse>) {
|
||||
try {
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { DatabaseModel, LogOrigin } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import { logger } from '../../classes/Logger.js';
|
||||
|
||||
import { portManager } from '../../classes/port-manager/PortManager.js';
|
||||
import { parseAutomationSettings } from '../automation/automation.parser.js';
|
||||
import { parseCustomFields } from '../custom-fields/customFields.parser.js';
|
||||
import { parseProjectData } from '../project-data/projectData.parser.js';
|
||||
import { parseRundowns } from '../rundown/rundown.parser.js';
|
||||
import { parseSettings } from '../settings/settings.parser.js';
|
||||
import { parseUrlPresets } from '../url-presets/urlPresets.parser.js';
|
||||
import { parseViewSettings } from '../view-settings/viewSettings.parser.js';
|
||||
import { parseCustomFields } from '../custom-fields/customFields.parser.js';
|
||||
import * as v3 from './migration/db.migration.v3.js';
|
||||
import * as v4 from './migration/db.migration.v4.js';
|
||||
import { portManager } from '../../classes/port-manager/PortManager.js';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
type ParsingError = {
|
||||
context: string;
|
||||
@@ -32,7 +31,6 @@ export function parseDatabaseModel(
|
||||
errors: ParsingError[];
|
||||
migrated: boolean;
|
||||
} {
|
||||
|
||||
let migrated = false;
|
||||
let migratedData = jsonData;
|
||||
const errors: ParsingError[] = [];
|
||||
@@ -46,11 +44,9 @@ export function parseDatabaseModel(
|
||||
logger.error(LogOrigin.Server, 'Failed to migrate the data');
|
||||
errors.push({ context: 'v3 migration', message: getErrorMessage(error) });
|
||||
migratedData = jsonData;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (v4.shouldMigrateServerPort(migratedData)) {
|
||||
try {
|
||||
migrated = true;
|
||||
@@ -62,7 +58,6 @@ export function parseDatabaseModel(
|
||||
logger.error(LogOrigin.Server, 'Failed to migrate serverPort');
|
||||
errors.push({ context: 'v4 migration', message: getErrorMessage(error) });
|
||||
migratedData = jsonData;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@ import {
|
||||
} from './db.controller.js';
|
||||
import { uploadProjectFile } from './db.middleware.js';
|
||||
import {
|
||||
validateNewProject,
|
||||
validatePatchProject,
|
||||
validateFilenameBody,
|
||||
validateFilenameParam,
|
||||
validateNewFilenameBody,
|
||||
validateNewProject,
|
||||
validatePatchProject,
|
||||
validateQuickProject,
|
||||
} from './db.validation.js';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { body, param } from 'express-validator';
|
||||
import sanitize from 'sanitize-filename';
|
||||
|
||||
import { ensureJsonExtension } from '../../utils/fileManagement.js';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
EndAction,
|
||||
EntryCustomFields,
|
||||
NormalisedAutomation,
|
||||
OntimeGroup,
|
||||
OntimeEntry,
|
||||
OntimeGroup,
|
||||
ProjectData,
|
||||
ProjectRundowns,
|
||||
Rundown,
|
||||
@@ -19,15 +19,15 @@ import {
|
||||
Day,
|
||||
} from 'ontime-types';
|
||||
import {
|
||||
customFieldLabelToKey,
|
||||
checkRegex,
|
||||
customFieldLabelToKey,
|
||||
eventDef as eventModel,
|
||||
isKnownTimerType,
|
||||
validateEndAction,
|
||||
eventDef as eventModel,
|
||||
} from 'ontime-utils';
|
||||
|
||||
import { is } from '../../../utils/is.js';
|
||||
import { getPartialProject } from '../../../models/dataModel.js';
|
||||
import { is } from '../../../utils/is.js';
|
||||
|
||||
// the methodology of the migrations is to just change the necessary keys to match with v4
|
||||
// and then let the normal project parser handle ensuring the the file is correct
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { DatabaseModel, Settings } from 'ontime-types';
|
||||
|
||||
import { is } from '../../../utils/is.js';
|
||||
|
||||
export function shouldMigrateServerPort(jsonData: object): boolean {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
AutomationSettings,
|
||||
CustomFields,
|
||||
type Day,
|
||||
DatabaseModel,
|
||||
EndAction,
|
||||
OntimeView,
|
||||
@@ -8,12 +9,13 @@ import {
|
||||
Rundown,
|
||||
Settings,
|
||||
SupportedEntry,
|
||||
TimeStrategy,
|
||||
TimerLifeCycle,
|
||||
TimerType,
|
||||
TimeStrategy,
|
||||
URLPreset,
|
||||
ViewSettings,
|
||||
} from 'ontime-types';
|
||||
|
||||
import * as v3 from './db.migration.v3.js';
|
||||
import * as v4 from './db.migration.v4.js';
|
||||
|
||||
@@ -295,7 +297,7 @@ describe('v3 to v4', () => {
|
||||
flag: false,
|
||||
parent: null,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
gap: 0,
|
||||
},
|
||||
group0: {
|
||||
@@ -340,7 +342,7 @@ describe('v3 to v4', () => {
|
||||
parent: 'group0',
|
||||
revision: -1,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
gap: 0,
|
||||
},
|
||||
event3: {
|
||||
@@ -371,7 +373,7 @@ describe('v3 to v4', () => {
|
||||
parent: 'group0',
|
||||
revision: -1,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
gap: 0,
|
||||
},
|
||||
group1: {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { CustomFields, OntimeEvent, OntimeGroup, SupportedEntry, TimerType } from 'ontime-types';
|
||||
import { ImportMap, MILLIS_PER_MINUTE, millisToString } from 'ontime-utils';
|
||||
|
||||
import { parseExcel } from '../excel.parser.js';
|
||||
|
||||
import { dataFromExcelTemplate } from './mockData.js';
|
||||
import { simpleTemplate } from '../__mocks__/simpleTemplate.js';
|
||||
import { parseExcel } from '../excel.parser.js';
|
||||
import { dataFromExcelTemplate } from './mockData.js';
|
||||
|
||||
describe('parseExcel()', () => {
|
||||
it('parses the simple template file', () => {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { CustomFields } from 'ontime-types';
|
||||
import { defaultImportMap, ImportMap } from 'ontime-utils';
|
||||
import { ImportMap, defaultImportMap } from 'ontime-utils';
|
||||
|
||||
import { demoDb } from '../../../models/demoProject.js';
|
||||
|
||||
import { getCustomFieldData, rundownToTabular } from '../excel.utils.js';
|
||||
|
||||
describe('getCustomFieldData()', () => {
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { Request } from 'express';
|
||||
import multer, { type FileFilterCallback } from 'multer';
|
||||
|
||||
import { storage } from '../../utils/upload.js';
|
||||
|
||||
import { EXCEL_MIME } from './excel.constants.js';
|
||||
|
||||
const filterExcel = (_req: Request, file: Express.Multer.File, cb: FileFilterCallback) => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {
|
||||
CustomFields,
|
||||
Rundown,
|
||||
EntryCustomFields,
|
||||
OntimeEntry,
|
||||
OntimeEvent,
|
||||
OntimeGroup,
|
||||
EntryCustomFields,
|
||||
SupportedEntry,
|
||||
isOntimeGroup,
|
||||
TimerType,
|
||||
OntimeMilestone,
|
||||
OntimeEntry,
|
||||
Rundown,
|
||||
SupportedEntry,
|
||||
TimerType,
|
||||
isOntimeGroup,
|
||||
isOntimeMilestone,
|
||||
} from 'ontime-types';
|
||||
import {
|
||||
@@ -16,16 +16,15 @@ import {
|
||||
defaultImportMap,
|
||||
generateId,
|
||||
isKnownTimerType,
|
||||
validateTimerType,
|
||||
validateEndAction,
|
||||
makeString,
|
||||
validateEndAction,
|
||||
validateTimerType,
|
||||
} from 'ontime-utils';
|
||||
|
||||
import { Prettify } from 'ts-essentials';
|
||||
|
||||
import { is } from '../../utils/is.js';
|
||||
import { parseExcelDate } from '../../utils/time.js';
|
||||
import { generateImportHandlers, getCustomFieldData, parseBooleanString, SheetMetadata } from './excel.utils.js';
|
||||
import { SheetMetadata, generateImportHandlers, getCustomFieldData, parseBooleanString } from './excel.utils.js';
|
||||
|
||||
type MergedOntimeEntry = Prettify<
|
||||
Omit<Omit<Omit<OntimeEvent, keyof OntimeGroup> & OntimeGroup, keyof OntimeMilestone> & OntimeMilestone, 'type'> & {
|
||||
|
||||
@@ -3,13 +3,11 @@ import type { Request, Response } from 'express';
|
||||
import { CustomFields, ErrorResponse, Rundown, RundownSummary } from 'ontime-types';
|
||||
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
|
||||
import { getProjectCustomFields } from '../rundown/rundown.dao.js';
|
||||
|
||||
import { uploadExcel } from './excel.middleware.js';
|
||||
import { validateFileExists, validateImportMapOptions, validateRundownExport } from './excel.validation.js';
|
||||
import { generateExcelFile, generateRundownPreview, readExcelFile } from './excel.service.js';
|
||||
import { EXCEL_MIME } from './excel.constants.js';
|
||||
import { uploadExcel } from './excel.middleware.js';
|
||||
import { generateExcelFile, generateRundownPreview, readExcelFile } from './excel.service.js';
|
||||
import { validateFileExists, validateImportMapOptions, validateRundownExport } from './excel.validation.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
|
||||
@@ -3,20 +3,18 @@
|
||||
* Google Sheets
|
||||
*/
|
||||
|
||||
import { existsSync } from 'fs';
|
||||
import { extname } from 'path';
|
||||
|
||||
import { CustomFields, Rundown, RundownSummary } from 'ontime-types';
|
||||
import { type ImportMap } from 'ontime-utils';
|
||||
|
||||
import { extname } from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
import xlsx from 'xlsx';
|
||||
import type { WorkBook } from 'xlsx';
|
||||
|
||||
import { deleteFile } from '../../utils/fileManagement.js';
|
||||
|
||||
import { parseRundown } from '../rundown/rundown.parser.js';
|
||||
import { getProjectCustomFields, processRundown } from '../rundown/rundown.dao.js';
|
||||
import { parseCustomFields } from '../custom-fields/customFields.parser.js';
|
||||
|
||||
import { getProjectCustomFields, processRundown } from '../rundown/rundown.dao.js';
|
||||
import { parseRundown } from '../rundown/rundown.parser.js';
|
||||
import { parseExcel } from './excel.parser.js';
|
||||
import { rundownToTabular } from './excel.utils.js';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CustomFieldKey, CustomFields, MaybeNumber, OntimeEntry, Rundown } from 'ontime-types';
|
||||
import { checkRegex, customFieldLabelToKey, ImportMap, millisToString } from 'ontime-utils';
|
||||
import { ImportMap, checkRegex, customFieldLabelToKey, millisToString } from 'ontime-utils';
|
||||
|
||||
/**
|
||||
* Receives an import map which contains custom field labels and a custom fields object
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isImportMap } from 'ontime-utils';
|
||||
|
||||
import { body, param } from 'express-validator';
|
||||
import { isImportMap } from 'ontime-utils';
|
||||
|
||||
import {
|
||||
requestValidationFunction,
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import express from 'express';
|
||||
|
||||
import { router as assetsRouter } from './assets/assets.router.js';
|
||||
import { router as automationsRouter } from './automation/automation.router.js';
|
||||
import { router as urlPresetsRouter } from './url-presets/urlPresets.router.js';
|
||||
import { router as customFieldsRouter } from './custom-fields/customFields.router.js';
|
||||
import { router as dbRouter } from './db/db.router.js';
|
||||
import { router as excelRouter } from './excel/excel.router.js';
|
||||
import { router as projectRouter } from './project-data/projectData.router.js';
|
||||
import { router as reportRouter } from './report/report.router.js';
|
||||
import { router as rundownsRouter } from './rundown/rundown.router.js';
|
||||
import { router as sessionRouter } from './session/session.router.js';
|
||||
import { router as settingsRouter } from './settings/settings.router.js';
|
||||
import { router as sheetsRouter } from './sheets/sheets.router.js';
|
||||
import { router as excelRouter } from './excel/excel.router.js';
|
||||
import { router as sessionRouter } from './session/session.router.js';
|
||||
import { router as urlPresetsRouter } from './url-presets/urlPresets.router.js';
|
||||
import { router as viewSettingsRouter } from './view-settings/viewSettings.router.js';
|
||||
import { router as reportRouter } from './report/report.router.js';
|
||||
import { router as assetsRouter } from './assets/assets.router.js';
|
||||
|
||||
export const appRouter = express.Router();
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { ProjectData, RefetchKey } from 'ontime-types';
|
||||
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { join } from 'node:path';
|
||||
import { deleteFile } from '../../utils/fileManagement.js';
|
||||
import { publicDir } from '../../setup/index.js';
|
||||
import { sendRefetch } from '../../adapters/WebsocketAdapter.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { publicDir } from '../../setup/index.js';
|
||||
import { deleteFile } from '../../utils/fileManagement.js';
|
||||
|
||||
/**
|
||||
* Gets the stored project data
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DatabaseModel, ProjectData } from 'ontime-types';
|
||||
|
||||
import { ErrorEmitter } from '../../utils/parserUtils.js';
|
||||
import { getPartialProject } from '../../models/dataModel.js';
|
||||
import { ErrorEmitter } from '../../utils/parserUtils.js';
|
||||
|
||||
/**
|
||||
* Parse event portion of an entry
|
||||
|
||||
@@ -3,11 +3,11 @@ import type { Request, Response } from 'express';
|
||||
import type { ErrorResponse, ProjectData } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import { projectSanitiser } from './projectData.validation.js';
|
||||
import { uploadImageFile } from '../db/db.middleware.js';
|
||||
import { postProjectLogo } from '../db/db.controller.js';
|
||||
import * as projectDao from './projectData.dao.js';
|
||||
import { removeUndefined } from '../../utils/parserUtils.js';
|
||||
import { postProjectLogo } from '../db/db.controller.js';
|
||||
import { uploadImageFile } from '../db/db.middleware.js';
|
||||
import * as projectDao from './projectData.dao.js';
|
||||
import { projectSanitiser } from './projectData.validation.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { body } from 'express-validator';
|
||||
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const projectSanitiser = [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
import { paramsWithId } from '../validation-utils/validationFunction.js';
|
||||
import * as report from './report.service.js';
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { OntimeReport, OntimeEventReport, TimerLifeCycle, RefetchKey } from 'ontime-types';
|
||||
import { RuntimeState } from '../../stores/runtimeState.js';
|
||||
import { OntimeEventReport, OntimeReport, RefetchKey, TimerLifeCycle } from 'ontime-types';
|
||||
import { DeepReadonly } from 'ts-essentials';
|
||||
|
||||
import { sendRefetch } from '../../adapters/WebsocketAdapter.js';
|
||||
import { RuntimeState } from '../../stores/runtimeState.js';
|
||||
|
||||
const report = new Map<string, OntimeEventReport>();
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import {
|
||||
SupportedEntry,
|
||||
OntimeEvent,
|
||||
OntimeDelay,
|
||||
OntimeGroup,
|
||||
Rundown,
|
||||
CustomField,
|
||||
OntimeDelay,
|
||||
OntimeEvent,
|
||||
OntimeGroup,
|
||||
OntimeMilestone,
|
||||
Rundown,
|
||||
SupportedEntry,
|
||||
} from 'ontime-types';
|
||||
|
||||
import { makeNewRundown } from '../../../models/dataModel.js';
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import {
|
||||
type Day,
|
||||
CustomFields,
|
||||
OntimeGroup,
|
||||
OntimeDelay,
|
||||
OntimeEvent,
|
||||
OntimeGroup,
|
||||
OntimeMilestone,
|
||||
SupportedEntry,
|
||||
TimeStrategy,
|
||||
OntimeMilestone,
|
||||
} from 'ontime-types';
|
||||
import { dayInMs, MILLIS_PER_HOUR, MILLIS_PER_MINUTE } from 'ontime-utils';
|
||||
import { MILLIS_PER_HOUR, MILLIS_PER_MINUTE, dayInMs } from 'ontime-utils';
|
||||
|
||||
import { demoDb } from '../../../models/demoProject.js';
|
||||
import {
|
||||
makeOntimeEvent,
|
||||
makeRundown,
|
||||
makeOntimeGroup,
|
||||
makeOntimeDelay,
|
||||
makeCustomField,
|
||||
makeOntimeDelay,
|
||||
makeOntimeEvent,
|
||||
makeOntimeGroup,
|
||||
makeOntimeMilestone,
|
||||
makeRundown,
|
||||
} from '../__mocks__/rundown.mocks.js';
|
||||
|
||||
import {
|
||||
createTransaction,
|
||||
customFieldMutation,
|
||||
@@ -25,23 +26,20 @@ import {
|
||||
rundownCache,
|
||||
rundownMutation,
|
||||
} from '../rundown.dao.js';
|
||||
import { demoDb } from '../../../models/demoProject.js';
|
||||
import { type ProcessedRundownMetadata } from '../rundown.parser.js';
|
||||
|
||||
const setRundownMock = vi.fn();
|
||||
const setCustomFieldsMock = vi.fn();
|
||||
|
||||
beforeAll(() => {
|
||||
vi.mock('../../../classes/data-provider/DataProvider.js', () => {
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
setRundown: setRundownMock,
|
||||
setCustomFields: setCustomFieldsMock,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
vi.mock('../../../classes/data-provider/DataProvider.js', () => {
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
setRundown: setRundownMock,
|
||||
setCustomFields: setCustomFieldsMock,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
@@ -100,6 +98,7 @@ describe('processRundown()', () => {
|
||||
Object.keys(result?.entries ?? {}).length,
|
||||
'events',
|
||||
);
|
||||
expect(t2 - t1).lessThan(100);
|
||||
});
|
||||
|
||||
it('generates metadata from given rundown', () => {
|
||||
@@ -1345,7 +1344,7 @@ describe('rundownMutation.applyDelay()', () => {
|
||||
'1': makeOntimeEvent({
|
||||
id: '1',
|
||||
gap: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
timeStart: 46800000, // 13:00:00
|
||||
timeEnd: 50400000, // 14:00:00
|
||||
duration: MILLIS_PER_HOUR,
|
||||
@@ -1354,7 +1353,7 @@ describe('rundownMutation.applyDelay()', () => {
|
||||
'2': makeOntimeEvent({
|
||||
id: '2',
|
||||
gap: 1 * MILLIS_PER_HOUR,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
timeStart: 54000000, // 15:00:00
|
||||
timeEnd: 57600000, // 16:00:00
|
||||
duration: MILLIS_PER_HOUR,
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { SupportedEntry, OntimeEvent, OntimeGroup, Rundown, CustomFields } from 'ontime-types';
|
||||
import { CustomFields, OntimeEvent, OntimeGroup, Rundown, SupportedEntry } from 'ontime-types';
|
||||
|
||||
import { makeNewRundown } from '../../../models/dataModel.js';
|
||||
|
||||
import { makeOntimeGroup, makeOntimeEvent, makeOntimeMilestone } from '../__mocks__/rundown.mocks.js';
|
||||
import { parseRundowns, parseRundown, sanitiseCustomFields } from '../rundown.parser.js';
|
||||
import { makeOntimeEvent, makeOntimeGroup, makeOntimeMilestone } from '../__mocks__/rundown.mocks.js';
|
||||
import { parseRundown, parseRundowns, sanitiseCustomFields } from '../rundown.parser.js';
|
||||
|
||||
describe('parseRundowns()', () => {
|
||||
it('returns a default project rundown if nothing is given', () => {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { TimeStrategy, EndAction, TimerType, OntimeEvent } from 'ontime-types';
|
||||
import { createEvent, MILLIS_PER_HOUR } from 'ontime-utils';
|
||||
|
||||
import { EndAction, OntimeEvent, TimeStrategy, TimerType } from 'ontime-types';
|
||||
import { MILLIS_PER_HOUR, createEvent } from 'ontime-utils';
|
||||
import { assertType } from 'vitest';
|
||||
|
||||
import { demoDb } from '../../../models/demoProject.js';
|
||||
|
||||
import { makeOntimeEvent, makeOntimeGroup, makeRundown } from '../__mocks__/rundown.mocks.js';
|
||||
import {
|
||||
calculateDayOffset,
|
||||
deleteById,
|
||||
@@ -13,7 +12,6 @@ import {
|
||||
hasChanges,
|
||||
makeDeepClone,
|
||||
} from '../rundown.utils.js';
|
||||
import { makeOntimeGroup, makeOntimeEvent, makeRundown } from '../__mocks__/rundown.mocks.js';
|
||||
|
||||
describe('test event validator', () => {
|
||||
it('validates a good object', () => {
|
||||
|
||||
@@ -15,22 +15,22 @@ import {
|
||||
CustomFieldKey,
|
||||
CustomFields,
|
||||
EntryId,
|
||||
isOntimeGroup,
|
||||
isOntimeEvent,
|
||||
isPlayableEvent,
|
||||
OntimeGroup,
|
||||
InsertOptions,
|
||||
OntimeDelay,
|
||||
OntimeEntry,
|
||||
OntimeEvent,
|
||||
OntimeGroup,
|
||||
PatchWithId,
|
||||
Rundown,
|
||||
InsertOptions,
|
||||
isOntimeEvent,
|
||||
isOntimeGroup,
|
||||
isPlayableEvent,
|
||||
} from 'ontime-types';
|
||||
import { addToRundown, customFieldLabelToKey, getInsertAfterId, insertAtIndex, createGroup } from 'ontime-utils';
|
||||
import { addToRundown, createGroup, customFieldLabelToKey, getInsertAfterId, insertAtIndex } from 'ontime-utils';
|
||||
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { consoleError } from '../../utils/console.js';
|
||||
|
||||
import { ProcessedRundownMetadata, makeRundownMetadata } from './rundown.parser.js';
|
||||
import type { RundownMetadata } from './rundown.types.js';
|
||||
import {
|
||||
applyPatchToEntry,
|
||||
@@ -40,7 +40,6 @@ import {
|
||||
getUniqueId,
|
||||
makeDeepClone,
|
||||
} from './rundown.utils.js';
|
||||
import { makeRundownMetadata, ProcessedRundownMetadata } from './rundown.parser.js';
|
||||
|
||||
/**
|
||||
* The currently loaded rundown in cache
|
||||
|
||||
@@ -1,40 +1,39 @@
|
||||
import {
|
||||
DatabaseModel,
|
||||
CustomFields,
|
||||
ProjectRundowns,
|
||||
Rundown,
|
||||
OntimeEvent,
|
||||
isOntimeEvent,
|
||||
isOntimeDelay,
|
||||
isOntimeGroup,
|
||||
CustomFieldKey,
|
||||
CustomFields,
|
||||
DatabaseModel,
|
||||
Day,
|
||||
EntryId,
|
||||
OntimeEntry,
|
||||
PlayableEvent,
|
||||
RundownEntries,
|
||||
isPlayableEvent,
|
||||
isOntimeMilestone,
|
||||
OntimeMilestone,
|
||||
OntimeEvent,
|
||||
OntimeGroup,
|
||||
Day,
|
||||
OntimeMilestone,
|
||||
PlayableEvent,
|
||||
ProjectRundowns,
|
||||
Rundown,
|
||||
RundownEntries,
|
||||
isOntimeDelay,
|
||||
isOntimeEvent,
|
||||
isOntimeGroup,
|
||||
isOntimeMilestone,
|
||||
isPlayableEvent,
|
||||
} from 'ontime-types';
|
||||
import {
|
||||
isObjectEmpty,
|
||||
generateId,
|
||||
getLinkedTimes,
|
||||
getTimeFrom,
|
||||
isNewLatest,
|
||||
createDelay,
|
||||
createEvent,
|
||||
createGroup,
|
||||
createMilestone,
|
||||
generateId,
|
||||
getLinkedTimes,
|
||||
getTimeFrom,
|
||||
isNewLatest,
|
||||
isObjectEmpty,
|
||||
} from 'ontime-utils';
|
||||
|
||||
import { makeNewRundown } from '../../models/dataModel.js';
|
||||
import type { ErrorEmitter } from '../../utils/parserUtils.js';
|
||||
|
||||
import { calculateDayOffset, cleanupCustomFields } from './rundown.utils.js';
|
||||
import { RundownMetadata } from './rundown.types.js';
|
||||
import { calculateDayOffset, cleanupCustomFields } from './rundown.utils.js';
|
||||
|
||||
/**
|
||||
* Parse a rundowns object along with the project custom fields
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import type { Request, Response } from 'express';
|
||||
import express from 'express';
|
||||
import { ErrorResponse, OntimeEntry, ProjectRundownsList, Rundown } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import express from 'express';
|
||||
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { makeNewRundown } from '../../models/dataModel.js';
|
||||
|
||||
import { paramsWithId } from '../validation-utils/validationFunction.js';
|
||||
|
||||
import { getCurrentRundown } from './rundown.dao.js';
|
||||
import {
|
||||
addEntry,
|
||||
@@ -20,23 +17,23 @@ import {
|
||||
editEntry,
|
||||
groupEntries,
|
||||
initRundown,
|
||||
loadRundown,
|
||||
reorderEntry,
|
||||
swapEvents,
|
||||
loadRundown,
|
||||
ungroupEntries,
|
||||
} from './rundown.service.js';
|
||||
import { duplicateRundown, normalisedToRundownArray } from './rundown.utils.js';
|
||||
import {
|
||||
rundownArrayOfIds,
|
||||
clonePostValidator,
|
||||
entryBatchPutValidator,
|
||||
entryPostValidator,
|
||||
rundownPostValidator,
|
||||
entryPutValidator,
|
||||
entryReorderValidator,
|
||||
entrySwapValidator,
|
||||
rundownArrayOfIds,
|
||||
rundownPostValidator,
|
||||
validateRundownMutation,
|
||||
clonePostValidator,
|
||||
} from './rundown.validation.js';
|
||||
import { duplicateRundown, normalisedToRundownArray } from './rundown.utils.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
|
||||
@@ -4,26 +4,26 @@ import {
|
||||
CustomFields,
|
||||
EntryId,
|
||||
EventPostPayload,
|
||||
isOntimeGroup,
|
||||
isOntimeDelay,
|
||||
isOntimeEvent,
|
||||
OntimeGroup,
|
||||
InsertOptions,
|
||||
LogOrigin,
|
||||
OntimeEntry,
|
||||
OntimeGroup,
|
||||
PatchWithId,
|
||||
ProjectRundowns,
|
||||
RefetchKey,
|
||||
Rundown,
|
||||
LogOrigin,
|
||||
ProjectRundowns,
|
||||
InsertOptions,
|
||||
isOntimeDelay,
|
||||
isOntimeEvent,
|
||||
isOntimeGroup,
|
||||
} from 'ontime-types';
|
||||
import { customFieldLabelToKey, getInsertAfterId, resolveInsertParent } from 'ontime-utils';
|
||||
|
||||
import { updateRundownData } from '../../stores/runtimeState.js';
|
||||
import { runtimeService } from '../../services/runtime-service/runtime.service.js';
|
||||
import { sendRefetch } from '../../adapters/WebsocketAdapter.js';
|
||||
import { setLastLoadedRundown } from '../../services/app-state-service/AppStateService.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { logger } from '../../classes/Logger.js';
|
||||
|
||||
import { setLastLoadedRundown } from '../../services/app-state-service/AppStateService.js';
|
||||
import { runtimeService } from '../../services/runtime-service/runtime.service.js';
|
||||
import { updateRundownData } from '../../stores/runtimeState.js';
|
||||
import {
|
||||
createTransaction,
|
||||
customFieldMutation,
|
||||
@@ -34,7 +34,6 @@ import {
|
||||
} from './rundown.dao.js';
|
||||
import type { RundownMetadata } from './rundown.types.js';
|
||||
import { generateEvent, hasChanges } from './rundown.utils.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
|
||||
/**
|
||||
* creates a new entry with given data
|
||||
|
||||
@@ -2,30 +2,30 @@ import {
|
||||
CustomFields,
|
||||
EntryCustomFields,
|
||||
EntryId,
|
||||
isOntimeGroup,
|
||||
isOntimeDelay,
|
||||
isOntimeEvent,
|
||||
isOntimeMilestone,
|
||||
OntimeBaseEvent,
|
||||
OntimeGroup,
|
||||
OntimeDelay,
|
||||
OntimeEntry,
|
||||
OntimeEvent,
|
||||
OntimeGroup,
|
||||
OntimeMilestone,
|
||||
ProjectRundown,
|
||||
ProjectRundowns,
|
||||
Rundown,
|
||||
SupportedEntry,
|
||||
TimeStrategy,
|
||||
ProjectRundown,
|
||||
ProjectRundowns,
|
||||
isOntimeDelay,
|
||||
isOntimeEvent,
|
||||
isOntimeGroup,
|
||||
isOntimeMilestone,
|
||||
} from 'ontime-types';
|
||||
import {
|
||||
dayInMs,
|
||||
generateId,
|
||||
getCueCandidate,
|
||||
createDelay,
|
||||
createEvent,
|
||||
createGroup,
|
||||
createMilestone,
|
||||
dayInMs,
|
||||
generateId,
|
||||
getCueCandidate,
|
||||
makeString,
|
||||
validateEndAction,
|
||||
validateTimerType,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import type { NextFunction, Request, Response } from 'express';
|
||||
import { body, param } from 'express-validator';
|
||||
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
import type { ErrorResponse, GetInfo, GetUrl, SessionStats } from 'ontime-types';
|
||||
import { validateGenerateUrl } from './session.validation.js';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import * as sessionService from './session.service.js';
|
||||
import { validateGenerateUrl } from './session.validation.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { GetInfo, LinkOptions, OntimeView, SessionStats } from 'ontime-types';
|
||||
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { publicDir } from '../../setup/index.js';
|
||||
import { socket } from '../../adapters/WebsocketAdapter.js';
|
||||
import { getLastRequest } from '../../api-integration/integration.controller.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { portManager } from '../../classes/port-manager/PortManager.js';
|
||||
import { password, routerPrefix } from '../../externals.js';
|
||||
import { ONTIME_VERSION } from '../../ONTIME_VERSION.js';
|
||||
import { getCurrentProject } from '../../services/project-service/ProjectService.js';
|
||||
import { runtimeService } from '../../services/runtime-service/runtime.service.js';
|
||||
import { publicDir } from '../../setup/index.js';
|
||||
import { hashPassword } from '../../utils/hash.js';
|
||||
import { getNetworkInterfaces } from '../../utils/network.js';
|
||||
import { getTimezoneLabel } from '../../utils/time.js';
|
||||
import { password, routerPrefix } from '../../externals.js';
|
||||
import { hashPassword } from '../../utils/hash.js';
|
||||
import { ONTIME_VERSION } from '../../ONTIME_VERSION.js';
|
||||
import { portManager } from '../../classes/port-manager/PortManager.js';
|
||||
|
||||
const startedAt = new Date();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { body } from 'express-validator';
|
||||
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const validateGenerateUrl = [
|
||||
|
||||
@@ -4,7 +4,7 @@ import { parseSettings } from '../settings.parser.js';
|
||||
|
||||
describe('parseSettings()', () => {
|
||||
it('throws if settings object does not exist', () => {
|
||||
expect(() => parseSettings({})).toThrow();
|
||||
expect(() => parseSettings({})).toThrow('ERROR: unable to parse settings, missing or incorrect version');
|
||||
});
|
||||
|
||||
it('returns an a base model as long as we have the app version', () => {
|
||||
|
||||
@@ -1,29 +1,24 @@
|
||||
import express from "express";
|
||||
import { matchedData } from "express-validator";
|
||||
import type { Request, Response } from "express";
|
||||
import { deepEqual } from "fast-equals";
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
import { matchedData } from 'express-validator';
|
||||
import { deepEqual } from 'fast-equals';
|
||||
import { ErrorResponse, PortInfo, RefetchKey, Settings } from 'ontime-types';
|
||||
import { getErrorMessage, obfuscate } from 'ontime-utils';
|
||||
|
||||
import { ErrorResponse, PortInfo, RefetchKey, Settings } from "ontime-types";
|
||||
import { getErrorMessage, obfuscate } from "ontime-utils";
|
||||
|
||||
import {
|
||||
validateSettings,
|
||||
validateWelcomeDialog,
|
||||
validateServerPort,
|
||||
} from "./settings.validation.js";
|
||||
import { getDataProvider } from "../../classes/data-provider/DataProvider.js";
|
||||
import * as appState from "../../services/app-state-service/AppStateService.js";
|
||||
import { sendRefetch } from "../../adapters/WebsocketAdapter.js";
|
||||
import { portManager } from "../../classes/port-manager/PortManager.js";
|
||||
import { sendRefetch } from '../../adapters/WebsocketAdapter.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { portManager } from '../../classes/port-manager/PortManager.js';
|
||||
import * as appState from '../../services/app-state-service/AppStateService.js';
|
||||
import { validateSettings, validateWelcomeDialog, validateServerPort } from './settings.validation.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
router.post("/welcomedialog", validateWelcomeDialog, async (req: Request, res: Response) => {
|
||||
router.post('/welcomedialog', validateWelcomeDialog, async (req: Request, res: Response) => {
|
||||
const show = await appState.setShowWelcomeDialog(req.body.show);
|
||||
res.status(200).json({ show });
|
||||
});
|
||||
|
||||
router.get("/", (_req: Request, res: Response<Settings>) => {
|
||||
router.get('/', (_req: Request, res: Response<Settings>) => {
|
||||
const settings = getDataProvider().getSettings();
|
||||
const obfuscatedSettings = { ...settings };
|
||||
if (settings.editorKey) {
|
||||
@@ -37,30 +32,26 @@ router.get("/", (_req: Request, res: Response<Settings>) => {
|
||||
res.status(200).json(obfuscatedSettings);
|
||||
});
|
||||
|
||||
router.post(
|
||||
"/",
|
||||
validateSettings,
|
||||
async (req: Request, res: Response<Settings | ErrorResponse>) => {
|
||||
try {
|
||||
const data = matchedData<Settings>(req);
|
||||
const settings = getDataProvider().getSettings();
|
||||
router.post('/', validateSettings, async (req: Request, res: Response<Settings | ErrorResponse>) => {
|
||||
try {
|
||||
const data = matchedData<Settings>(req);
|
||||
const settings = getDataProvider().getSettings();
|
||||
|
||||
data.version = settings.version;
|
||||
data.version = settings.version;
|
||||
|
||||
if (!deepEqual(data, settings)) {
|
||||
await getDataProvider().setSettings(data);
|
||||
sendRefetch(RefetchKey.Settings);
|
||||
}
|
||||
|
||||
res.status(200).json(data);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(400).json({ message });
|
||||
if (!deepEqual(data, settings)) {
|
||||
await getDataProvider().setSettings(data);
|
||||
sendRefetch(RefetchKey.Settings);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
router.get("/serverport", (_req: Request, res: Response<PortInfo | ErrorResponse>) => {
|
||||
res.status(200).json(data);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(400).json({ message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/serverport', (_req: Request, res: Response<PortInfo | ErrorResponse>) => {
|
||||
try {
|
||||
const { port, pendingRestart } = portManager.getPort();
|
||||
res.status(200).json({ port, pendingRestart });
|
||||
@@ -70,19 +61,15 @@ router.get("/serverport", (_req: Request, res: Response<PortInfo | ErrorResponse
|
||||
}
|
||||
});
|
||||
|
||||
router.post(
|
||||
"/serverport",
|
||||
validateServerPort,
|
||||
async (req: Request, res: Response<PortInfo | ErrorResponse>) => {
|
||||
try {
|
||||
const { serverPort } = matchedData<{ serverPort: number }>(req);
|
||||
portManager.changePort(serverPort);
|
||||
const { port, pendingRestart } = portManager.getPort();
|
||||
router.post('/serverport', validateServerPort, async (req: Request, res: Response<PortInfo | ErrorResponse>) => {
|
||||
try {
|
||||
const { serverPort } = matchedData<{ serverPort: number }>(req);
|
||||
portManager.changePort(serverPort);
|
||||
const { port, pendingRestart } = portManager.getPort();
|
||||
|
||||
res.status(200).json({ port, pendingRestart });
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(400).json({ message });
|
||||
}
|
||||
},
|
||||
);
|
||||
res.status(200).json({ port, pendingRestart });
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(400).json({ message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { body } from 'express-validator';
|
||||
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { EndAction, OntimeEvent, SupportedEntry, TimeStrategy, TimerType } from 'ontime-types';
|
||||
import { type Day, EndAction, OntimeEvent, SupportedEntry, TimeStrategy, TimerType } from 'ontime-types';
|
||||
import { millisToString } from 'ontime-utils';
|
||||
|
||||
import { getA1Notation, cellRequestFromEvent } from '../sheets.utils.js';
|
||||
import { cellRequestFromEvent, getA1Notation } from '../sheets.utils.js';
|
||||
|
||||
describe('getA1Notation()', () => {
|
||||
test('A1', () => {
|
||||
@@ -38,7 +38,7 @@ describe('cellRequestFromEvent()', () => {
|
||||
colour: 'red',
|
||||
delay: 0,
|
||||
gap: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
parent: null,
|
||||
revision: 0,
|
||||
id: '1358',
|
||||
@@ -89,7 +89,7 @@ describe('cellRequestFromEvent()', () => {
|
||||
revision: 0,
|
||||
delay: 0,
|
||||
gap: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
id: '1358',
|
||||
timeWarning: 0,
|
||||
timeDanger: 0,
|
||||
@@ -140,7 +140,7 @@ describe('cellRequestFromEvent()', () => {
|
||||
revision: 0,
|
||||
delay: 0,
|
||||
gap: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
id: '1358',
|
||||
timeWarning: 0,
|
||||
timeDanger: 0,
|
||||
@@ -187,7 +187,7 @@ describe('cellRequestFromEvent()', () => {
|
||||
colour: 'red',
|
||||
delay: 0,
|
||||
gap: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
parent: null,
|
||||
revision: 0,
|
||||
id: '1358',
|
||||
@@ -226,7 +226,7 @@ describe('cellRequestFromEvent()', () => {
|
||||
revision: 0,
|
||||
delay: 0,
|
||||
gap: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
id: '1358',
|
||||
timeWarning: 0,
|
||||
timeDanger: 0,
|
||||
@@ -264,7 +264,7 @@ describe('cellRequestFromEvent()', () => {
|
||||
revision: 0,
|
||||
delay: 0,
|
||||
gap: 0,
|
||||
dayOffset: 0,
|
||||
dayOffset: 0 as Day,
|
||||
id: '1358',
|
||||
timeWarning: 0,
|
||||
timeDanger: 0,
|
||||
|
||||
@@ -3,22 +3,21 @@
|
||||
* Google Sheets
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
import { Request, Response } from 'express';
|
||||
import type { AuthenticationStatus, CustomFields, ErrorResponse, Rundown, RundownSummary } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import { Request, Response } from 'express';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
import { deleteFile } from '../../utils/fileManagement.js';
|
||||
|
||||
import {
|
||||
revoke,
|
||||
download,
|
||||
getWorksheetOptions,
|
||||
handleClientSecret,
|
||||
handleInitialConnection,
|
||||
hasAuth,
|
||||
download,
|
||||
revoke,
|
||||
upload,
|
||||
getWorksheetOptions,
|
||||
} from './sheets.service.js';
|
||||
|
||||
export async function requestConnection(
|
||||
|
||||
@@ -4,35 +4,32 @@
|
||||
* @link https://developers.google.com/identity/protocols/oauth2/limited-input-device
|
||||
*/
|
||||
|
||||
import { sheets, type sheets_v4 } from '@googleapis/sheets';
|
||||
import { Credentials, OAuth2Client } from 'google-auth-library';
|
||||
import {
|
||||
AuthenticationStatus,
|
||||
CustomFields,
|
||||
DatabaseModel,
|
||||
EntryId,
|
||||
isOntimeEvent,
|
||||
isOntimeMilestone,
|
||||
LogOrigin,
|
||||
MaybeString,
|
||||
OntimeGroup,
|
||||
Rundown,
|
||||
RundownSummary,
|
||||
SupportedEntry,
|
||||
isOntimeEvent,
|
||||
isOntimeMilestone,
|
||||
} from 'ontime-types';
|
||||
import { ImportMap, getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import { sheets, type sheets_v4 } from '@googleapis/sheets';
|
||||
import { Credentials, OAuth2Client } from 'google-auth-library';
|
||||
|
||||
import { logger } from '../../classes/Logger.js';
|
||||
import { parseRundowns } from '../rundown/rundown.parser.js';
|
||||
|
||||
import { getCurrentRundown, getProjectCustomFields, processRundown } from '../rundown/rundown.dao.js';
|
||||
import { parseExcel } from '../excel/excel.parser.js';
|
||||
import { parseCustomFields } from '../custom-fields/customFields.parser.js';
|
||||
import { consoleSubdued } from '../../utils/console.js';
|
||||
|
||||
import { cellRequestFromEvent, type ClientSecret, getA1Notation, isClientSecret } from './sheets.utils.js';
|
||||
import { parseCustomFields } from '../custom-fields/customFields.parser.js';
|
||||
import { parseExcel } from '../excel/excel.parser.js';
|
||||
import { getCurrentRundown, getProjectCustomFields, processRundown } from '../rundown/rundown.dao.js';
|
||||
import { parseRundowns } from '../rundown/rundown.parser.js';
|
||||
import { catchCommonImportXlsxError } from './googleApi.utils.js';
|
||||
import { type ClientSecret, cellRequestFromEvent, getA1Notation, isClientSecret } from './sheets.utils.js';
|
||||
|
||||
const sheetScope = 'https://www.googleapis.com/auth/spreadsheets';
|
||||
const codesUrl = 'https://oauth2.googleapis.com/device/code';
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import type { sheets_v4 } from '@googleapis/sheets';
|
||||
import {
|
||||
OntimeEntry,
|
||||
OntimeEntryCommonKeys,
|
||||
RGBColour,
|
||||
isOntimeDelay,
|
||||
OntimeEntryCommonKeys,
|
||||
isOntimeGroup,
|
||||
isOntimeMilestone,
|
||||
} from 'ontime-types';
|
||||
import { cssOrHexToColour, isLightColour, millisToString, mixColours } from 'ontime-utils';
|
||||
|
||||
import type { sheets_v4 } from '@googleapis/sheets';
|
||||
|
||||
import { is } from '../../utils/is.js';
|
||||
|
||||
export type ClientSecret = {
|
||||
@@ -104,6 +103,7 @@ export function cellRequestFromEvent(
|
||||
const thisCol = e[1].col;
|
||||
const diff = thisCol - prevCol;
|
||||
if (diff > 1) {
|
||||
// TODO: we need to clarify this logic
|
||||
const fillArr = new Array<(typeof rowData)[0]>(1).fill(['blank', { row: e[1].row, col: prevCol + 1 }]);
|
||||
rowData.splice(index, 0, ...fillArr);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import { body, param, validationResult } from 'express-validator';
|
||||
import { isImportMap } from 'ontime-utils';
|
||||
|
||||
import { body, param, validationResult } from 'express-validator';
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const validateRequestConnection = [
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
import { RefetchKey, type ErrorResponse, type URLPreset } from 'ontime-types';
|
||||
import { type ErrorResponse, RefetchKey, type URLPreset } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import { sendRefetch } from '../../adapters/WebsocketAdapter.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { validateNewPreset, validatePresetParam, validateUpdatePreset } from './urlPresets.validation.js';
|
||||
import { sendRefetch } from '../../adapters/WebsocketAdapter.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { OntimeView } from 'ontime-types';
|
||||
|
||||
import { body, param } from 'express-validator';
|
||||
import { OntimeView } from 'ontime-types';
|
||||
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import type { NextFunction, Request, Response } from 'express';
|
||||
import { param, validationResult } from 'express-validator';
|
||||
|
||||
export const paramsWithId = [param('id').isString().trim().notEmpty(), requestValidationFunction];
|
||||
type RequestWithFile = Request & { file?: unknown };
|
||||
|
||||
// #region operations on project rundowns =========================
|
||||
|
||||
@@ -27,8 +28,9 @@ export function requestValidationFunctionWithFile(req: Request, res: Response, n
|
||||
res.status(422).json({ errors: errors.array() });
|
||||
return;
|
||||
}
|
||||
const request = req as RequestWithFile;
|
||||
// check that the file exists
|
||||
if (!req.file) {
|
||||
if (!request.file) {
|
||||
res.status(422).json({ errors: 'File not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
import { RefetchKey, type ErrorResponse, type ViewSettings } from 'ontime-types';
|
||||
import { type ErrorResponse, RefetchKey, type ViewSettings } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import { validateViewSettings } from './viewSettings.validation.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { sendRefetch } from '../../adapters/WebsocketAdapter.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { validateViewSettings } from './viewSettings.validation.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { body } from 'express-validator';
|
||||
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,140 +1,141 @@
|
||||
import { CustomFields, EntryCustomFields, OntimeDelay, OntimeEvent } from 'ontime-types';
|
||||
import { isValidChangeProperty } from '../integration.utils.js';
|
||||
|
||||
describe('isValidChangeProperty()', () => {
|
||||
test('allows changing a valid event property with valid value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'duration', 123, {})).toBeTruthy();
|
||||
});
|
||||
|
||||
test('forbids changing a valid event property with undefined value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'duration', undefined, {})).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids changing a non-existing property', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'missing', 123, {})).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids changing customValues in event without custom fields', () => {
|
||||
const testDelay = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeDelay;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testDelay, 'custom:test', 123, testCustomFields)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids changing a 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('allows changing an existing custom value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:test', 123, testCustomFields)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('forbids changing a custom field with a missing value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:', 123, testCustomFields)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids references to prototype properties in custom object', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:toString', 123, testCustomFields)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids references to prototype properties in object', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'toString', 123, testCustomFields)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
import { CustomFields, EntryCustomFields, OntimeDelay, OntimeEvent } from 'ontime-types';
|
||||
|
||||
import { isValidChangeProperty } from '../integration.utils.js';
|
||||
|
||||
describe('isValidChangeProperty()', () => {
|
||||
test('allows changing a valid event property with valid value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'duration', 123, {})).toBeTruthy();
|
||||
});
|
||||
|
||||
test('forbids changing a valid event property with undefined value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'duration', undefined, {})).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids changing a non-existing property', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeEvent;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'missing', 123, {})).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids changing customValues in event without custom fields', () => {
|
||||
const testDelay = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
} as OntimeDelay;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testDelay, 'custom:test', 123, testCustomFields)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids changing a 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('allows changing an existing custom value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:test', 123, testCustomFields)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('forbids changing a custom field with a missing value', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:', 123, testCustomFields)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids references to prototype properties in custom object', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'custom:toString', 123, testCustomFields)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('forbids references to prototype properties in object', () => {
|
||||
const testEvent = {
|
||||
id: 'test',
|
||||
duration: 111,
|
||||
custom: {
|
||||
test: 'test',
|
||||
} as EntryCustomFields,
|
||||
} as OntimeEvent;
|
||||
|
||||
const testCustomFields = {
|
||||
test: {
|
||||
type: 'text',
|
||||
colour: '#ffffff',
|
||||
label: 'Test Field',
|
||||
},
|
||||
} satisfies CustomFields;
|
||||
|
||||
expect(isValidChangeProperty(testEvent, 'toString', 123, testCustomFields)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,9 +8,12 @@ import {
|
||||
SimplePlayback,
|
||||
} from 'ontime-types';
|
||||
import { MILLIS_PER_HOUR } from 'ontime-utils';
|
||||
|
||||
import { DeepPartial } from 'ts-essentials';
|
||||
|
||||
import { socket } from '../adapters/WebsocketAdapter.js';
|
||||
import { getCurrentRundown, getProjectCustomFields } from '../api-data/rundown/rundown.dao.js';
|
||||
import { editEntry } from '../api-data/rundown/rundown.service.js';
|
||||
import { willCauseRegeneration } from '../api-data/rundown/rundown.utils.js';
|
||||
import { ONTIME_VERSION } from '../ONTIME_VERSION.js';
|
||||
import { auxTimerService } from '../services/aux-timer-service/AuxTimerService.js';
|
||||
import * as messageService from '../services/message-service/message.service.js';
|
||||
@@ -18,12 +21,8 @@ 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, isValidChangeProperty } from './integration.utils.js';
|
||||
import { socket } from '../adapters/WebsocketAdapter.js';
|
||||
import { coerceEnum } from '../utils/coerceType.js';
|
||||
import { editEntry } from '../api-data/rundown/rundown.service.js';
|
||||
import { willCauseRegeneration } from '../api-data/rundown/rundown.utils.js';
|
||||
import { getCurrentRundown, getProjectCustomFields } from '../api-data/rundown/rundown.dao.js';
|
||||
import { isValidChangeProperty, parseProperty } from './integration.utils.js';
|
||||
|
||||
let lastRequest: Date | null = null;
|
||||
|
||||
|
||||
@@ -5,16 +5,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import { ErrorResponse, LogOrigin } from 'ontime-types';
|
||||
|
||||
import express, { type Request, type Response } from 'express';
|
||||
|
||||
import { logger } from '../classes/Logger.js';
|
||||
import { integrationPayloadFromPath } from '../adapters/utils/parse.js';
|
||||
|
||||
import { dispatchFromAdapter } from './integration.controller.js';
|
||||
import { ErrorResponse, LogOrigin } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import { integrationPayloadFromPath } from '../adapters/utils/parse.js';
|
||||
import { logger } from '../classes/Logger.js';
|
||||
import { isEmptyObject } from '../utils/parserUtils.js';
|
||||
import { dispatchFromAdapter } from './integration.controller.js';
|
||||
|
||||
export const integrationRouter = express.Router();
|
||||
|
||||
|
||||
+31
-37
@@ -1,53 +1,47 @@
|
||||
import { LogOrigin, runtimeStorePlaceholder, SimpleDirection, SimplePlayback } from 'ontime-types';
|
||||
import http, { type Server } from 'http';
|
||||
|
||||
import 'dotenv/config';
|
||||
import express from 'express';
|
||||
import http, { type Server } from 'http';
|
||||
import cors from 'cors';
|
||||
import serverTiming from 'server-timing';
|
||||
import cookieParser from 'cookie-parser';
|
||||
import cors from 'cors';
|
||||
import express from 'express';
|
||||
import { LogOrigin, SimpleDirection, SimplePlayback, runtimeStorePlaceholder } from 'ontime-types';
|
||||
import serverTiming from 'server-timing';
|
||||
|
||||
// import utils
|
||||
import { publicDir, srcDir } from './setup/index.js';
|
||||
import { environment, isProduction } from './setup/environment.js';
|
||||
import { updateRouterPrefix } from './externals.js';
|
||||
import { ONTIME_VERSION } from './ONTIME_VERSION.js';
|
||||
import { consoleSuccess, consoleHighlight, consoleError } from './utils/console.js';
|
||||
|
||||
// Import middleware configuration
|
||||
import { bodyParser } from './middleware/bodyParser.js';
|
||||
import { compressedStatic } from './middleware/staticGZip.js';
|
||||
import { makeLoginRouter, makeAuthenticateMiddleware } from './middleware/authenticate.js';
|
||||
|
||||
import { oscServer } from './adapters/OscAdapter.js';
|
||||
// Import adapters
|
||||
import { socket } from './adapters/WebsocketAdapter.js';
|
||||
// Import Routers
|
||||
import { appRouter } from './api-data/index.js';
|
||||
import { integrationRouter } from './api-integration/integration.router.js';
|
||||
|
||||
// Import adapters
|
||||
import { socket } from './adapters/WebsocketAdapter.js';
|
||||
import { getDataProvider, flushPendingWrites } from './classes/data-provider/DataProvider.js';
|
||||
|
||||
import { flushPendingWrites, getDataProvider } from './classes/data-provider/DataProvider.js';
|
||||
// Services
|
||||
import { logger } from './classes/Logger.js';
|
||||
import { populateDemo } from './setup/loadDemo.js';
|
||||
import { populateTranslation } from './setup/loadTranslations.js';
|
||||
import { populateStyles } from './setup/loadStyles.js';
|
||||
import { eventStore } from './stores/EventStore.js';
|
||||
import { runtimeService } from './services/runtime-service/runtime.service.js';
|
||||
import { portManager } from './classes/port-manager/PortManager.js';
|
||||
import { updateRouterPrefix } from './externals.js';
|
||||
import { makeAuthenticateMiddleware, makeLoginRouter } from './middleware/authenticate.js';
|
||||
// Import middleware configuration
|
||||
import { bodyParser } from './middleware/bodyParser.js';
|
||||
import { compressedStatic } from './middleware/staticGZip.js';
|
||||
import { ONTIME_VERSION } from './ONTIME_VERSION.js';
|
||||
import { getShowWelcomeDialog } from './services/app-state-service/AppStateService.js';
|
||||
import * as messageService from './services/message-service/message.service.js';
|
||||
import { initialiseProject } from './services/project-service/ProjectService.js';
|
||||
import { restoreService } from './services/restore-service/restore.service.js';
|
||||
import type { RestorePoint } from './services/restore-service/restore.type.js';
|
||||
import * as messageService from './services/message-service/message.service.js';
|
||||
import { getState } from './stores/runtimeState.js';
|
||||
import { initialiseProject } from './services/project-service/ProjectService.js';
|
||||
import { getShowWelcomeDialog } from './services/app-state-service/AppStateService.js';
|
||||
import { oscServer } from './adapters/OscAdapter.js';
|
||||
|
||||
// Utilities
|
||||
import { clearUploadfolder } from './utils/upload.js';
|
||||
import { generateCrashReport } from './utils/generateCrashReport.js';
|
||||
import { runtimeService } from './services/runtime-service/runtime.service.js';
|
||||
import { timerConfig } from './setup/config.js';
|
||||
import { environment, isProduction } from './setup/environment.js';
|
||||
// import utils
|
||||
import { publicDir, srcDir } from './setup/index.js';
|
||||
import { populateDemo } from './setup/loadDemo.js';
|
||||
import { populateStyles } from './setup/loadStyles.js';
|
||||
import { populateTranslation } from './setup/loadTranslations.js';
|
||||
import { eventStore } from './stores/EventStore.js';
|
||||
import { getState } from './stores/runtimeState.js';
|
||||
import { consoleError, consoleHighlight, consoleSuccess } from './utils/console.js';
|
||||
import { generateCrashReport } from './utils/generateCrashReport.js';
|
||||
import { getNetworkInterfaces } from './utils/network.js';
|
||||
import { portManager } from './classes/port-manager/PortManager.js';
|
||||
import { clearUploadfolder } from './utils/upload.js';
|
||||
|
||||
console.log('\n');
|
||||
consoleHighlight(`Starting Ontime version ${ONTIME_VERSION}`);
|
||||
|
||||
@@ -2,9 +2,9 @@ import { Log, LogLevel, MessageTag } from 'ontime-types';
|
||||
import { generateId, millisToString } from 'ontime-utils';
|
||||
|
||||
import { socket } from '../adapters/WebsocketAdapter.js';
|
||||
import { consoleSubdued, consoleError } from '../utils/console.js';
|
||||
import { timeNow } from '../utils/time.js';
|
||||
import { isProduction } from '../setup/environment.js';
|
||||
import { consoleError, consoleSubdued } from '../utils/console.js';
|
||||
import { timeNow } from '../utils/time.js';
|
||||
|
||||
class Logger {
|
||||
private queue: Log[];
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import {
|
||||
ProjectData,
|
||||
ViewSettings,
|
||||
DatabaseModel,
|
||||
Settings,
|
||||
CustomFields,
|
||||
URLPreset,
|
||||
AutomationSettings,
|
||||
Rundown,
|
||||
ProjectRundowns,
|
||||
} from 'ontime-types';
|
||||
|
||||
import type { Low } from 'lowdb';
|
||||
import { JSONFilePreset } from 'lowdb/node';
|
||||
import {
|
||||
AutomationSettings,
|
||||
CustomFields,
|
||||
DatabaseModel,
|
||||
ProjectData,
|
||||
ProjectRundowns,
|
||||
Rundown,
|
||||
Settings,
|
||||
URLPreset,
|
||||
ViewSettings,
|
||||
} from 'ontime-types';
|
||||
|
||||
import { isPath } from '../../utils/fileManagement.js';
|
||||
import { shouldCrashDev } from '../../utils/development.js';
|
||||
import { isTest } from '../../setup/environment.js';
|
||||
|
||||
import { shouldCrashDev } from '../../utils/development.js';
|
||||
import { isPath } from '../../utils/fileManagement.js';
|
||||
import { safeMerge } from './DataProvider.utils.js';
|
||||
|
||||
type ReadonlyPromise<T> = Promise<Readonly<T>>;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { AutomationSettings, CustomField, DatabaseModel, Settings, TimerLifeCycle, URLPreset } from 'ontime-types';
|
||||
|
||||
import { makeNewProject } from '../../../models/dataModel.js';
|
||||
import { makeOntimeEvent, makeRundown } from '../../../api-data/rundown/__mocks__/rundown.mocks.js';
|
||||
|
||||
import { makeNewProject } from '../../../models/dataModel.js';
|
||||
import { safeMerge } from '../DataProvider.utils.js';
|
||||
|
||||
const baseDb = makeNewProject('demo');
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Server } from "http";
|
||||
import { config } from "../../setup/config.js";
|
||||
import { envPort, isDocker, isOntimeCloud } from "../../setup/environment.js";
|
||||
import * as appState from "../../services/app-state-service/AppStateService.js";
|
||||
import { logger } from "../Logger.js";
|
||||
import { LogOrigin, MaybeNumber } from "ontime-types";
|
||||
import { isAddressInfo, isPortInUseError } from "./PortManager.utils.js";
|
||||
import { shouldCrashDev } from "../../utils/development.js";
|
||||
import { Server } from 'http';
|
||||
|
||||
import { LogOrigin, MaybeNumber } from 'ontime-types';
|
||||
|
||||
import * as appState from '../../services/app-state-service/AppStateService.js';
|
||||
import { config } from '../../setup/config.js';
|
||||
import { envPort, isDocker, isOntimeCloud } from '../../setup/environment.js';
|
||||
import { shouldCrashDev } from '../../utils/development.js';
|
||||
import { logger } from '../Logger.js';
|
||||
import { isAddressInfo, isPortInUseError } from './PortManager.utils.js';
|
||||
|
||||
class PortManager {
|
||||
private static port: number;
|
||||
@@ -27,7 +29,7 @@ class PortManager {
|
||||
* @returns {void}
|
||||
*/
|
||||
public changePort(newPort: number): void {
|
||||
if (isDocker) throw new Error("Can not change port when running inside docker");
|
||||
if (isDocker) throw new Error('Can not change port when running inside docker');
|
||||
if (PortManager.port === newPort) return;
|
||||
PortManager.newPort = newPort;
|
||||
PortManager.pendingRestart = true;
|
||||
@@ -36,7 +38,7 @@ class PortManager {
|
||||
public migratePortFromProjectFile(port: number) {
|
||||
shouldCrashDev(
|
||||
PortManager.port !== undefined,
|
||||
"this function should not be called after `PortManager.port` has been initialized",
|
||||
'this function should not be called after `PortManager.port` has been initialized',
|
||||
);
|
||||
appState.setServerPort(port);
|
||||
}
|
||||
@@ -61,8 +63,7 @@ class PortManager {
|
||||
if (isOntimeCloud) {
|
||||
PortManager.port = await this.forceCloudPort(server);
|
||||
} else {
|
||||
PortManager.port =
|
||||
this.parsePort(envPort) || (await appState.getServerPort()) || config.defaultServerPort;
|
||||
PortManager.port = this.parsePort(envPort) || (await appState.getServerPort()) || config.defaultServerPort;
|
||||
PortManager.port = await this.tryServerPort(server);
|
||||
}
|
||||
await appState.setServerPort(PortManager.port);
|
||||
@@ -70,8 +71,8 @@ class PortManager {
|
||||
}
|
||||
|
||||
private parsePort(port: string | undefined) {
|
||||
if (typeof port !== "string") return null;
|
||||
if (port === "") return null;
|
||||
if (typeof port !== 'string') return null;
|
||||
if (port === '') return null;
|
||||
const maybePort = Number(port);
|
||||
if (isNaN(maybePort)) return null;
|
||||
return maybePort;
|
||||
@@ -79,7 +80,7 @@ class PortManager {
|
||||
|
||||
private async tryServerPort(server: Server): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
server.once("error", (error) => {
|
||||
server.once('error', (error) => {
|
||||
// we should only move ports if we are in a desktop environment
|
||||
if (isDocker) {
|
||||
reject(error);
|
||||
@@ -93,10 +94,10 @@ class PortManager {
|
||||
|
||||
// if we get an address in use error, we will try to open the server in an ephemeral port
|
||||
// port 0 will assign an ephemeral port
|
||||
server.listen(0, "0.0.0.0", () => {
|
||||
server.listen(0, '0.0.0.0', () => {
|
||||
const address = server.address();
|
||||
if (!isAddressInfo(address)) {
|
||||
reject(new Error("Unknown port type, unable to proceed"));
|
||||
reject(new Error('Unknown port type, unable to proceed'));
|
||||
return;
|
||||
}
|
||||
logger.error(
|
||||
@@ -109,10 +110,10 @@ class PortManager {
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(PortManager.port, "0.0.0.0", () => {
|
||||
server.listen(PortManager.port, '0.0.0.0', () => {
|
||||
const address = server.address();
|
||||
if (!isAddressInfo(address)) {
|
||||
reject(new Error("Unknown port type, unable to proceed"));
|
||||
reject(new Error('Unknown port type, unable to proceed'));
|
||||
return;
|
||||
}
|
||||
resolve(address.port);
|
||||
@@ -122,13 +123,13 @@ class PortManager {
|
||||
|
||||
private forceCloudPort(server: Server): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
server.once("error", (error) => {
|
||||
server.once('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
server.listen(config.defaultServerPort, "0.0.0.0", () => {
|
||||
server.listen(config.defaultServerPort, '0.0.0.0', () => {
|
||||
const address = server.address();
|
||||
if (!isAddressInfo(address)) {
|
||||
reject(new Error("Unknown port type, unable to proceed"));
|
||||
reject(new Error('Unknown port type, unable to proceed'));
|
||||
return;
|
||||
}
|
||||
resolve(address.port);
|
||||
|
||||
Vendored
+2
-1
@@ -2,7 +2,8 @@
|
||||
|
||||
This folder contains resources which will be distributed as part of Ontime's infrastructure.
|
||||
Folders added here would be available at
|
||||
``` bash
|
||||
|
||||
```bash
|
||||
http://<ip-address>:<port>/external/<folder-name>
|
||||
```
|
||||
|
||||
|
||||
+111
-109
@@ -1,114 +1,116 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<!-- For detailed explanations and examples, refer to the README.md file in this directory -->
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>ontime demo</title>
|
||||
<link href="./styles.css" rel="stylesheet" />
|
||||
</head>
|
||||
<!-- For detailed explanations and examples, refer to the README.md file in this directory -->
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>ontime demo</title>
|
||||
<link href="./styles.css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header class="title-card">
|
||||
<div class="logo-title">
|
||||
<img src="https://www.getontime.no/images/icons/ontime-logo.png" alt="Ontime logo"
|
||||
onerror="this.style.display='none'" />
|
||||
<h1 class="title">Ontime demo</h1>
|
||||
</div>
|
||||
<div>
|
||||
<span>Last message received at</span>
|
||||
<span id="clock">-</span>
|
||||
</div>
|
||||
<nav>
|
||||
<a href="https://docs.getontime.no/api/data/runtime-data" target="_blank">Help? See docs</a>
|
||||
<div>See <a href="README.md">README.md</a> details.</div>
|
||||
</nav>
|
||||
</header>
|
||||
<body>
|
||||
<header class="title-card">
|
||||
<div class="logo-title">
|
||||
<img
|
||||
src="https://www.getontime.no/images/icons/ontime-logo.png"
|
||||
alt="Ontime logo"
|
||||
onerror="this.style.display = 'none'"
|
||||
/>
|
||||
<h1 class="title">Ontime demo</h1>
|
||||
</div>
|
||||
<div>
|
||||
<span>Last message received at</span>
|
||||
<span id="clock">-</span>
|
||||
</div>
|
||||
<nav>
|
||||
<a href="https://docs.getontime.no/api/data/runtime-data" target="_blank">Help? See docs</a>
|
||||
<div>See <a href="README.md">README.md</a> details.</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<section class="column">
|
||||
<details class="card" open>
|
||||
<summary class="title">Timer</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Current timer values</figcaption>
|
||||
<code id="timer">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Rundown</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Progress of the current rundown</figcaption>
|
||||
<code id="rundown">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Offset</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Runtime offset and timings for upcoming targets</figcaption>
|
||||
<code id="offset">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
</section>
|
||||
<section class="column">
|
||||
<details class="card" open>
|
||||
<summary class="title">Event now</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Currently loaded event</figcaption>
|
||||
<code id="eventNow">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Event next</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Next scheduled event</figcaption>
|
||||
<code id="eventNext">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
</section>
|
||||
<section class="column">
|
||||
<details class="card" open>
|
||||
<summary class="title">Group now</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Currently active group</figcaption>
|
||||
<code id="groupNow">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Event flag</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Currently targeted flag</figcaption>
|
||||
<code id="eventFlag">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
</section>
|
||||
<section class="column">
|
||||
<details class="card" open>
|
||||
<summary class="title">Message</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Messaging feature</figcaption>
|
||||
<code id="message">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Aux timers</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Auxiliary Timer 1</figcaption>
|
||||
<code id="auxtimer1">-</code>
|
||||
</figure>
|
||||
<figure>
|
||||
<figcaption class="description">Auxiliary Timer 2</figcaption>
|
||||
<code id="auxtimer2">-</code>
|
||||
</figure>
|
||||
<figure>
|
||||
<figcaption class="description">Auxiliary Timer 3</figcaption>
|
||||
<code id="auxtimer3">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script src="./app.js" type="text/javascript"></script>
|
||||
<main class="container">
|
||||
<section class="column">
|
||||
<details class="card" open>
|
||||
<summary class="title">Timer</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Current timer values</figcaption>
|
||||
<code id="timer">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Rundown</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Progress of the current rundown</figcaption>
|
||||
<code id="rundown">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Offset</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Runtime offset and timings for upcoming targets</figcaption>
|
||||
<code id="offset">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
</section>
|
||||
<section class="column">
|
||||
<details class="card" open>
|
||||
<summary class="title">Event now</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Currently loaded event</figcaption>
|
||||
<code id="eventNow">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Event next</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Next scheduled event</figcaption>
|
||||
<code id="eventNext">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
</section>
|
||||
<section class="column">
|
||||
<details class="card" open>
|
||||
<summary class="title">Group now</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Currently active group</figcaption>
|
||||
<code id="groupNow">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Event flag</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Currently targeted flag</figcaption>
|
||||
<code id="eventFlag">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
</section>
|
||||
<section class="column">
|
||||
<details class="card" open>
|
||||
<summary class="title">Message</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Messaging feature</figcaption>
|
||||
<code id="message">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
<details class="card" open>
|
||||
<summary class="title">Aux timers</summary>
|
||||
<figure>
|
||||
<figcaption class="description">Auxiliary Timer 1</figcaption>
|
||||
<code id="auxtimer1">-</code>
|
||||
</figure>
|
||||
<figure>
|
||||
<figcaption class="description">Auxiliary Timer 2</figcaption>
|
||||
<code id="auxtimer2">-</code>
|
||||
</figure>
|
||||
<figure>
|
||||
<figcaption class="description">Auxiliary Timer 3</figcaption>
|
||||
<code id="auxtimer3">-</code>
|
||||
</figure>
|
||||
</details>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
</html>
|
||||
<script src="./app.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
|
||||
import { srcFiles } from './setup/index.js';
|
||||
import { isOntimeCloud } from './setup/environment.js';
|
||||
import { srcFiles } from './setup/index.js';
|
||||
|
||||
// =================================================
|
||||
export const password = process.env.SESSION_PASSWORD;
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
<style>
|
||||
body,
|
||||
html {
|
||||
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana,
|
||||
sans-serif;
|
||||
font-family:
|
||||
'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
|
||||
background: #101010;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable no-console */
|
||||
import { consoleHighlight, consoleError } from './utils/console.js';
|
||||
import { initAssets, startIntegrations, startServer } from './app.js';
|
||||
/* eslint-disable no-console */
|
||||
import { consoleError, consoleHighlight } from './utils/console.js';
|
||||
|
||||
async function startOntime() {
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { dayInMs, MILLIS_PER_HOUR, MILLIS_PER_MINUTE, millisToString } from 'ontime-utils';
|
||||
import { Duration, Instant, TimeOfDay } from 'ontime-types';
|
||||
import { dayInMs, MILLIS_PER_HOUR, MILLIS_PER_MINUTE, millisToString } from 'ontime-utils';
|
||||
|
||||
import { timeNow } from '../../../utils/time.js';
|
||||
import * as timeCore from '../timeCore.js';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Day, Duration, Instant, TimeOfDay } from 'ontime-types';
|
||||
import { dayInMs, MILLIS_PER_MINUTE } from 'ontime-utils';
|
||||
import { MILLIS_PER_MINUTE, dayInMs } from 'ontime-utils';
|
||||
|
||||
/** Returns the current instant */
|
||||
export function now(): Instant {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import express, { type Request, type Response, type NextFunction } from 'express';
|
||||
import type { IncomingMessage } from 'node:http';
|
||||
import type { WebSocket } from 'ws';
|
||||
|
||||
import { parse as parseCookie } from 'cookie';
|
||||
import express, { type NextFunction, type Request, type Response } from 'express';
|
||||
import type { WebSocket } from 'ws';
|
||||
|
||||
import { hashPassword } from '../utils/hash.js';
|
||||
import { hasPassword, hashedPassword } from '../api-data/session/session.service.js';
|
||||
import { srcFiles } from '../setup/index.js';
|
||||
import { hashedPassword, hasPassword } from '../api-data/session/session.service.js';
|
||||
|
||||
import { hashPassword } from '../utils/hash.js';
|
||||
import { noopMiddleware } from './noop.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import type { NextFunction, Request, Response } from 'express';
|
||||
|
||||
export function noopMiddleware(_req: Request, _res: Response, next: NextFunction) {
|
||||
next();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import expressStaticGzip from 'express-static-gzip';
|
||||
import { extname } from 'node:path';
|
||||
|
||||
import expressStaticGzip from 'express-static-gzip';
|
||||
|
||||
import { srcDir } from '../setup/index.js';
|
||||
|
||||
// serve static - react, in dev/test mode we fetch the React app from module
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { DatabaseModel, Rundown } from 'ontime-types';
|
||||
import { ONTIME_VERSION } from '../ONTIME_VERSION.js';
|
||||
import { generateId } from 'ontime-utils';
|
||||
|
||||
import { ONTIME_VERSION } from '../ONTIME_VERSION.js';
|
||||
|
||||
const defaultRundown: Rundown = {
|
||||
id: 'default',
|
||||
title: 'Default',
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
import { dayInMs, MILLIS_PER_HOUR, MILLIS_PER_MINUTE } from 'ontime-utils';
|
||||
|
||||
import { PlayableEvent } from 'ontime-types';
|
||||
import { MILLIS_PER_HOUR, MILLIS_PER_MINUTE, dayInMs } from 'ontime-utils';
|
||||
|
||||
import { initRundown } from '../../api-data/rundown/rundown.service.js';
|
||||
import { processRundown, rundownCache } from '../../api-data/rundown/rundown.dao.js';
|
||||
import { makeOntimeEvent, makeRundown } from '../../api-data/rundown/__mocks__/rundown.mocks.js';
|
||||
|
||||
import { processRundown, rundownCache } from '../../api-data/rundown/rundown.dao.js';
|
||||
import { initRundown } from '../../api-data/rundown/rundown.service.js';
|
||||
import { loadRoll } from '../rollUtils.js';
|
||||
|
||||
beforeAll(() => {
|
||||
vi.mock('../../classes/data-provider/DataProvider.js', () => {
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
setCustomFields: vi.fn().mockImplementation((newData) => newData),
|
||||
setRundown: vi.fn().mockImplementation((newData) => newData),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
vi.mock('../../classes/data-provider/DataProvider.js', () => {
|
||||
return {
|
||||
getDataProvider: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
setCustomFields: vi.fn().mockImplementation((newData) => newData),
|
||||
setRundown: vi.fn().mockImplementation((newData) => newData),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const mockEvent = {
|
||||
@@ -727,7 +723,7 @@ describe('loadRoll() test that roll behaviour multi day event edge cases', () =>
|
||||
id: '2',
|
||||
timeStart: 11 * MILLIS_PER_HOUR,
|
||||
timeEnd: 2 * MILLIS_PER_HOUR,
|
||||
duration: 14 * MILLIS_PER_HOUR
|
||||
duration: 14 * MILLIS_PER_HOUR,
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -782,7 +778,7 @@ describe('loadRoll() test that roll behaviour multi day event edge cases', () =>
|
||||
});
|
||||
|
||||
describe('loadRoll() should not roll skipped events', () => {
|
||||
test('', async () => {
|
||||
test('load roll', async () => {
|
||||
vi.useFakeTimers();
|
||||
await initRundown(
|
||||
makeRundown({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { dayInMs, MILLIS_PER_HOUR, MILLIS_PER_MINUTE, MILLIS_PER_SECOND, millisToString } from 'ontime-utils';
|
||||
import { EndAction, Playback, TimeOfDay, TimeStrategy, TimerPhase, TimerType } from 'ontime-types';
|
||||
import { MILLIS_PER_HOUR, MILLIS_PER_MINUTE, MILLIS_PER_SECOND, dayInMs, millisToString } from 'ontime-utils';
|
||||
|
||||
import type { RuntimeState } from '../../stores/runtimeState.js';
|
||||
import {
|
||||
findDayOffset,
|
||||
getCurrent,
|
||||
@@ -11,7 +12,8 @@ import {
|
||||
normaliseEndTime,
|
||||
skippedOutOfEvent,
|
||||
} from '../timerUtils.js';
|
||||
import type { RuntimeState } from '../../stores/runtimeState.js';
|
||||
|
||||
const asTimeOfDay = (value: number): RuntimeState['clock'] => value as RuntimeState['clock'];
|
||||
|
||||
describe('getExpectedFinish()', () => {
|
||||
it('is null if we havent started', () => {
|
||||
@@ -574,7 +576,7 @@ describe('skippedOutOfEvent()', () => {
|
||||
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
|
||||
state.clock += testSkipLimit;
|
||||
state.clock = asTimeOfDay(state.clock + testSkipLimit);
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -594,7 +596,7 @@ describe('skippedOutOfEvent()', () => {
|
||||
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
|
||||
state.clock += testSkipLimit;
|
||||
state.clock = asTimeOfDay(state.clock + testSkipLimit);
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -613,7 +615,7 @@ describe('skippedOutOfEvent()', () => {
|
||||
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
|
||||
state.clock = testSkipLimit - 2;
|
||||
state.clock = asTimeOfDay(testSkipLimit - 2);
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -632,7 +634,7 @@ describe('skippedOutOfEvent()', () => {
|
||||
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
|
||||
state.clock -= testSkipLimit;
|
||||
state.clock = asTimeOfDay(state.clock - testSkipLimit);
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -652,7 +654,7 @@ describe('skippedOutOfEvent()', () => {
|
||||
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
|
||||
state.clock += testSkipLimit + 1;
|
||||
state.clock = asTimeOfDay(state.clock + testSkipLimit + 1);
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -672,7 +674,7 @@ describe('skippedOutOfEvent()', () => {
|
||||
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
|
||||
state.clock -= testSkipLimit + 1;
|
||||
state.clock = asTimeOfDay(state.clock - testSkipLimit - 1);
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -691,7 +693,7 @@ describe('skippedOutOfEvent()', () => {
|
||||
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
|
||||
state.clock = testSkipLimit - 2;
|
||||
state.clock = asTimeOfDay(testSkipLimit - 2);
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -710,7 +712,7 @@ describe('skippedOutOfEvent()', () => {
|
||||
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||
|
||||
state.clock -= testSkipLimit + 1;
|
||||
state.clock = asTimeOfDay(state.clock - testSkipLimit - 1);
|
||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1253,7 +1255,7 @@ describe('getTimerPhase()', () => {
|
||||
expect(phase).toBe(TimerPhase.Warning);
|
||||
});
|
||||
|
||||
it('it default if the timer is playing and there is none of the above', () => {
|
||||
it('is default if the timer is playing and there is none of the above', () => {
|
||||
const state = {
|
||||
timer: {
|
||||
addedTime: 0,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Low } from 'lowdb';
|
||||
import { JSONFile } from 'lowdb/node';
|
||||
|
||||
import { publicFiles } from '../../setup/index.js';
|
||||
import { isTest } from '../../setup/environment.js';
|
||||
import { isPath } from '../../utils/fileManagement.js';
|
||||
import { publicFiles } from '../../setup/index.js';
|
||||
import { shouldCrashDev } from '../../utils/development.js';
|
||||
import { isPath } from '../../utils/fileManagement.js';
|
||||
|
||||
interface AppState {
|
||||
projectName?: string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RuntimeStore, SimpleDirection, SimplePlayback } from 'ontime-types';
|
||||
|
||||
import { SimpleTimer } from '../../classes/simple-timer/SimpleTimer.js';
|
||||
import { eventStore } from '../../stores/EventStore.js';
|
||||
import { timerConfig } from '../../setup/config.js';
|
||||
import { eventStore } from '../../stores/EventStore.js';
|
||||
|
||||
type AuxTimerStateUpdate = Partial<Pick<RuntimeStore, 'auxtimer1' | 'auxtimer2' | 'auxtimer3'>>;
|
||||
type EmitFn = (state: AuxTimerStateUpdate) => void;
|
||||
|
||||
@@ -2,8 +2,8 @@ import { MessageState, runtimeStorePlaceholder } from 'ontime-types';
|
||||
import { withoutUndefinedValues } from 'ontime-utils';
|
||||
import { DeepPartial } from 'ts-essentials';
|
||||
|
||||
import type { PublishFn, StoreGetter } from '../../stores/EventStore.js';
|
||||
import { throttle } from '../../utils/throttle.js';
|
||||
import type { StoreGetter, PublishFn } from '../../stores/EventStore.js';
|
||||
|
||||
/**
|
||||
* Create a throttled version of the set function
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
import { DatabaseModel, LogOrigin, ProjectFileListResponse } from 'ontime-types';
|
||||
import { getErrorMessage, getFirstRundown } from 'ontime-utils';
|
||||
|
||||
import { copyFile } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
|
||||
import { DatabaseModel, LogOrigin, ProjectFileListResponse } from 'ontime-types';
|
||||
import { getErrorMessage, getFirstRundown } from 'ontime-utils';
|
||||
|
||||
import { parseCustomFields } from '../../api-data/custom-fields/customFields.parser.js';
|
||||
import { parseDatabaseModel } from '../../api-data/db/db.parser.js';
|
||||
import { getCurrentRundown } from '../../api-data/rundown/rundown.dao.js';
|
||||
import { parseRundowns } from '../../api-data/rundown/rundown.parser.js';
|
||||
import { initRundown } from '../../api-data/rundown/rundown.service.js';
|
||||
import { getDataProvider, initPersistence } from '../../classes/data-provider/DataProvider.js';
|
||||
import { safeMerge } from '../../classes/data-provider/DataProvider.utils.js';
|
||||
import { logger } from '../../classes/Logger.js';
|
||||
import { makeNewProject } from '../../models/dataModel.js';
|
||||
import { demoDb } from '../../models/demoProject.js';
|
||||
import { config } from '../../setup/config.js';
|
||||
import { publicDir } from '../../setup/index.js';
|
||||
import { populateOntimeLogo } from '../../setup/loadOntimeLogo.js';
|
||||
import {
|
||||
appendToName,
|
||||
deleteFile,
|
||||
@@ -16,20 +27,8 @@ import {
|
||||
getFileNameFromPath,
|
||||
removeFileExtension,
|
||||
} from '../../utils/fileManagement.js';
|
||||
import { parseRundowns } from '../../api-data/rundown/rundown.parser.js';
|
||||
import { demoDb } from '../../models/demoProject.js';
|
||||
import { config } from '../../setup/config.js';
|
||||
import { getDataProvider, initPersistence } from '../../classes/data-provider/DataProvider.js';
|
||||
import { initRundown } from '../../api-data/rundown/rundown.service.js';
|
||||
import { parseDatabaseModel } from '../../api-data/db/db.parser.js';
|
||||
import { parseCustomFields } from '../../api-data/custom-fields/customFields.parser.js';
|
||||
import { makeNewProject } from '../../models/dataModel.js';
|
||||
import { safeMerge } from '../../classes/data-provider/DataProvider.utils.js';
|
||||
import { getCurrentRundown } from '../../api-data/rundown/rundown.dao.js';
|
||||
|
||||
import { getLastLoaded, isLastLoadedProject, setLastLoaded } from '../app-state-service/AppStateService.js';
|
||||
import { runtimeService } from '../runtime-service/runtime.service.js';
|
||||
|
||||
import {
|
||||
doesProjectExist,
|
||||
getPathToProject,
|
||||
@@ -37,7 +36,6 @@ import {
|
||||
moveCorruptFile,
|
||||
parseJsonFile,
|
||||
} from './projectServiceUtils.js';
|
||||
import { populateOntimeLogo } from '../../setup/loadOntimeLogo.js';
|
||||
|
||||
type ProjectState =
|
||||
| {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Mock } from 'vitest';
|
||||
|
||||
import { isLastLoadedProject } from '../../app-state-service/AppStateService.js';
|
||||
|
||||
import { deleteProjectFile, duplicateProjectFile, renameProjectFile } from '../ProjectService.js';
|
||||
import { doesProjectExist } from '../projectServiceUtils.js';
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { DatabaseModel, MaybeString, ProjectFile } from 'ontime-types';
|
||||
|
||||
import { existsSync } from 'fs';
|
||||
import { readFile, stat } from 'fs/promises';
|
||||
import { extname, join } from 'path';
|
||||
|
||||
import { DatabaseModel, MaybeString, ProjectFile } from 'ontime-types';
|
||||
|
||||
import { publicDir } from '../../setup/index.js';
|
||||
import { dockerSafeRename, getFilesFromFolder, removeFileExtension } from '../../utils/fileManagement.js';
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { Playback } from 'ontime-types';
|
||||
import type { Instant } from 'ontime-types';
|
||||
|
||||
import { isRestorePoint } from '../restore.parser.js';
|
||||
import { RestorePoint } from '../restore.type.js';
|
||||
|
||||
const asInstant = (value: number): Instant => value as Instant;
|
||||
|
||||
describe('isRestorePoint()', () => {
|
||||
it('validates a well defined object', () => {
|
||||
let restorePoint: RestorePoint = {
|
||||
@@ -12,7 +15,7 @@ describe('isRestorePoint()', () => {
|
||||
addedTime: 2,
|
||||
pausedAt: 3,
|
||||
firstStart: 1,
|
||||
startEpoch: 1,
|
||||
startEpoch: asInstant(1),
|
||||
currentDay: 0,
|
||||
};
|
||||
expect(isRestorePoint(restorePoint)).toBe(true);
|
||||
@@ -24,7 +27,7 @@ describe('isRestorePoint()', () => {
|
||||
addedTime: 0,
|
||||
pausedAt: null,
|
||||
firstStart: 1,
|
||||
startEpoch: 1,
|
||||
startEpoch: asInstant(1),
|
||||
currentDay: 2,
|
||||
};
|
||||
expect(isRestorePoint(restorePoint)).toBe(true);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { Playback } from 'ontime-types';
|
||||
|
||||
import type { Instant } from 'ontime-types';
|
||||
import { vi } from 'vitest';
|
||||
|
||||
import { RestorePoint } from '../restore.type.js';
|
||||
import { restoreService } from '../restore.service.js';
|
||||
import { RestorePoint } from '../restore.type.js';
|
||||
|
||||
const asInstant = (value: number): Instant => value as Instant;
|
||||
|
||||
describe('restoreService', () => {
|
||||
describe('load()', () => {
|
||||
@@ -16,7 +18,7 @@ describe('restoreService', () => {
|
||||
addedTime: 5678,
|
||||
pausedAt: 9087,
|
||||
firstStart: 1234,
|
||||
startEpoch: 1234,
|
||||
startEpoch: asInstant(1234),
|
||||
currentDay: 0,
|
||||
};
|
||||
|
||||
@@ -35,7 +37,7 @@ describe('restoreService', () => {
|
||||
addedTime: 0,
|
||||
pausedAt: null,
|
||||
firstStart: 1234,
|
||||
startEpoch: 1234,
|
||||
startEpoch: asInstant(1234),
|
||||
currentDay: null,
|
||||
};
|
||||
|
||||
@@ -83,7 +85,7 @@ describe('restoreService', () => {
|
||||
addedTime: 1234,
|
||||
pausedAt: 1234,
|
||||
firstStart: 1234,
|
||||
startEpoch: 1234,
|
||||
startEpoch: asInstant(1234),
|
||||
currentDay: 0,
|
||||
};
|
||||
|
||||
@@ -101,7 +103,7 @@ describe('restoreService', () => {
|
||||
addedTime: 2345,
|
||||
pausedAt: 2345,
|
||||
firstStart: 2345,
|
||||
startEpoch: 2345,
|
||||
startEpoch: asInstant(2345),
|
||||
currentDay: 0,
|
||||
};
|
||||
|
||||
@@ -112,7 +114,7 @@ describe('restoreService', () => {
|
||||
addedTime: 3456,
|
||||
pausedAt: 3456,
|
||||
firstStart: 3456,
|
||||
startEpoch: 3456,
|
||||
startEpoch: asInstant(3456),
|
||||
currentDay: 1,
|
||||
};
|
||||
|
||||
@@ -134,7 +136,7 @@ describe('restoreService', () => {
|
||||
addedTime: 5678,
|
||||
pausedAt: 5678,
|
||||
firstStart: 5678,
|
||||
startEpoch: 5678,
|
||||
startEpoch: asInstant(5678),
|
||||
currentDay: 0,
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user