mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-12 10:53:51 +00:00
V3 project migration (#1652)
* migrate settings * migrate viewsettings * migrate url preset * migrate project data * migrate custom fields * migrate automations * migrate rundown * lint * return custom field translation table * check regex * new url type * refactor * migrate old OSC subscriptions * migrate old http subscriptions * update comments * migrate the whole db * remove automation logging unlis there is an error * return a new object * refactor: copy currup is only used in one place * make a copy of original migrated file * refactor: ensure image flder is part of project service init * add entrys to groups * small cleanup * just drop incorrect custom fields in the default data parser
This commit is contained in:
committed by
GitHub
parent
35347e8d63
commit
9ebb3decdb
@@ -0,0 +1,492 @@
|
||||
import {
|
||||
AutomationSettings,
|
||||
CustomFields,
|
||||
EndAction,
|
||||
ProjectData,
|
||||
Rundown,
|
||||
Settings,
|
||||
SupportedEntry,
|
||||
TimerLifeCycle,
|
||||
TimerType,
|
||||
TimeStrategy,
|
||||
URLPreset,
|
||||
ViewSettings,
|
||||
} from 'ontime-types';
|
||||
import * as v3 from './db.migration.v3.js';
|
||||
import { dbModel } from '../../../models/dataModel.js';
|
||||
import { ONTIME_VERSION } from '../../../ONTIME_VERSION.js';
|
||||
|
||||
describe('v3 to v4', () => {
|
||||
const oldDb = {
|
||||
rundown: [
|
||||
{
|
||||
id: 'event1',
|
||||
type: 'event',
|
||||
cue: '123',
|
||||
title: 'ABC',
|
||||
note: 'DEF',
|
||||
endAction: EndAction.None,
|
||||
timerType: TimerType.CountDown,
|
||||
countToEnd: false,
|
||||
linkStart: false,
|
||||
timeStrategy: TimeStrategy.LockDuration,
|
||||
timeStart: 0,
|
||||
timeEnd: 10,
|
||||
duration: 10,
|
||||
isPublic: false,
|
||||
skip: false,
|
||||
colour: 'blue',
|
||||
timeWarning: 5,
|
||||
timeDanger: 2,
|
||||
custom: {
|
||||
song: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
doseNotExist: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
},
|
||||
revision: 0,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
{ id: 'block0', type: 'block', title: 'BLOCK 0' },
|
||||
{
|
||||
id: 'event2',
|
||||
type: SupportedEntry.Event,
|
||||
cue: '124',
|
||||
title: 'ABC',
|
||||
note: 'DEF',
|
||||
endAction: EndAction.None,
|
||||
timerType: TimerType.CountDown,
|
||||
countToEnd: false,
|
||||
linkStart: false,
|
||||
timeStrategy: TimeStrategy.LockDuration,
|
||||
timeStart: 0,
|
||||
timeEnd: 10,
|
||||
duration: 10,
|
||||
isPublic: false,
|
||||
skip: false,
|
||||
colour: 'blue',
|
||||
timeWarning: 5,
|
||||
timeDanger: 2,
|
||||
custom: {
|
||||
wow: 'http://www.agoodimage.com',
|
||||
artist: 'Ib Andersen',
|
||||
},
|
||||
triggers: [{ id: 'testTrig', title: 'Test trigger', trigger: TimerLifeCycle.onStart, automationId: '1' }],
|
||||
revision: 0,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
{
|
||||
id: 'event3',
|
||||
type: SupportedEntry.Event,
|
||||
cue: '125',
|
||||
// title: 'ABC', this has a missing field
|
||||
note: 'DEF',
|
||||
endAction: EndAction.None,
|
||||
timerType: TimerType.CountDown,
|
||||
countToEnd: false,
|
||||
linkStart: false,
|
||||
timeStrategy: TimeStrategy.LockDuration,
|
||||
timeStart: 0,
|
||||
timeEnd: 10,
|
||||
duration: 10,
|
||||
isPublic: false,
|
||||
skip: false,
|
||||
colour: 'blue',
|
||||
timeWarning: 5,
|
||||
timeDanger: 2,
|
||||
custom: {
|
||||
wow: 'http://www.agoodimage.com',
|
||||
artist: 'Ib Andersen',
|
||||
},
|
||||
triggers: [{ id: 'testTrig', title: 'Test trigger', trigger: TimerLifeCycle.onStart, automationId: '1' }],
|
||||
revision: 0,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
{ id: 'block1', type: 'block', title: 'BLOCK 1' },
|
||||
{ id: 'delay', type: 'delay', duration: 1000 },
|
||||
],
|
||||
project: {
|
||||
title: 'Eurovision Song Contest',
|
||||
description: 'Turin 2022',
|
||||
publicUrl: '123',
|
||||
publicInfo: '456',
|
||||
backstageUrl: 'www.github.com/cpvalente/ontime',
|
||||
backstageInfo: 'Rehearsal Schedule - Turin 2022\nAll performers to wear full costumes for 1st rehearsal',
|
||||
},
|
||||
settings: {
|
||||
version: '3.3.3',
|
||||
serverPort: 4001,
|
||||
editorKey: null,
|
||||
operatorKey: null,
|
||||
timeFormat: '24',
|
||||
language: 'en',
|
||||
},
|
||||
viewSettings: {
|
||||
overrideStyles: false,
|
||||
normalColor: '#ffffffcc',
|
||||
warningColor: '#ffa528',
|
||||
dangerColor: '#ff7300',
|
||||
freezeEnd: false,
|
||||
endMessage: '',
|
||||
},
|
||||
urlPresets: [
|
||||
{
|
||||
enabled: true,
|
||||
alias: 'clock',
|
||||
pathAndParams:
|
||||
'timer?showLeadingZeros=true&timerType=clock&hideClock=true&hideCards=true&hideProgress=true&hideMessage=true&hideSecondary=true&hideLogo=true',
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
alias: 'minimal',
|
||||
pathAndParams:
|
||||
'timer?showLeadingZeros=true&hideClock=true&hideCards=true&hideProgress=true&hideMessage=true&hideSecondary=true&hideLogo=true',
|
||||
},
|
||||
],
|
||||
customFields: {
|
||||
song: {
|
||||
label: 'Song and Dance',
|
||||
type: 'string',
|
||||
colour: '#339E4E',
|
||||
},
|
||||
artist: {
|
||||
label: 'Artist and Host',
|
||||
type: 'string',
|
||||
colour: '#3E75E8',
|
||||
},
|
||||
wow: {
|
||||
label: 'WOW 123',
|
||||
type: 'image',
|
||||
colour: '#E80000',
|
||||
},
|
||||
},
|
||||
automation: {
|
||||
enabledAutomations: true,
|
||||
enabledOscIn: true,
|
||||
oscPortIn: 8888,
|
||||
triggers: [],
|
||||
automations: {},
|
||||
},
|
||||
};
|
||||
|
||||
test('migrate settings', () => {
|
||||
const expectSettings: Settings = {
|
||||
version: ONTIME_VERSION,
|
||||
serverPort: 4001,
|
||||
editorKey: null,
|
||||
operatorKey: null,
|
||||
timeFormat: '24',
|
||||
language: 'en',
|
||||
};
|
||||
const newSettings = v3.migrateSettings(oldDb);
|
||||
expect(newSettings).toEqual(expectSettings);
|
||||
});
|
||||
|
||||
test('migrate view settings', () => {
|
||||
const expectViewSettings: ViewSettings = {
|
||||
dangerColor: '#ff7300',
|
||||
normalColor: '#ffffffcc',
|
||||
overrideStyles: false,
|
||||
warningColor: '#ffa528',
|
||||
};
|
||||
const newViewSettings = v3.migrateViewSettings(oldDb);
|
||||
expect(newViewSettings).toEqual(expectViewSettings);
|
||||
});
|
||||
|
||||
test('migrate url preset', () => {
|
||||
const expectUrlPresets: URLPreset[] = [
|
||||
{
|
||||
enabled: true,
|
||||
alias: 'clock',
|
||||
target: 'timer',
|
||||
search:
|
||||
'showLeadingZeros=true&timerType=clock&hideClock=true&hideCards=true&hideProgress=true&hideMessage=true&hideSecondary=true&hideLogo=true',
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
alias: 'minimal',
|
||||
target: 'timer',
|
||||
search:
|
||||
'showLeadingZeros=true&hideClock=true&hideCards=true&hideProgress=true&hideMessage=true&hideSecondary=true&hideLogo=true',
|
||||
},
|
||||
];
|
||||
const newUrlPreset = v3.migrateURLPresets(oldDb);
|
||||
expect(newUrlPreset).toEqual(expectUrlPresets);
|
||||
});
|
||||
|
||||
test('migrate project data', () => {
|
||||
const expectProjectData: ProjectData = {
|
||||
title: 'Eurovision Song Contest',
|
||||
description: 'Turin 2022',
|
||||
url: 'www.github.com/cpvalente/ontime',
|
||||
info: 'Rehearsal Schedule - Turin 2022\nAll performers to wear full costumes for 1st rehearsal',
|
||||
logo: null,
|
||||
custom: [],
|
||||
};
|
||||
const newProjectData = v3.migrateProjectData(oldDb);
|
||||
expect(newProjectData).toEqual(expectProjectData);
|
||||
});
|
||||
|
||||
test('migrate custom fields', () => {
|
||||
const expectCustomFields: CustomFields = {
|
||||
Song_and_Dance: {
|
||||
label: 'Song and Dance',
|
||||
type: 'text',
|
||||
colour: '#339E4E',
|
||||
},
|
||||
Artist_and_Host: {
|
||||
label: 'Artist and Host',
|
||||
type: 'text',
|
||||
colour: '#3E75E8',
|
||||
},
|
||||
WOW_123: {
|
||||
label: 'WOW 123',
|
||||
type: 'image',
|
||||
colour: '#E80000',
|
||||
},
|
||||
};
|
||||
const { customFields, translationTable } = v3.migrateCustomFields(oldDb)!;
|
||||
expect(customFields).toEqual(expectCustomFields);
|
||||
|
||||
expect(translationTable).toEqual(
|
||||
new Map([
|
||||
['song', 'Song_and_Dance'],
|
||||
['artist', 'Artist_and_Host'],
|
||||
['wow', 'WOW_123'],
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
test('migrate rundown', () => {
|
||||
const expectedRundown: Rundown = {
|
||||
id: 'default',
|
||||
title: 'Default',
|
||||
order: ['event1', 'block0', 'block1'],
|
||||
flatOrder: ['event1', 'block0', 'event2', 'event3', 'block1', 'delay'],
|
||||
entries: {
|
||||
event1: {
|
||||
id: 'event1',
|
||||
type: SupportedEntry.Event,
|
||||
cue: '123',
|
||||
title: 'ABC',
|
||||
note: 'DEF',
|
||||
endAction: EndAction.None,
|
||||
timerType: TimerType.CountDown,
|
||||
countToEnd: false,
|
||||
linkStart: false,
|
||||
timeStrategy: TimeStrategy.LockDuration,
|
||||
timeStart: 0,
|
||||
timeEnd: 10,
|
||||
duration: 10,
|
||||
skip: false,
|
||||
colour: 'blue',
|
||||
timeWarning: 5,
|
||||
timeDanger: 2,
|
||||
custom: { Song_and_Dance: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit' },
|
||||
triggers: [],
|
||||
revision: -1,
|
||||
flag: false,
|
||||
parent: null,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
block0: {
|
||||
id: 'block0',
|
||||
type: SupportedEntry.Block,
|
||||
title: 'BLOCK 0',
|
||||
colour: '',
|
||||
custom: {},
|
||||
duration: 0,
|
||||
entries: ['event2', 'event3'],
|
||||
isFirstLinked: false,
|
||||
note: '',
|
||||
revision: -1,
|
||||
targetDuration: null,
|
||||
timeEnd: null,
|
||||
timeStart: null,
|
||||
},
|
||||
event2: {
|
||||
id: 'event2',
|
||||
type: SupportedEntry.Event,
|
||||
cue: '124',
|
||||
title: 'ABC',
|
||||
note: 'DEF',
|
||||
endAction: EndAction.None,
|
||||
timerType: TimerType.CountDown,
|
||||
countToEnd: false,
|
||||
linkStart: false,
|
||||
timeStrategy: TimeStrategy.LockDuration,
|
||||
timeStart: 0,
|
||||
timeEnd: 10,
|
||||
duration: 10,
|
||||
skip: false,
|
||||
colour: 'blue',
|
||||
timeWarning: 5,
|
||||
timeDanger: 2,
|
||||
custom: {
|
||||
WOW_123: 'http://www.agoodimage.com',
|
||||
Artist_and_Host: 'Ib Andersen',
|
||||
},
|
||||
triggers: [{ id: 'testTrig', title: 'Test trigger', trigger: TimerLifeCycle.onStart, automationId: '1' }],
|
||||
flag: false,
|
||||
parent: 'block0',
|
||||
revision: -1,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
event3: {
|
||||
id: 'event3',
|
||||
type: SupportedEntry.Event,
|
||||
cue: '125',
|
||||
//@ts-expect-error - if a field is missing we should pass it through a let our normal import fix it
|
||||
title: undefined,
|
||||
note: 'DEF',
|
||||
endAction: EndAction.None,
|
||||
timerType: TimerType.CountDown,
|
||||
countToEnd: false,
|
||||
linkStart: false,
|
||||
timeStrategy: TimeStrategy.LockDuration,
|
||||
timeStart: 0,
|
||||
timeEnd: 10,
|
||||
duration: 10,
|
||||
skip: false,
|
||||
colour: 'blue',
|
||||
timeWarning: 5,
|
||||
timeDanger: 2,
|
||||
custom: {
|
||||
WOW_123: 'http://www.agoodimage.com',
|
||||
Artist_and_Host: 'Ib Andersen',
|
||||
},
|
||||
triggers: [{ id: 'testTrig', title: 'Test trigger', trigger: TimerLifeCycle.onStart, automationId: '1' }],
|
||||
flag: false,
|
||||
parent: 'block0',
|
||||
revision: -1,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
block1: {
|
||||
id: 'block1',
|
||||
type: SupportedEntry.Block,
|
||||
title: 'BLOCK 1',
|
||||
colour: '',
|
||||
custom: {},
|
||||
duration: 0,
|
||||
entries: ['delay'],
|
||||
isFirstLinked: false,
|
||||
note: '',
|
||||
revision: -1,
|
||||
targetDuration: null,
|
||||
timeEnd: null,
|
||||
timeStart: null,
|
||||
},
|
||||
delay: {
|
||||
type: SupportedEntry.Delay,
|
||||
id: 'delay',
|
||||
duration: 1000,
|
||||
parent: 'block1',
|
||||
},
|
||||
},
|
||||
|
||||
revision: 0,
|
||||
};
|
||||
const translationTable = new Map([
|
||||
['song', 'Song_and_Dance'],
|
||||
['artist', 'Artist_and_Host'],
|
||||
['wow', 'WOW_123'],
|
||||
]);
|
||||
|
||||
//@ts-expect-error - we know the default rundown should appear
|
||||
expect(v3.migrateRundown(oldDb, translationTable)['default']).toStrictEqual(expectedRundown);
|
||||
});
|
||||
|
||||
describe('migrate old automation', () => {
|
||||
test('osc', () => {
|
||||
const oldData = {
|
||||
portIn: 8881,
|
||||
portOut: 55890,
|
||||
targetIP: '127.0.0.1',
|
||||
enabledIn: true,
|
||||
enabledOut: true,
|
||||
subscriptions: [
|
||||
{
|
||||
id: '23f4d8',
|
||||
cycle: 'onClock',
|
||||
address: '/test',
|
||||
payload: 'bip',
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const expectedAutomation: AutomationSettings = {
|
||||
enabledAutomations: true,
|
||||
enabledOscIn: true,
|
||||
oscPortIn: 8881,
|
||||
triggers: [
|
||||
{
|
||||
id: '23f4d8-T',
|
||||
title: 'Migrated Trigger 23f4d8',
|
||||
trigger: TimerLifeCycle.onClock,
|
||||
automationId: '23f4d8-A',
|
||||
},
|
||||
],
|
||||
automations: {
|
||||
'23f4d8-A': {
|
||||
id: '23f4d8-A',
|
||||
title: 'Migrated Automation 23f4d8',
|
||||
filterRule: 'any',
|
||||
filters: [],
|
||||
outputs: [{ type: 'osc', targetIP: '127.0.0.1', targetPort: 55890, address: '/test', args: 'bip' }],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(v3.migrateAutomations({ osc: oldData })).toStrictEqual(expectedAutomation);
|
||||
});
|
||||
test('http', () => {
|
||||
const oldData = {
|
||||
enabledOut: true,
|
||||
subscriptions: [
|
||||
{
|
||||
id: '1ge4r8',
|
||||
cycle: 'onClock',
|
||||
message: 'http://www.test.com',
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const expectedAutomation: AutomationSettings = {
|
||||
enabledAutomations: true,
|
||||
enabledOscIn: true,
|
||||
oscPortIn: dbModel.automation.oscPortIn,
|
||||
triggers: [
|
||||
{
|
||||
id: '1ge4r8-T',
|
||||
title: 'Migrated Trigger 1ge4r8',
|
||||
trigger: TimerLifeCycle.onClock,
|
||||
automationId: '1ge4r8-A',
|
||||
},
|
||||
],
|
||||
automations: {
|
||||
'1ge4r8-A': {
|
||||
id: '1ge4r8-A',
|
||||
title: 'Migrated Automation 1ge4r8',
|
||||
filterRule: 'any',
|
||||
filters: [],
|
||||
outputs: [{ type: 'http', url: 'http://www.test.com' }],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(v3.migrateAutomations({ http: oldData })).toStrictEqual(expectedAutomation);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user