Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: rename project #1108

Merged
merged 9 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/client/src/common/api/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export async function renameProject(filename: string, newFilename: string): Prom
const url = `${dbPath}/${filename}/rename`;
const decodedUrl = decodeURIComponent(url);
const res = await axios.put(decodedUrl, {
filename: newFilename,
newFilename,
});
return res.data;
}
Expand Down
80 changes: 27 additions & 53 deletions apps/server/src/api-data/db/db.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,17 @@ import {
} from 'ontime-types';
import { getErrorMessage } from 'ontime-utils';

import { join } from 'path';
import { existsSync } from 'fs';
import type { Request, Response } from 'express';

import { failEmptyObjects } from '../../utils/routerUtils.js';
import { resolveDbDirectory } from '../../setup/index.js';

import { doesProjectExist, handleUploaded } from '../../services/project-service/projectServiceUtils.js';
import * as projectService from '../../services/project-service/ProjectService.js';
import { doesProjectExist, upload, validateProjectFiles } from '../../services/project-service/projectServiceUtils.js';
import { oscIntegration } from '../../services/integration-service/OscIntegration.js';
import { httpIntegration } from '../../services/integration-service/HttpIntegration.js';
import { DataProvider } from '../../classes/data-provider/DataProvider.js';

export async function patchPartialProjectFile(req: Request, res: Response<DatabaseModel | ErrorResponse>) {
// all fields are optional in validation
if (failEmptyObjects(req.body, res)) {
res.status(400).send({ message: 'No field found to patch' });
return;
}

try {
const { rundown, project, settings, viewSettings, urlPresets, customFields, osc, http } = req.body;
const patchDb: DatabaseModel = { rundown, project, settings, viewSettings, urlPresets, customFields, osc, http };

const newData = await projectService.applyDataModel(patchDb);
const newData = await projectService.patchCurrentProject(patchDb);

res.status(200).send(newData);
} catch (error) {
Expand Down Expand Up @@ -77,10 +63,8 @@ export async function createProjectFile(req: Request, res: Response<{ filename:
*/
export async function projectDownload(req: Request, res: Response) {
const { filename } = req.body;
const pathToFile = join(resolveDbDirectory, filename);

// Check if the file exists before attempting to download
if (!existsSync(pathToFile)) {
const pathToFile = doesProjectExist(filename);
if (!pathToFile) {
return res.status(404).send({ message: `Project ${filename} not found.` });
}

Expand All @@ -94,6 +78,7 @@ export async function projectDownload(req: Request, res: Response) {

/**
* uploads, parses and applies the data from a given file
* Pretty much loadProject but with the extra upload step
*/
export async function postProjectFile(req: Request, res: Response<MessageResponse | ErrorResponse>) {
if (!req.file) {
Expand All @@ -102,24 +87,18 @@ export async function postProjectFile(req: Request, res: Response<MessageRespons
}

try {
const options = req.query;
const { filename, path } = req.file;

// TODO: controller shouldnt consume this directly
await upload(path, filename);
await projectService.applyProjectFile(filename, options);

const oscSettings = await DataProvider.getOsc();
const httpSettings = await DataProvider.getHttp();

oscIntegration.init(oscSettings);
httpIntegration.init(httpSettings);
await handleUploaded(path, filename);
await projectService.loadProjectFile(filename);

res.status(201).send({
message: `Loaded project ${filename}`,
});
} catch (error) {
const message = getErrorMessage(error);
if (message.startsWith('Project file')) {
return res.status(403).send({ message });
}
res.status(400).send({ message });
}
}
Expand All @@ -143,23 +122,16 @@ export async function listProjects(_req: Request, res: Response<ProjectFileListR
export async function loadProject(req: Request, res: Response<MessageResponse | ErrorResponse>) {
try {
const name = req.body.filename;
if (!doesProjectExist(name)) {
return res.status(404).send({ message: 'File not found' });
}

await projectService.applyProjectFile(name);

const oscSettings = await DataProvider.getOsc();
const httpSettings = await DataProvider.getHttp();

oscIntegration.init(oscSettings);
httpIntegration.init(httpSettings);
await projectService.loadProjectFile(name);

res.status(201).send({
message: `Loaded project ${name}`,
});
} catch (error) {
const message = getErrorMessage(error);
if (message.startsWith('Project file')) {
return res.status(403).send({ message });
}
res.status(500).send({ message });
}
}
Expand Down Expand Up @@ -208,23 +180,20 @@ export async function duplicateProjectFile(req: Request, res: Response<MessageRe
*/
export async function renameProjectFile(req: Request, res: Response<MessageResponse | ErrorResponse>) {
try {
const { filename: newFilename } = req.body;
const { newFilename } = req.body;
const { filename } = req.params;

const errors = validateProjectFiles({ filename, newFilename });

if (errors.length) {
return res.status(409).send({ message: errors.join(', ') });
}

// Rename the file
await projectService.renameProjectFile(filename, newFilename);

res.status(201).send({
message: `Renamed project ${filename} to ${newFilename}`,
});
} catch (error) {
const message = getErrorMessage(error);
if (message.startsWith('Project file')) {
return res.status(403).send({ message });
}

res.status(500).send({ message });
}
}
Expand Down Expand Up @@ -260,7 +229,12 @@ export async function deleteProjectFile(req: Request, res: Response<MessageRespo
}
}

export async function getInfo(_req: Request, res: Response<GetInfo>) {
const info = await projectService.getInfo();
res.status(200).send(info);
export async function getInfo(_req: Request, res: Response<GetInfo | ErrorResponse>) {
try {
const info = await projectService.getInfo();
res.status(200).send(info);
} catch (error) {
const message = getErrorMessage(error);
res.status(500).send({ message });
}
}
2 changes: 1 addition & 1 deletion apps/server/src/api-data/db/db.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ router.get('/all', listProjects);

router.post('/load', validateFilenameBody, loadProject);
router.post('/:filename/duplicate', validateFilenameParam, validateNewFilenameBody, duplicateProjectFile);
router.put('/:filename/rename', validateFilenameParam, validateFilenameBody, renameProjectFile);
router.put('/:filename/rename', validateFilenameParam, validateNewFilenameBody, renameProjectFile);
router.delete('/:filename', validateFilenameParam, deleteProjectFile);

router.get('/info', getInfo);
11 changes: 10 additions & 1 deletion apps/server/src/api-data/db/db.validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,22 @@ export const validateNewProject = [
* @description Validates request for pathing data in the project.
*/
export const validatePatchProject = [
// Custom validator to ensure the body is not empty
(req: Request, res: Response, next: NextFunction) => {
if (Object.keys(req.body).length === 0) {
return res.status(422).json({ errors: [{ msg: 'Request body cannot be empty' }] });
}
next();
},

body('rundown').isArray().optional({ nullable: false }),
body('project').isObject().optional({ nullable: false }),
body('settings').isObject().optional({ nullable: false }),
body('viewSettings').isObject().optional({ nullable: false }),
body('aliases').isArray().optional({ nullable: false }),
body('urlPresets').isArray().optional({ nullable: false }),
body('customFields').isObject().optional({ nullable: false }),
body('osc').isObject().optional({ nullable: false }),
body('http').isObject().optional({ nullable: false }),

(req: Request, res: Response, next: NextFunction) => {
const errors = validationResult(req);
Expand Down
10 changes: 5 additions & 5 deletions apps/server/src/api-data/http/http.controller.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { ErrorResponse, HttpSettings } from 'ontime-types';
import { getErrorMessage } from 'ontime-utils';

import { Request, Response } from 'express';
import type { Request, Response } from 'express';

import { DataProvider } from '../../classes/data-provider/DataProvider.js';
import { failEmptyObjects } from '../../utils/routerUtils.js';
import { httpIntegration } from '../../services/integration-service/HttpIntegration.js';
import { getErrorMessage } from 'ontime-utils';
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';

export async function getHTTP(_req: Request, res: Response<HttpSettings>) {
const http = DataProvider.getHttp();
const http = getDataProvider().getHttp();
res.status(200).send(http);
}

Expand All @@ -22,7 +22,7 @@ export async function postHTTP(req: Request, res: Response<HttpSettings | ErrorR

httpIntegration.init(httpSettings);
// we persist the data after init to avoid persisting invalid data
const result = await DataProvider.setHttp(httpSettings);
const result = await getDataProvider().setHttp(httpSettings);
res.send(result).status(200);
} catch (error) {
const message = getErrorMessage(error);
Expand Down
10 changes: 5 additions & 5 deletions apps/server/src/api-data/osc/osc.controller.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { ErrorResponse, OSCSettings } from 'ontime-types';
import { getErrorMessage } from 'ontime-utils';

import { Request, Response } from 'express';
import type { Request, Response } from 'express';

import { DataProvider } from '../../classes/data-provider/DataProvider.js';
import { failEmptyObjects } from '../../utils/routerUtils.js';
import { oscIntegration } from '../../services/integration-service/OscIntegration.js';
import { getErrorMessage } from 'ontime-utils';
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';

export async function getOSC(_req: Request, res: Response<OSCSettings>) {
const osc = DataProvider.getOsc();
const osc = getDataProvider().getOsc();
res.status(200).send(osc);
}

Expand All @@ -22,7 +22,7 @@ export async function postOSC(req: Request, res: Response<OSCSettings | ErrorRes

oscIntegration.init(oscSettings);
// we persist the data after init to avoid persisting invalid data
const result = await DataProvider.setOsc(oscSettings);
const result = await getDataProvider().setOsc(oscSettings);

res.send(result).status(200);
} catch (error) {
Expand Down
9 changes: 5 additions & 4 deletions apps/server/src/api-data/project/project.controller.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { ErrorResponse, ProjectData } from 'ontime-types';
import { getErrorMessage } from 'ontime-utils';

import type { Request, Response } from 'express';
import { DataProvider } from '../../classes/data-provider/DataProvider.js';

import { removeUndefined } from '../../utils/parserUtils.js';
import { failEmptyObjects } from '../../utils/routerUtils.js';
import { getErrorMessage } from 'ontime-utils';
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';

export async function getProjectData(_req: Request, res: Response<ProjectData>) {
res.json(DataProvider.getProjectData());
res.json(getDataProvider().getProjectData());
}

export async function postProjectData(req: Request, res: Response<ProjectData | ErrorResponse>) {
Expand All @@ -25,7 +26,7 @@ export async function postProjectData(req: Request, res: Response<ProjectData |
backstageInfo: req.body?.backstageInfo,
endMessage: req.body?.endMessage,
});
const newData = await DataProvider.setProjectData(newEvent);
const newData = await getDataProvider().setProjectData(newEvent);
res.status(200).send(newData);
} catch (error) {
const message = getErrorMessage(error);
Expand Down
10 changes: 5 additions & 5 deletions apps/server/src/api-data/settings/settings.controller.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { ErrorResponse, Settings } from 'ontime-types';
import { getErrorMessage, obfuscate } from 'ontime-utils';

import { Request, Response } from 'express';
import type { Request, Response } from 'express';

import { DataProvider } from '../../classes/data-provider/DataProvider.js';
import { failEmptyObjects } from '../../utils/routerUtils.js';
import { isDocker } from '../../setup/index.js';
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';

import { extractPin } from './settings.utils.js';

export async function getSettings(_req: Request, res: Response<Settings>) {
const settings = DataProvider.getSettings();
const settings = getDataProvider().getSettings();
const obfuscatedSettings = { ...settings };
if (settings.editorKey) {
obfuscatedSettings.editorKey = obfuscate(settings.editorKey);
Expand All @@ -28,7 +28,7 @@ export async function postSettings(req: Request, res: Response<Settings | ErrorR
return;
}
try {
const settings = DataProvider.getSettings();
const settings = getDataProvider().getSettings();
const editorKey = extractPin(req.body?.editorKey, settings.editorKey);
const operatorKey = extractPin(req.body?.operatorKey, settings.operatorKey);
const serverPort = Number(req.body?.serverPort);
Expand Down Expand Up @@ -58,7 +58,7 @@ export async function postSettings(req: Request, res: Response<Settings | ErrorR
language,
serverPort,
};
await DataProvider.setSettings(newData);
await getDataProvider().setSettings(newData);
res.status(200).send(newData);
} catch (error) {
const message = getErrorMessage(error);
Expand Down
10 changes: 5 additions & 5 deletions apps/server/src/api-data/url-presets/urlPresets.controller.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { ErrorResponse, URLPreset } from 'ontime-types';
import { getErrorMessage } from 'ontime-utils';

import { Request, Response } from 'express';
import type { Request, Response } from 'express';

import { DataProvider } from '../../classes/data-provider/DataProvider.js';
import { failIsNotArray } from '../../utils/routerUtils.js';
import { getErrorMessage } from 'ontime-utils';
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';

export async function getUrlPresets(_req: Request, res: Response<URLPreset[]>) {
const presets = DataProvider.getUrlPresets();
const presets = getDataProvider().getUrlPresets();
res.status(200).send(presets as URLPreset[]);
}

Expand All @@ -21,7 +21,7 @@ export async function postUrlPresets(req: Request, res: Response<URLPreset[] | E
alias: preset.alias,
pathAndParams: preset.pathAndParams,
}));
await DataProvider.setUrlPresets(newPresets);
await getDataProvider().setUrlPresets(newPresets);
res.status(200).send(newPresets);
} catch (error) {
const message = getErrorMessage(error);
Expand Down
19 changes: 7 additions & 12 deletions apps/server/src/api-data/view-settings/viewSettings.controller.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
import type { ErrorResponse, ViewSettings } from 'ontime-types';
import { getErrorMessage } from 'ontime-utils';

import { Request, Response } from 'express';
import type { Request, Response } from 'express';

import { DataProvider } from '../../classes/data-provider/DataProvider.js';
import { failEmptyObjects } from '../../utils/routerUtils.js';
import { getErrorMessage } from 'ontime-utils';
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';

export async function getViewSettings(_req: Request, res: Response<ViewSettings>) {
const views = DataProvider.getViewSettings();
const views = getDataProvider().getViewSettings();
res.status(200).send(views);
}

export async function postViewSettings(req: Request, res: Response<ViewSettings | ErrorResponse>) {
if (failEmptyObjects(req.body, res)) {
return;
}

try {
const newData = {
dangerColor: req.body.dangerColor,
endMessage: req.body?.endMessage ?? '',
endMessage: req.body.endMessage,
freezeEnd: req.body.freezeEnd,
normalColor: req.body.normalColor,
overrideStyles: req.body.overrideStyles,
warningColor: req.body.warningColor,
};
await DataProvider.setViewSettings(newData);
} as ViewSettings;
await getDataProvider().setViewSettings(newData);
res.status(200).send(newData);
} catch (error) {
const message = getErrorMessage(error);
Expand Down
Loading