Merge remote-tracking branch 'org/master' into google-sheets-lite

This commit is contained in:
arc-alex
2023-11-19 18:28:57 +01:00
58 changed files with 436 additions and 254 deletions
@@ -1,3 +1,4 @@
import { Alias, DatabaseModel, OntimeRundown, Settings } from 'ontime-types';
import { safeMerge } from '../DataProvider.utils.js';
describe('safeMerge', () => {
@@ -5,13 +6,15 @@ describe('safeMerge', () => {
rundown: [],
project: {
title: 'existing title',
description: 'existing description',
publicUrl: 'existing public URL',
backstageUrl: 'existing backstageUrl',
publicInfo: 'existing backstageInfo',
backstageInfo: 'existing backstageInfo',
},
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
serverPort: 4001,
editorKey: null,
operatorKey: null,
@@ -42,7 +45,7 @@ describe('safeMerge', () => {
onFinish: [],
},
},
};
} as DatabaseModel;
it('returns existing data if new data is not provided', () => {
const mergedData = safeMerge(existing, undefined);
@@ -51,7 +54,7 @@ describe('safeMerge', () => {
it('merges the rundown key', () => {
const newData = {
rundown: [{ name: 'item 1' }, { name: 'item 2' }],
rundown: [{ title: 'item 1' }, { title: 'item 2' }] as OntimeRundown,
};
const mergedData = safeMerge(existing, newData);
expect(mergedData.rundown).toEqual(newData.rundown);
@@ -64,9 +67,11 @@ describe('safeMerge', () => {
publicInfo: 'new public info',
},
};
// @ts-expect-error -- just testing
const mergedData = safeMerge(existing, newData);
expect(mergedData.project).toEqual({
title: 'new title',
description: 'existing description',
publicUrl: 'existing public URL',
publicInfo: 'new public info',
backstageUrl: 'existing backstageUrl',
@@ -79,12 +84,12 @@ describe('safeMerge', () => {
settings: {
serverPort: 3000,
language: 'pt',
},
} as Settings,
};
const mergedData = safeMerge(existing, newData);
expect(mergedData.settings).toEqual({
app: 'ontime',
version: 2,
version: '2.0.0',
serverPort: 3000,
operatorKey: null,
editorKey: null,
@@ -108,6 +113,7 @@ describe('safeMerge', () => {
},
},
};
//@ts-expect-error -- testing partial merge
const mergedData = safeMerge(existing, newData);
expect(mergedData.osc).toEqual({
portIn: 7777,
@@ -135,7 +141,7 @@ describe('safeMerge', () => {
it('should merge the aliases key when present', () => {
const existingData = {
rundown: [],
event: {
project: {
title: '',
publicUrl: '',
publicInfo: '',
@@ -144,7 +150,7 @@ describe('safeMerge', () => {
},
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
serverPort: 4001,
operatorKey: null,
editorKey: null,
@@ -183,10 +189,13 @@ describe('safeMerge', () => {
onFinish: [],
},
},
};
} as DatabaseModel;
const newData = {
aliases: ['alias1', 'alias2'],
aliases: [
{ enabled: true, alias: 'alias1', pathAndParams: '' },
{ enabled: true, alias: 'alias2', pathAndParams: '' },
] as Alias[],
};
const mergedData = safeMerge(existingData, newData);
@@ -217,6 +226,7 @@ describe('safeMerge', () => {
user3: 'David',
};
//@ts-expect-error -- testing partial merge
const result = safeMerge(existing, newData);
expect(result.userFields).toEqual(expected);
});
@@ -1,6 +1,6 @@
import { Alias, DatabaseModel, LogOrigin, ProjectData } from 'ontime-types';
import { Alias, DatabaseModel, GetInfo, LogOrigin, ProjectData } from 'ontime-types';
import { RequestHandler } from 'express';
import { RequestHandler, Request, Response } from 'express';
import fs from 'fs';
import { networkInterfaces } from 'os';
@@ -9,7 +9,7 @@ import { DataProvider } from '../classes/data-provider/DataProvider.js';
import { failEmptyObjects, failIsNotArray } from '../utils/routerUtils.js';
import { PlaybackService } from '../services/PlaybackService.js';
import { eventStore } from '../stores/EventStore.js';
import { isDocker, resolveDbPath } from '../setup.js';
import { isDocker, pathToStartStyles, resolveDbPath } from '../setup.js';
import { oscIntegration } from '../services/integration-service/OscIntegration.js';
import { logger } from '../classes/Logger.js';
import { deleteAllEvents, notifyChanges } from '../services/rundown-service/RundownService.js';
@@ -107,15 +107,16 @@ const getNetworkInterfaces = () => {
return results;
};
// Create controller for POST request to '/ontime/info'
// Create controller for GET request to '/ontime/info'
// Returns -
export const getInfo = async (req, res) => {
export const getInfo = async (req: Request, res: Response<GetInfo>) => {
const { version, serverPort } = DataProvider.getSettings();
const osc = DataProvider.getOsc();
// get nif and inject localhost
const ni = getNetworkInterfaces();
ni.unshift({ name: 'localhost', address: '127.0.0.1' });
const cssOverride = pathToStartStyles;
// send object with network information
res.status(200).send({
@@ -123,6 +124,7 @@ export const getInfo = async (req, res) => {
version,
serverPort,
osc,
cssOverride,
});
};
@@ -1,3 +1,7 @@
import { GetRundownCached } from 'ontime-types';
import { Request, Response, RequestHandler } from 'express';
import { failEmptyObjects } from '../utils/routerUtils.js';
import {
addEvent,
@@ -8,8 +12,7 @@ import {
reorderEvent,
swapEvents,
} from '../services/rundown-service/RundownService.js';
import { getDelayedRundown } from '../services/rundown-service/delayedRundown.utils.js';
import { RequestHandler } from 'express';
import { getDelayedRundown, getRundownCache } from '../services/rundown-service/delayedRundown.utils.js';
// Create controller for GET request to '/events'
// Returns -
@@ -18,6 +21,13 @@ export const rundownGetAll: RequestHandler = async (_req, res) => {
res.json(delayedRundown);
};
// Create controller for GET request to '/events/cached'
// Returns -
export const rundownGetCached: RequestHandler = async (_req: Request, res: Response<GetRundownCached>) => {
const cachedRundown = getRundownCache();
res.json(cachedRundown);
};
// Create controller for POST request to '/events/'
// Returns -
export const rundownPost: RequestHandler = async (req, res) => {
+2 -1
View File
@@ -1,4 +1,5 @@
import { DatabaseModel } from 'ontime-types';
import { ONTIME_VERSION } from '../ONTIME_VERSION.js';
export const dbModel: DatabaseModel = {
rundown: [],
@@ -12,7 +13,7 @@ export const dbModel: DatabaseModel = {
},
settings: {
app: 'ontime',
version: 2,
version: ONTIME_VERSION,
serverPort: 4001,
editorKey: null,
operatorKey: null,
+4
View File
@@ -4,6 +4,7 @@ import {
rundownApplyDelay,
rundownDelete,
rundownGetAll,
rundownGetCached,
rundownPost,
rundownPut,
rundownReorder,
@@ -19,6 +20,9 @@ import {
export const router = express.Router();
// create route between controller and '/events/cached' endpoint
router.get('/cached', rundownGetCached);
// create route between controller and '/events/' endpoint
router.get('/', rundownGetAll);
@@ -1,4 +1,5 @@
import {
GetRundownCached,
isOntimeBlock,
isOntimeDelay,
isOntimeEvent,
@@ -16,6 +17,11 @@ import { isProduction } from '../../setup.js';
import { deleteAtIndex, insertAtIndex, reorderArray } from '../../utils/arrayUtils.js';
import { _applyDelay } from '../delayUtils.js';
/**
* Keep incremental revision number of rundown for runtime
*/
let rundownRevision = 0;
/**
* Key of rundown in cache
*/
@@ -38,7 +44,25 @@ export function invalidateFromError(errorMessage = 'Found mismatch between store
* Returns rundown with calculated delays
* Ensures request goes through the caching layer
*/
export function getDelayedRundown(): OntimeRundown {
export function getRundownCache(): GetRundownCached {
function calculateRundown() {
const rundown = DataProvider.getRundown();
return calculateRuntimeDelays(rundown);
}
const cached = getCached(delayedRundownCacheKey, calculateRundown);
return {
rundown: cached,
revision: rundownRevision,
};
}
/**
* Returns rundown with calculated delays
* Ensures request goes through the caching layer
*/
export function getDelayedRundown() {
function calculateRundown() {
const rundown = DataProvider.getRundown();
return calculateRuntimeDelays(rundown);
@@ -72,6 +96,8 @@ export async function cachedAdd(eventIndex: number, event: OntimeEvent | OntimeD
runtimeCacheStore.setCached(delayedRundownCacheKey, newDelayedRundown);
// we need to delay updating this to ensure add operation happens on same dataset
await DataProvider.setRundown(newRundown);
rundownRevision++;
}
/**
@@ -113,6 +139,8 @@ export async function cachedEdit(
// we need to delay updating this to ensure edit operation happens on same dataset
await DataProvider.setRundown(updatedRundown);
rundownRevision++;
return newEvent;
}
@@ -147,6 +175,8 @@ export async function cachedDelete(eventId: string) {
}
// we need to delay updating this to ensure edit operation happens on same dataset
await DataProvider.setRundown(updatedRundown);
rundownRevision++;
}
/**
@@ -178,12 +208,15 @@ export async function cachedReorder(eventId: string, from: number, to: number) {
// we need to delay updating this to ensure edit operation happens on same dataset
await DataProvider.setRundown(updatedRundown);
rundownRevision++;
return reorderedEvent;
}
export async function cachedClear() {
await DataProvider.clearRundown();
runtimeCacheStore.setCached(delayedRundownCacheKey, []);
rundownRevision++;
}
/**
@@ -211,6 +244,8 @@ export async function cachedSwap(fromEventId: string, toEventId: string) {
}
await DataProvider.setRundown(rundownToUpdate);
rundownRevision++;
}
export async function cachedApplyDelay(eventId: string) {
@@ -224,6 +259,8 @@ export async function cachedApplyDelay(eventId: string) {
// update
runtimeCacheStore.setCached(delayedRundownCacheKey, cachedRundown);
await DataProvider.setRundown(persistedRundown);
rundownRevision++;
}
/**
+13 -13
View File
@@ -201,7 +201,7 @@ describe('test json parser with valid def', () => {
},
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
timeFormat: '24',
},
viewSettings: {},
@@ -260,7 +260,7 @@ describe('test json parser with valid def', () => {
it('settings are for right app and version', () => {
const settings = parseResponse?.settings;
expect(settings.app).toBe('ontime');
expect(settings.version).toBe(2);
expect(settings.version).toEqual(expect.any(String));
});
it('missing settings', () => {
@@ -387,7 +387,7 @@ describe('test corrupt data', () => {
},
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
serverPort: 4001,
lock: null,
timeFormat: '24',
@@ -410,7 +410,7 @@ describe('test corrupt data', () => {
},
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
serverPort: 4001,
lock: null,
timeFormat: '24',
@@ -427,7 +427,7 @@ describe('test corrupt data', () => {
project: {},
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
serverPort: 4001,
lock: null,
timeFormat: '24',
@@ -444,7 +444,7 @@ describe('test corrupt data', () => {
event: {},
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
},
};
@@ -734,7 +734,7 @@ describe('test aliases import', () => {
rundown: [],
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
},
aliases: [
{
@@ -773,7 +773,7 @@ describe('test userFields import', () => {
rundown: [],
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
},
userFields: testUserFields,
};
@@ -800,7 +800,7 @@ describe('test userFields import', () => {
rundown: [],
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
},
userFields: testUserFields,
};
@@ -814,7 +814,7 @@ describe('test userFields import', () => {
rundown: [],
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
},
};
@@ -828,7 +828,7 @@ describe('test userFields import', () => {
rundown: [],
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
},
userFields: {
notThis: 'this shouldng be accepted',
@@ -847,7 +847,7 @@ describe('test views import', () => {
rundown: [],
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
},
viewSettings: {
normalColor: '#ffffffcc',
@@ -881,7 +881,7 @@ describe('test views import', () => {
rundown: [],
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
},
};
const parsed = parseViewSettings(testData);
@@ -34,13 +34,13 @@ describe('mergeObject()', () => {
third: 'yes',
};
const b = {
first: 0,
first: 'no',
second: null,
third: '',
};
const merged = mergeObject(a, b);
expect(merged).toStrictEqual({
first: 0,
first: 'no',
second: null,
third: '',
});
@@ -57,6 +57,7 @@ describe('mergeObject()', () => {
third: '',
forth: 'not-this',
};
// @ts-expect-error -- testing changing type
const merged = mergeObject(a, b);
expect(merged).toStrictEqual({
first: 0,
@@ -83,6 +84,7 @@ describe('mergeObject()', () => {
},
};
// @ts-expect-error -- testing missing property
const merged = mergeObject(a, b);
expect(merged.name).toBe('Doe');
+1 -4
View File
@@ -331,7 +331,7 @@ export const parseExcel = (excelData: unknown[][], options?: Partial<ExcelImport
project: projectData,
settings: {
app: 'ontime',
version: 2,
version: '2.0.0',
},
userFields: customUserFields,
projectMetadata: projectMetadata,
@@ -474,9 +474,6 @@ export const fileHandler = async (file: string, options: ExcelImportOptions): Pr
let uploadedJson = null;
uploadedJson = JSON.parse(rawdata);
if (uploadedJson.settings.version !== 2) {
throw new Error(`Project version unknown ${uploadedJson.settings.version}`);
}
res.data = await parseJson(uploadedJson);
// delete file
+1
View File
@@ -114,6 +114,7 @@ export const parseSettings = (data): Settings => {
console.log('ERROR: unknown app version, skipping');
} else {
const settings = {
version: dbModel.settings.version,
serverPort: s.serverPort || dbModel.settings.serverPort,
editorKey: s.editorKey || null,
operatorKey: s.operatorKey || null,