mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-14 03:43:50 +00:00
event cucle (#76)
* install sass * refact: integration settings - OSC in its own HTTP endpoint - OSC settings have own object in db * refact: simplify event cycle * refact: restructure external triggers http * refact: restructure external triggers osc+socket * refact: restructure data updates * feat: osc integration class * IO improvements - timer uses osc integration - create trigger handler to manage external triggers * refact: refract state machine update * Integration: simple HTTP Client * Integration: http options in datamodel * Integration: call http send on life cycle * feat/62-logging: fix issue #71
This commit is contained in:
@@ -6,7 +6,6 @@ import {
|
||||
validateEventv1,
|
||||
} from '../parser.js';
|
||||
import { dbModelv1 as dbModel } from '../../models/dataModel.js';
|
||||
import { describe } from 'jest-circus';
|
||||
|
||||
describe('test json parser with valid def', () => {
|
||||
const testData = {
|
||||
@@ -133,6 +132,7 @@ describe('test json parser with valid def', () => {
|
||||
revision: 0,
|
||||
id: '4b31',
|
||||
};
|
||||
expect(first).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it('loaded event settings', () => {
|
||||
@@ -192,7 +192,7 @@ describe('test parser edge cases', () => {
|
||||
|
||||
const parseResponse = await parseJsonv1(testData);
|
||||
expect(console.log).toHaveBeenCalledWith(
|
||||
'ERROR: ID colision on import, skipping'
|
||||
'ERROR: ID collision on import, skipping'
|
||||
);
|
||||
expect(parseResponse?.events.length).toBe(1);
|
||||
});
|
||||
@@ -267,11 +267,7 @@ describe('test corrupt data', () => {
|
||||
app: 'ontime',
|
||||
version: 1,
|
||||
serverPort: 4001,
|
||||
oscInPort: 8888,
|
||||
oscOutPort: 9999,
|
||||
oscOutIP: '127.0.0.1',
|
||||
oscEnabled: false,
|
||||
lock: false,
|
||||
lock: null,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -293,11 +289,7 @@ describe('test corrupt data', () => {
|
||||
app: 'ontime',
|
||||
version: 1,
|
||||
serverPort: 4001,
|
||||
oscInPort: 8888,
|
||||
oscOutPort: 9999,
|
||||
oscOutIP: '127.0.0.1',
|
||||
oscEnabled: false,
|
||||
lock: false,
|
||||
lock: null,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -313,11 +305,7 @@ describe('test corrupt data', () => {
|
||||
app: 'ontime',
|
||||
version: 1,
|
||||
serverPort: 4001,
|
||||
oscInPort: 8888,
|
||||
oscOutPort: 9999,
|
||||
oscOutIP: '127.0.0.1',
|
||||
oscEnabled: false,
|
||||
lock: false,
|
||||
lock: null,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -430,7 +418,6 @@ describe('test makeString function', () => {
|
||||
expect(converted).toBe(expected);
|
||||
|
||||
val = { doing: 'testing' };
|
||||
expected = 'testing';
|
||||
converted = makeString(val, 'fallback');
|
||||
expect(converted).toBe('fallback');
|
||||
});
|
||||
@@ -477,8 +464,8 @@ describe('test parseExcel function', () => {
|
||||
|
||||
const expectedParsedEvents = [
|
||||
{
|
||||
timeStart: 28800000,
|
||||
timeEnd: 32410000,
|
||||
timeStart: 25200000,
|
||||
timeEnd: 28810000,
|
||||
title: 'Guest Welcome',
|
||||
presenter: 'Carlos',
|
||||
subtitle: 'Getting things started',
|
||||
@@ -487,8 +474,8 @@ describe('test parseExcel function', () => {
|
||||
type: 'event',
|
||||
},
|
||||
{
|
||||
timeStart: 32400000,
|
||||
timeEnd: 34200000,
|
||||
timeStart: 28800000,
|
||||
timeEnd: 30600000,
|
||||
title: 'A song from the hearth',
|
||||
presenter: 'Still Carlos',
|
||||
subtitle: 'Derailing early',
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { describe } from 'jest-circus';
|
||||
import { excelDateStringToMillis, stringFromMillis } from '../time.js';
|
||||
|
||||
describe('test string to milis function', () => {
|
||||
@@ -60,12 +59,15 @@ describe('test string to milis function', () => {
|
||||
|
||||
describe('test excel date parser', () => {
|
||||
it('parses the given dates correctly', () => {
|
||||
const d0 = '1899-12-30T00:00:00.000Z';
|
||||
const d1 = '1899-12-30T08:00:00.000Z';
|
||||
const d2 = '1899-12-30T08:30:00.000Z';
|
||||
|
||||
const d0Millis = 0;
|
||||
const d1Millis = 28800000;
|
||||
const d2Millis = 30600000;
|
||||
|
||||
expect(excelDateStringToMillis(d0)).toBe(d0Millis);
|
||||
expect(excelDateStringToMillis(d1)).toBe(d1Millis);
|
||||
expect(excelDateStringToMillis(d2)).toBe(d2Millis);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// test cleanURL()
|
||||
|
||||
import {cleanURL} from "../url";
|
||||
|
||||
describe('url is correctly formatted', () => {
|
||||
it('has no leading spaces', () => {
|
||||
const test = ' http://testing';
|
||||
const expected = 'http://testing';
|
||||
expect(cleanURL(test)).toBe(expected);
|
||||
});
|
||||
|
||||
it('has no trailing spaces', () => {
|
||||
const test = 'http://testing ';
|
||||
const expected = 'http://testing';
|
||||
expect(cleanURL(test)).toBe(expected);
|
||||
});
|
||||
|
||||
it('doesnt contain spaces', () => {
|
||||
const test = 'http://t e s t i n g';
|
||||
const expected = 'http://t%20e%20s%20t%20i%20n%20g';
|
||||
expect(cleanURL(test)).toBe(expected);
|
||||
});
|
||||
|
||||
it('only contains allowed characters', () => {
|
||||
const test = 'http://<>[]{}|\^';
|
||||
const expected = 'http://';
|
||||
expect(cleanURL(test)).toBe(expected);
|
||||
});
|
||||
|
||||
it('begins with http://', () => {
|
||||
const test = 'ontime.com';
|
||||
const expected = 'http://ontime.com';
|
||||
expect(cleanURL(test)).toBe(expected);
|
||||
});
|
||||
|
||||
});
|
||||
+66
-19
@@ -16,7 +16,7 @@ export const ALLOWED_TYPES = ['JSON', 'EXCEL'];
|
||||
|
||||
/**
|
||||
* @description Middleware function that checks file type and calls relevant parser
|
||||
* @argument {string} file - reference to file
|
||||
* @param {string} file - reference to file
|
||||
* @return {object} - parse result message
|
||||
*/
|
||||
export const fileHandler = async (file) => {
|
||||
@@ -82,7 +82,7 @@ export const fileHandler = async (file) => {
|
||||
|
||||
/**
|
||||
* @description Excel array parser
|
||||
* @argument {array} excelData - array with excel sheet
|
||||
* @param {array} excelData - array with excel sheet
|
||||
* @returns {object} - parsed object
|
||||
*/
|
||||
export const parseExcelv1 = async (excelData) => {
|
||||
@@ -196,11 +196,12 @@ export const parseExcelv1 = async (excelData) => {
|
||||
|
||||
/**
|
||||
* @description JSON parser function for v1 of data system
|
||||
* @argument {object} jsonData - json data JSON object to be parsed
|
||||
* @param {object} jsonData - json data JSON object to be parsed
|
||||
* @param {boolean} [enforce=false] - flag, tells to create an object anyway
|
||||
* @returns {object} - parsed object
|
||||
*/
|
||||
|
||||
export const parseJsonv1 = async (jsonData) => {
|
||||
export const parseJsonv1 = async (jsonData, enforce=false) => {
|
||||
if (!jsonData || typeof jsonData !== 'object') {
|
||||
console.log('ERROR: Invalid JSON format');
|
||||
return -1;
|
||||
@@ -213,9 +214,9 @@ export const parseJsonv1 = async (jsonData) => {
|
||||
let events = [];
|
||||
let ids = [];
|
||||
for (const e of jsonData.events) {
|
||||
// doublecheck unique ids
|
||||
// double check unique ids
|
||||
if (ids.indexOf(e?.id) !== -1) {
|
||||
console.log('ERROR: ID colision on import, skipping');
|
||||
console.log('ERROR: ID collision on import, skipping');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -243,13 +244,17 @@ export const parseJsonv1 = async (jsonData) => {
|
||||
// write to db
|
||||
returnData.events = events;
|
||||
console.log(`Uploaded file with ${numEntries} entries`);
|
||||
} else if (enforce) {
|
||||
returnData.events = [];
|
||||
console.log(`Created events object in db`);
|
||||
}
|
||||
|
||||
if ('event' in jsonData) {
|
||||
console.log('Found event data, importing...');
|
||||
const e = jsonData.event;
|
||||
// filter known properties
|
||||
const event = {
|
||||
|
||||
// filter known properties and write to db
|
||||
returnData.event = {
|
||||
...dbModelv1.event,
|
||||
title: e.title || dbModelv1.event.title,
|
||||
url: e.url || dbModelv1.event.url,
|
||||
@@ -257,9 +262,9 @@ export const parseJsonv1 = async (jsonData) => {
|
||||
backstageInfo: e.backstageInfo || dbModelv1.event.backstageInfo,
|
||||
endMessage: e.endMessage || dbModelv1.event.endMessage,
|
||||
};
|
||||
|
||||
// write to db
|
||||
returnData.event = event;
|
||||
} else if (enforce) {
|
||||
returnData.event = dbModelv1.event;
|
||||
console.log(`Created event object in db`);
|
||||
}
|
||||
|
||||
// Settings handled partially
|
||||
@@ -271,11 +276,9 @@ export const parseJsonv1 = async (jsonData) => {
|
||||
if (s.app == null || s.version == null) {
|
||||
console.log('ERROR: unknown app version, skipping');
|
||||
} else {
|
||||
let settings = {};
|
||||
|
||||
if (s.oscInPort) settings.oscInPort = s.oscInPort;
|
||||
if (s.oscOutPort) settings.oscOutPort = s.oscOutPort;
|
||||
if (s.oscOutIP) settings.oscOutIP = s.oscOutIP;
|
||||
let settings = {
|
||||
lock: s.lock || null,
|
||||
};
|
||||
|
||||
// write to db
|
||||
returnData.settings = {
|
||||
@@ -283,6 +286,49 @@ export const parseJsonv1 = async (jsonData) => {
|
||||
...settings,
|
||||
};
|
||||
}
|
||||
} else if (enforce) {
|
||||
returnData.settings = dbModelv1.settings;
|
||||
console.log(`Created settings object in db`);
|
||||
}
|
||||
|
||||
// Import OSC settings if any
|
||||
if ('osc' in jsonData) {
|
||||
console.log('Found OSC definition, importing...');
|
||||
const s = jsonData.osc;
|
||||
let osc = {};
|
||||
|
||||
if (s.port) osc.port = s.port;
|
||||
if (s.portOut) osc.portOut = s.portOut;
|
||||
if (s.targetIP) osc.targetIP = s.targetIP;
|
||||
if (s.enabled) osc.enabled = s.enabled;
|
||||
|
||||
// write to db
|
||||
returnData.osc = {
|
||||
...dbModelv1.osc,
|
||||
...osc,
|
||||
};
|
||||
} else if (enforce) {
|
||||
returnData.osc = dbModelv1.osc;
|
||||
console.log(`Created osc object in db`);
|
||||
}
|
||||
|
||||
// Import HTTP settings if any
|
||||
if ('http' in jsonData) {
|
||||
console.log('Found HTTP definition, importing...');
|
||||
const h = jsonData.osc;
|
||||
let http = {};
|
||||
|
||||
if (h.user) http.user = h.user;
|
||||
if (h.pwd) http.pwd = h.pwd;
|
||||
|
||||
// write to db
|
||||
returnData.http = {
|
||||
...dbModelv1.http,
|
||||
...http,
|
||||
};
|
||||
} else if (enforce) {
|
||||
returnData.http = dbModelv1.http;
|
||||
console.log(`Created http object in db`);
|
||||
}
|
||||
|
||||
return returnData;
|
||||
@@ -292,7 +338,7 @@ export const parseJsonv1 = async (jsonData) => {
|
||||
* @description Ensures variable is string, it skips object types
|
||||
* @param {any} val - variable to convert
|
||||
* @param {string} [fallback=''] - fallback value
|
||||
* @returns {string} - value as string or fallback if not possibe
|
||||
* @returns {string} - value as string or fallback if not possible
|
||||
*/
|
||||
export const makeString = (val, fallback = '') => {
|
||||
if (typeof val === 'string') return val;
|
||||
@@ -348,7 +394,7 @@ export const validateEventv1 = (eventArgs) => {
|
||||
|
||||
/**
|
||||
* @description Delete file from system
|
||||
* @argument {string} file - reference to file
|
||||
* @param {string} file - reference to file
|
||||
*/
|
||||
const deleteFile = async (file) => {
|
||||
// delete a file
|
||||
@@ -361,7 +407,8 @@ const deleteFile = async (file) => {
|
||||
|
||||
/**
|
||||
* @description Delete file from system
|
||||
* @argument {string} file - reference to file
|
||||
* @param {string} file - reference to file
|
||||
* @returns {boolean} - whether file is valid JSON
|
||||
*/
|
||||
export const validateFile = (file) => {
|
||||
try {
|
||||
|
||||
@@ -40,9 +40,8 @@ export const stringFromMillis = (
|
||||
*/
|
||||
export const excelDateStringToMillis = (excelDate) => {
|
||||
const date = new Date(excelDate);
|
||||
|
||||
if (date instanceof Date && !isNaN(date)) {
|
||||
const h = date.getHours();
|
||||
const h = date.getUTCHours();
|
||||
const m = date.getMinutes();
|
||||
const s = date.getSeconds();
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @description Cleans given url
|
||||
* @param {string} url - URL to be checked
|
||||
* @returns {string} Sanitized url
|
||||
*/
|
||||
export const cleanURL = (url) => {
|
||||
|
||||
// trim whitespaces
|
||||
let r = url.trim();
|
||||
|
||||
// clear any whitespaces
|
||||
r = r.split(' ').join('%20');
|
||||
|
||||
// contain only allowed characters
|
||||
r = r.replace(/([^\x00-\x7F]|[@\s<>\[\]{}|\\^])+/g, '')
|
||||
|
||||
// starts with http://
|
||||
if (!r.startsWith('http://')) r = `http://${r}`
|
||||
|
||||
return r;
|
||||
}
|
||||
Reference in New Issue
Block a user