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:
Carlos Valente
2026-03-08 16:22:12 +01:00
committed by GitHub
parent 9516ac21bb
commit 1849b4d39f
501 changed files with 2678 additions and 4654 deletions
@@ -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)', () => {
+3 -4
View File
@@ -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 {
+4 -9
View File
@@ -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;
}
}
+2 -2
View File
@@ -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) => {
+9 -10
View File
@@ -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,
+5 -5
View File
@@ -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';
/**