mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-08 08:53:51 +00:00
Upgrade expressjs (#1633)
* upgrade expressjs * migration * reenable test * extend timeout on download test * fixup! migration * move empty body test from controller to validator * enusre not empty * extract validation function * fixup! reenable test * remove thin controllers * disable e2e test of project file download
This commit is contained in:
committed by
Carlos Valente
parent
90870ecfb6
commit
6f3ab274bd
@@ -1,41 +0,0 @@
|
||||
import { defaultCss } from '../../user/styles/bundledCss.js';
|
||||
import type { Request, Response } from 'express';
|
||||
import { readCssFile, writeCssFile } from './assets.service.js';
|
||||
|
||||
/**
|
||||
* Exposes the contents of the cssOverride.css file
|
||||
*/
|
||||
export async function getCssOverride(_req: Request, res: Response) {
|
||||
try {
|
||||
const data = await readCssFile();
|
||||
res.status(200).send(data);
|
||||
} catch (error) {
|
||||
res.status(500).send({ message: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows modifying the cssOverride.css file
|
||||
*/
|
||||
export async function postCssOverride(req: Request, res: Response) {
|
||||
const { css } = req.body;
|
||||
|
||||
try {
|
||||
await writeCssFile(css);
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
res.status(500).send({ message: error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the default cssOverride.css file
|
||||
*/
|
||||
export async function restoreCss(_req: Request, res: Response) {
|
||||
try {
|
||||
await writeCssFile(defaultCss);
|
||||
res.status(200).send(defaultCss);
|
||||
} catch (error) {
|
||||
res.status(500).send({ message: error });
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,40 @@
|
||||
import express from 'express';
|
||||
|
||||
import { getCssOverride, postCssOverride, restoreCss } from './assets.controller.js';
|
||||
import type { Request, Response } from 'express';
|
||||
import type { ErrorResponse } from 'ontime-types';
|
||||
import { validatePostCss } from './assets.validation.js';
|
||||
import { readCssFile, writeCssFile } from './assets.service.js';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
import { defaultCss } from '../../user/styles/bundledCss.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
router.get('/css', getCssOverride);
|
||||
router.post('/css', validatePostCss, postCssOverride);
|
||||
router.post('/css/restore', restoreCss);
|
||||
router.get('/css', async (_req: Request, res: Response<string | ErrorResponse>) => {
|
||||
try {
|
||||
const data = await readCssFile();
|
||||
res.status(200).send(data);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/css', validatePostCss, async (req: Request, res: Response<never | ErrorResponse>) => {
|
||||
const { css } = req.body;
|
||||
try {
|
||||
await writeCssFile(css);
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/css/restore', async (_req: Request, res: Response<string | ErrorResponse>) => {
|
||||
try {
|
||||
await writeCssFile(defaultCss);
|
||||
res.status(200).send(defaultCss);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { body, validationResult } from 'express-validator';
|
||||
import { body } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const validatePostCss = [
|
||||
body('css').isString().trim(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
];
|
||||
export const validatePostCss = [body('css').isString().trim(), requestValidationFunction];
|
||||
|
||||
@@ -12,7 +12,7 @@ import * as automationService from './automation.service.js';
|
||||
import { parseOutput } from './automation.validation.js';
|
||||
|
||||
export function getAutomationSettings(_req: Request, res: Response<AutomationSettings>) {
|
||||
res.json(automationDao.getAutomationSettings());
|
||||
res.status(200).json(automationDao.getAutomationSettings());
|
||||
}
|
||||
|
||||
export async function postAutomationSettings(req: Request, res: Response<AutomationSettings | ErrorResponse>) {
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
testOutput,
|
||||
} from './automation.controller.js';
|
||||
import {
|
||||
paramContainsId,
|
||||
validateAutomationSettings,
|
||||
validateAutomation,
|
||||
validateAutomationPatch,
|
||||
@@ -20,6 +19,7 @@ import {
|
||||
validateTrigger,
|
||||
validateTriggerPatch,
|
||||
} from './automation.validation.js';
|
||||
import { paramsWithId } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
@@ -28,10 +28,10 @@ router.post('/', validateAutomationSettings, postAutomationSettings);
|
||||
|
||||
router.post('/trigger', validateTrigger, postTrigger);
|
||||
router.put('/trigger/:id', validateTriggerPatch, putTrigger);
|
||||
router.delete('/trigger/:id', paramContainsId, deleteTrigger);
|
||||
router.delete('/trigger/:id', paramsWithId, deleteTrigger);
|
||||
|
||||
router.post('/automation', validateAutomation, postAutomation);
|
||||
router.put('/automation/:id', validateAutomationPatch, editAutomation);
|
||||
router.delete('/automation/:id', paramContainsId, deleteAutomation);
|
||||
router.delete('/automation/:id', paramsWithId, deleteAutomation);
|
||||
|
||||
router.post('/test', validateTestPayload, testOutput);
|
||||
|
||||
@@ -10,22 +10,12 @@ import {
|
||||
} from 'ontime-types';
|
||||
import { parseUserTime } from 'ontime-utils';
|
||||
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import { body, oneOf, param, validationResult } from 'express-validator';
|
||||
import { body, oneOf, param } from 'express-validator';
|
||||
|
||||
import * as assert from '../../utils/assert.js';
|
||||
|
||||
import { isFilterOperator, isFilterRule, isOntimeActionAction } from './automation.utils.js';
|
||||
|
||||
export const paramContainsId = [
|
||||
param('id').isString().notEmpty(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
];
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const validateAutomationSettings = [
|
||||
body('enabledAutomations').isBoolean(),
|
||||
@@ -37,57 +27,33 @@ export const validateAutomationSettings = [
|
||||
body('triggers.*.automationId').optional().isString().trim(),
|
||||
body('automations').optional().custom(parseAutomation),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
export const validateTrigger = [
|
||||
body('title').isString().trim(),
|
||||
body('title').isString().trim().notEmpty(),
|
||||
body('trigger').isIn(timerLifecycleValues),
|
||||
body('automationId').isString().trim(),
|
||||
body('automationId').isString().trim().notEmpty(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
export const validateTriggerPatch = [
|
||||
param('id').isString().notEmpty(),
|
||||
body('title').optional().isString().trim(),
|
||||
body('title').optional().isString().trim().notEmpty(),
|
||||
body('trigger').optional().isIn(timerLifecycleValues),
|
||||
body('automationId').optional().isString().trim(),
|
||||
body('automationId').optional().isString().trim().notEmpty(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
export const validateAutomation = [
|
||||
body().custom(parseAutomation),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
];
|
||||
export const validateAutomation = [body().custom(parseAutomation), requestValidationFunction];
|
||||
|
||||
export const validateAutomationPatch = [
|
||||
param('id').isString().notEmpty(),
|
||||
body().custom(parseAutomation),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -162,11 +128,7 @@ export const validateTestPayload = [
|
||||
body('visible').if(body('type').equals('ontime')).optional().isString().trim(),
|
||||
body('secondarySource').if(body('type').equals('ontime')).optional().isString().trim(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@ export const router = express.Router();
|
||||
|
||||
router.get('/', async (_req: Request, res: Response<CustomFields>) => {
|
||||
const customFields = getProjectCustomFields();
|
||||
res.json(customFields);
|
||||
res.status(200).json(customFields);
|
||||
});
|
||||
|
||||
router.post('/', validateCustomField, async (req: Request, res: Response<CustomFields | ErrorResponse>) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { isAlphanumericWithSpace } from 'ontime-utils';
|
||||
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import { body, param, validationResult } from 'express-validator';
|
||||
import { body, param } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const validateCustomField = [
|
||||
body('label')
|
||||
@@ -14,11 +14,7 @@ export const validateCustomField = [
|
||||
body('type').isIn(['string', 'image']),
|
||||
body('colour').isString().trim(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
export const validateEditCustomField = [
|
||||
@@ -33,19 +29,7 @@ export const validateEditCustomField = [
|
||||
body('type').isIn(['string', 'image']),
|
||||
body('colour').isString().trim(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
export const validateDeleteCustomField = [
|
||||
param('key').isString().notEmpty(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
];
|
||||
export const validateDeleteCustomField = [param('key').isString().notEmpty(), requestValidationFunction];
|
||||
|
||||
@@ -106,7 +106,8 @@ export async function projectDownload(req: Request, res: Response) {
|
||||
const { filename } = req.body;
|
||||
const pathToFile = doesProjectExist(filename);
|
||||
if (!pathToFile) {
|
||||
return res.status(404).send({ message: `Project ${filename} not found.` });
|
||||
res.status(404).send({ message: `Project ${filename} not found.` });
|
||||
return;
|
||||
}
|
||||
|
||||
res.download(pathToFile, filename, (error) => {
|
||||
@@ -138,7 +139,8 @@ export async function postProjectFile(req: Request, res: Response<MessageRespons
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
if (message.startsWith('Project file')) {
|
||||
return res.status(403).send({ message });
|
||||
res.status(403).send({ message });
|
||||
return;
|
||||
}
|
||||
res.status(400).send({ message });
|
||||
}
|
||||
@@ -195,7 +197,8 @@ export async function loadProject(req: Request, res: Response<MessageResponse |
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
if (message.startsWith('Project file')) {
|
||||
return res.status(403).send({ message });
|
||||
res.status(403).send({ message });
|
||||
return;
|
||||
}
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
@@ -214,7 +217,8 @@ export async function loadDemo(_req: Request, res: Response<MessageResponse | Er
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
if (message.startsWith('Project file')) {
|
||||
return res.status(403).send({ message });
|
||||
res.status(403).send({ message });
|
||||
return;
|
||||
}
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
@@ -245,7 +249,8 @@ export async function duplicateProjectFile(req: Request, res: Response<MessageRe
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
if (message.startsWith('Project file')) {
|
||||
return res.status(403).send({ message });
|
||||
res.status(403).send({ message });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).send({ message });
|
||||
@@ -275,7 +280,8 @@ export async function renameProjectFile(req: Request, res: Response<MessageRespo
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
if (message.startsWith('Project file')) {
|
||||
return res.status(403).send({ message });
|
||||
res.status(403).send({ message });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).send({ message });
|
||||
@@ -303,10 +309,12 @@ export async function deleteProjectFile(req: Request, res: Response<MessageRespo
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
if (message === 'Cannot delete currently loaded project') {
|
||||
return res.status(403).send({ message });
|
||||
res.status(403).send({ message });
|
||||
return;
|
||||
}
|
||||
if (message === 'Project file not found') {
|
||||
return res.status(404).send({ message });
|
||||
res.status(404).send({ message });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).send({ message });
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import { body, param, validationResult } from 'express-validator';
|
||||
import { body, param } from 'express-validator';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import { ensureJsonExtension } from '../../utils/fileManagement.js';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
/**
|
||||
* @description Validates request for a new project.
|
||||
*/
|
||||
export const validateNewProject = [
|
||||
body().notEmpty().withMessage('No object found in request'),
|
||||
body('filename').optional().isString().trim(),
|
||||
body('title').optional().isString().trim(),
|
||||
body('description').optional().isString().trim(),
|
||||
@@ -18,11 +19,7 @@ export const validateNewProject = [
|
||||
body('endMessage').optional().isString().trim(),
|
||||
body('custom').optional().isArray(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -40,25 +37,14 @@ export const validateQuickProject = [
|
||||
body('viewSettings.freezeEnd').optional().isBoolean(),
|
||||
body('viewSettings.endMessage').optional().isString().trim(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
/**
|
||||
* @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().notEmpty().withMessage('No object found in request'),
|
||||
body('rundowns').isObject().optional({ nullable: false }),
|
||||
body('project').isObject().optional({ nullable: false }),
|
||||
body('settings').isObject().optional({ nullable: false }),
|
||||
@@ -68,11 +54,7 @@ export const validatePatchProject = [
|
||||
body('osc').isObject().optional({ nullable: false }),
|
||||
body('http').isObject().optional({ nullable: false }),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -88,14 +70,7 @@ export const validateNewFilenameBody = [
|
||||
.withMessage('Filename was empty or contained only invalid characters')
|
||||
.customSanitizer((input: string) => ensureJsonExtension(input)),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(422).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -111,14 +86,7 @@ export const validateFilenameBody = [
|
||||
.withMessage('Filename was empty or contained only invalid characters')
|
||||
.customSanitizer((input: string) => ensureJsonExtension(input)),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(422).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -134,12 +102,5 @@ export const validateFilenameParam = [
|
||||
.withMessage('Filename was empty or contained only invalid characters')
|
||||
.customSanitizer((input: string) => ensureJsonExtension(input)),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(422).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* This module encapsulates logic related to
|
||||
* Google Sheets
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import { generateRundownPreview, listWorksheets, saveExcelFile } from './excel.service.js';
|
||||
import { CustomFields, Rundown } from 'ontime-types';
|
||||
|
||||
export async function postExcel(req: Request, res: Response) {
|
||||
try {
|
||||
// file has been validated by middleware
|
||||
const filePath = (req.file as Express.Multer.File).path;
|
||||
await saveExcelFile(filePath);
|
||||
res.status(200).send();
|
||||
} catch (error) {
|
||||
res.status(500).send({ message: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
export async function getWorksheets(req: Request, res: Response) {
|
||||
try {
|
||||
const names = listWorksheets();
|
||||
res.status(200).send(names);
|
||||
} catch (error) {
|
||||
res.status(500).send({ message: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parses an Excel spreadsheet
|
||||
* @returns parsed result
|
||||
*/
|
||||
export async function previewExcel(
|
||||
req: Request,
|
||||
res: Response<{ rundown: Rundown; customFields: CustomFields } | { message: string }>,
|
||||
) {
|
||||
try {
|
||||
const { options } = req.body;
|
||||
const data = generateRundownPreview(options);
|
||||
res.status(200).send(data);
|
||||
} catch (error) {
|
||||
res.status(500).send({ message: String(error) });
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,42 @@
|
||||
/**
|
||||
* This is a feature specific router for integration with Excel
|
||||
*/
|
||||
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
import { uploadExcel } from './excel.middleware.js';
|
||||
import { getWorksheets, postExcel, previewExcel } from './excel.controller.js';
|
||||
import { validateFileExists, validateImportMapOptions } from './excel.validation.js';
|
||||
import { CustomFields, ErrorResponse, Rundown } from 'ontime-types';
|
||||
import { generateRundownPreview, listWorksheets, saveExcelFile } from './excel.service.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
router.post('/upload', uploadExcel, validateFileExists, postExcel);
|
||||
router.get('/worksheets', getWorksheets);
|
||||
router.post('/preview', validateImportMapOptions, previewExcel);
|
||||
router.post('/upload', uploadExcel, validateFileExists, async (req: Request, res: Response<never | ErrorResponse>) => {
|
||||
try {
|
||||
// file has been validated by middleware
|
||||
const filePath = (req.file as Express.Multer.File).path;
|
||||
await saveExcelFile(filePath);
|
||||
res.status(201).send();
|
||||
} catch (error) {
|
||||
res.status(500).send({ message: String(error) });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/worksheets', (_req: Request, res: Response<string[] | ErrorResponse>) => {
|
||||
try {
|
||||
const names = listWorksheets();
|
||||
res.status(200).send(names);
|
||||
} catch (error) {
|
||||
res.status(500).send({ message: String(error) });
|
||||
}
|
||||
});
|
||||
|
||||
router.post(
|
||||
'/preview',
|
||||
validateImportMapOptions,
|
||||
(req: Request, res: Response<{ rundown: Rundown; customFields: CustomFields } | ErrorResponse>) => {
|
||||
try {
|
||||
const { options } = req.body;
|
||||
const data = generateRundownPreview(options);
|
||||
res.status(200).send(data);
|
||||
} catch (error) {
|
||||
res.status(500).send({ message: String(error) });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import { isImportMap } from 'ontime-utils';
|
||||
|
||||
import { body, validationResult } from 'express-validator';
|
||||
import type { NextFunction, Request, Response } from 'express';
|
||||
import { body } from 'express-validator';
|
||||
import {
|
||||
requestValidationFunction,
|
||||
requestValidationFunctionWithFile,
|
||||
} from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const validateFileExists = [
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
if (!req.file) {
|
||||
return res.status(422).json({ errors: 'File not found' });
|
||||
}
|
||||
next();
|
||||
},
|
||||
];
|
||||
export const validateFileExists = [requestValidationFunctionWithFile];
|
||||
|
||||
export const validateImportMapOptions = [
|
||||
body('options')
|
||||
@@ -19,9 +15,5 @@ export const validateImportMapOptions = [
|
||||
return isImportMap(content);
|
||||
}),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
@@ -31,6 +31,6 @@ appRouter.use('/report', reportRouter);
|
||||
appRouter.use('/assets', assetsRouter);
|
||||
|
||||
//we don't want to redirect to react index when using api routes
|
||||
appRouter.all('/*', (_req, res) => {
|
||||
res.status(404).send();
|
||||
appRouter.all('/*splat', (_req, res) => {
|
||||
res.status(404).send('data path not found');
|
||||
});
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { ErrorResponse, ProjectData } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
import { removeUndefined } from '../../utils/parserUtils.js';
|
||||
import { failEmptyObjects } from '../../utils/routerUtils.js';
|
||||
import { editCurrentProjectData } from '../../services/project-service/ProjectService.js';
|
||||
import * as projectDao from './projectData.dao.js';
|
||||
|
||||
export function getProjectData(_req: Request, res: Response<ProjectData>) {
|
||||
res.json(projectDao.getProjectData());
|
||||
}
|
||||
|
||||
export async function postProjectData(req: Request, res: Response<ProjectData | ErrorResponse>) {
|
||||
if (failEmptyObjects(req.body, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const newData: Partial<ProjectData> = removeUndefined({
|
||||
title: req.body?.title,
|
||||
description: req.body?.description,
|
||||
publicUrl: req.body?.publicUrl,
|
||||
publicInfo: req.body?.publicInfo,
|
||||
backstageUrl: req.body?.backstageUrl,
|
||||
backstageInfo: req.body?.backstageInfo,
|
||||
endMessage: req.body?.endMessage,
|
||||
projectLogo: req.body?.projectLogo,
|
||||
custom: req.body?.custom,
|
||||
});
|
||||
|
||||
const updatedData = await editCurrentProjectData(newData);
|
||||
|
||||
res.status(200).send(updatedData);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(400).send({ message });
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,42 @@
|
||||
import express from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
import type { ErrorResponse, ProjectData } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import { getProjectData, postProjectData } from './projectData.controller.js';
|
||||
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 { editCurrentProjectData } from '../../services/project-service/ProjectService.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
router.get('/', getProjectData);
|
||||
router.post('/', projectSanitiser, postProjectData);
|
||||
router.get('/', (_req: Request, res: Response<ProjectData>) => {
|
||||
res.status(200).json(projectDao.getProjectData());
|
||||
});
|
||||
|
||||
router.post('/', projectSanitiser, async (req: Request, res: Response<ProjectData | ErrorResponse>) => {
|
||||
try {
|
||||
const newData: Partial<ProjectData> = removeUndefined({
|
||||
title: req.body?.title,
|
||||
description: req.body?.description,
|
||||
publicUrl: req.body?.publicUrl,
|
||||
publicInfo: req.body?.publicInfo,
|
||||
backstageUrl: req.body?.backstageUrl,
|
||||
backstageInfo: req.body?.backstageInfo,
|
||||
endMessage: req.body?.endMessage,
|
||||
projectLogo: req.body?.projectLogo,
|
||||
custom: req.body?.custom,
|
||||
});
|
||||
|
||||
const updatedData = await editCurrentProjectData(newData);
|
||||
|
||||
res.status(200).send(updatedData);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(400).send({ message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/upload', uploadImageFile, postProjectLogo);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { body, validationResult } from 'express-validator';
|
||||
import { body } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const projectSanitiser = [
|
||||
body().notEmpty().withMessage('No object found in request'),
|
||||
body('title').optional().isString().trim(),
|
||||
body('description').optional().isString().trim(),
|
||||
body('publicUrl').optional().isString().trim(),
|
||||
@@ -9,14 +10,10 @@ export const projectSanitiser = [
|
||||
body('backstageUrl').optional().isString().trim(),
|
||||
body('backstageInfo').optional().isString().trim(),
|
||||
body('endMessage').optional().isString().trim(),
|
||||
body('projectLogo').optional({ nullable: true }).isString().trim(),
|
||||
body('projectLogo').optional({ nullable: true }).isString().trim().isBase64(),
|
||||
body('custom').optional().isArray(),
|
||||
body('custom.*.title').optional().isString().trim().notEmpty(),
|
||||
body('custom.*.value').optional().isString().trim().notEmpty(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import type { Request, Response } from 'express';
|
||||
import type { OntimeReport } from 'ontime-types';
|
||||
import * as report from './report.service.js';
|
||||
|
||||
export function getAll(_req: Request, res: Response<OntimeReport>) {
|
||||
res.json(report.generate());
|
||||
}
|
||||
|
||||
export function deleteAll(_req: Request, res: Response<OntimeReport>) {
|
||||
report.clear();
|
||||
res.status(200).send();
|
||||
}
|
||||
|
||||
export function deleteWithId(req: Request, res: Response<OntimeReport>) {
|
||||
const { eventId } = req.params;
|
||||
report.clear(eventId);
|
||||
res.status(200).send();
|
||||
}
|
||||
@@ -1,10 +1,21 @@
|
||||
import express from 'express';
|
||||
import { getAll, deleteWithId, deleteAll } from './report.controller.js';
|
||||
import { paramsMustHaveEntryId } from '../rundown/rundown.validation.js';
|
||||
import type { Request, Response } from 'express';
|
||||
import { paramsWithId } from '../validation-utils/validationFunction.js';
|
||||
import * as report from './report.service.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
router.get('/', getAll);
|
||||
router.get('/', (_req: Request, res: Response) => {
|
||||
res.status(200).json(report.generate());
|
||||
});
|
||||
|
||||
router.delete('/all', deleteAll);
|
||||
router.delete('/:eventId', paramsMustHaveEntryId, deleteWithId);
|
||||
router.delete('/all', (_req: Request, res: Response) => {
|
||||
report.clear();
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
router.delete('/:id', paramsWithId, (req: Request, res: Response) => {
|
||||
const { id } = req.params;
|
||||
report.clear(id);
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
ungroupEntries,
|
||||
} from './rundown.service.js';
|
||||
import {
|
||||
paramsMustHaveEntryId,
|
||||
rundownArrayOfIds,
|
||||
rundownBatchPutValidator,
|
||||
rundownPostValidator,
|
||||
@@ -27,6 +26,7 @@ import {
|
||||
rundownReorderValidator,
|
||||
rundownSwapValidator,
|
||||
} from './rundown.validation.js';
|
||||
import { paramsWithId } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
@@ -100,11 +100,11 @@ router.patch('/swap', rundownSwapValidator, async (req: Request, res: Response<R
|
||||
});
|
||||
|
||||
router.patch(
|
||||
'/applydelay/:entryId',
|
||||
paramsMustHaveEntryId,
|
||||
'/applydelay/:id',
|
||||
paramsWithId,
|
||||
async (req: Request, res: Response<Rundown | ErrorResponse>) => {
|
||||
try {
|
||||
const newRundown = await applyDelay(req.params.entryId);
|
||||
const newRundown = await applyDelay(req.params.id);
|
||||
res.status(200).send(newRundown);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
@@ -113,9 +113,9 @@ router.patch(
|
||||
},
|
||||
);
|
||||
|
||||
router.post('/clone/:entryId', paramsMustHaveEntryId, async (req: Request, res: Response<Rundown | ErrorResponse>) => {
|
||||
router.post('/clone/:id', paramsWithId, async (req: Request, res: Response<Rundown | ErrorResponse>) => {
|
||||
try {
|
||||
const newRundown = await cloneEntry(req.params.entryId);
|
||||
const newRundown = await cloneEntry(req.params.id);
|
||||
res.status(200).send(newRundown);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
@@ -134,11 +134,11 @@ router.post('/group', rundownArrayOfIds, async (req: Request, res: Response<Rund
|
||||
});
|
||||
|
||||
router.post(
|
||||
'/ungroup/:entryId',
|
||||
paramsMustHaveEntryId,
|
||||
'/ungroup/:id',
|
||||
paramsWithId,
|
||||
async (req: Request, res: Response<Rundown | ErrorResponse>) => {
|
||||
try {
|
||||
const newRundown = await ungroupEntries(req.params.entryId);
|
||||
const newRundown = await ungroupEntries(req.params.id);
|
||||
res.status(200).send(newRundown);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
|
||||
@@ -1,38 +1,22 @@
|
||||
import { body, param, validationResult } from 'express-validator';
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import { body, param } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const rundownPostValidator = [
|
||||
body('type').isString().isIn(['event', 'delay', 'block']),
|
||||
body('after').optional().isString(),
|
||||
body('before').optional().isString(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
export const rundownPutValidator = [
|
||||
body('id').isString().notEmpty(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
];
|
||||
export const rundownPutValidator = [body('id').isString().notEmpty(), requestValidationFunction];
|
||||
|
||||
export const rundownBatchPutValidator = [
|
||||
body('data').isObject(),
|
||||
body('ids').isArray().notEmpty(),
|
||||
body('ids.*').isString(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
export const rundownReorderValidator = [
|
||||
@@ -40,41 +24,21 @@ export const rundownReorderValidator = [
|
||||
body('destinationId').isString().notEmpty(),
|
||||
body('order').isIn(['before', 'after', 'insert']),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
export const rundownSwapValidator = [
|
||||
body('from').isString().notEmpty(),
|
||||
body('to').isString().notEmpty(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
export const paramsMustHaveEntryId = [
|
||||
param('entryId').isString().notEmpty(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
];
|
||||
export const paramsMustHaveEntryId = [param('entryId').isString().notEmpty(), requestValidationFunction];
|
||||
|
||||
export const rundownArrayOfIds = [
|
||||
body('ids').isArray().notEmpty(),
|
||||
body('ids.*').isString(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
import { ErrorResponse, GetInfo, GetUrl, SessionStats } from 'ontime-types';
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
import * as sessionService from './session.service.js';
|
||||
|
||||
export async function getSessionStats(_req: Request, res: Response<SessionStats | ErrorResponse>) {
|
||||
try {
|
||||
const stats = await sessionService.getSessionStats();
|
||||
res.status(200).send(stats);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
}
|
||||
|
||||
export async function getInfo(_req: Request, res: Response<GetInfo | ErrorResponse>) {
|
||||
try {
|
||||
const info = await sessionService.getInfo();
|
||||
res.status(200).send(info);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateUrl(req: Request, res: Response<GetUrl | ErrorResponse>) {
|
||||
try {
|
||||
const url = sessionService.generateAuthenticatedUrl(
|
||||
req.body.baseUrl,
|
||||
req.body.path,
|
||||
req.body.lock,
|
||||
req.body.authenticate,
|
||||
);
|
||||
res.status(200).send({ url: url.toString() });
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,43 @@
|
||||
import express from 'express';
|
||||
|
||||
import { getInfo, getSessionStats, generateUrl } from './session.controller.js';
|
||||
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 * as sessionService from './session.service.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
router.get('/', getSessionStats);
|
||||
router.get('/info', getInfo);
|
||||
router.post('/url', validateGenerateUrl, generateUrl);
|
||||
router.get('/', async (_req: Request, res: Response<SessionStats | ErrorResponse>) => {
|
||||
try {
|
||||
const stats = await sessionService.getSessionStats();
|
||||
res.status(200).send(stats);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/info', async (_req: Request, res: Response<GetInfo | ErrorResponse>) => {
|
||||
try {
|
||||
const info = await sessionService.getInfo();
|
||||
res.status(200).send(info);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/url', validateGenerateUrl, (req: Request, res: Response<GetUrl | ErrorResponse>) => {
|
||||
try {
|
||||
const url = sessionService.generateAuthenticatedUrl(
|
||||
req.body.baseUrl,
|
||||
req.body.path,
|
||||
req.body.lock,
|
||||
req.body.authenticate,
|
||||
);
|
||||
res.status(200).send({ url: url.toString() });
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(500).send({ message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import { body, validationResult } from 'express-validator';
|
||||
|
||||
import { body } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const validateGenerateUrl = [
|
||||
body('baseUrl').isString().trim().notEmpty(),
|
||||
@@ -7,9 +8,5 @@ export const validateGenerateUrl = [
|
||||
body('lock').isBoolean(),
|
||||
body('authenticate').isBoolean(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
@@ -4,7 +4,6 @@ import { getErrorMessage, obfuscate } from 'ontime-utils';
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
import { isDocker } from '../../setup/environment.js';
|
||||
import { failEmptyObjects } from '../../utils/routerUtils.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import * as appState from '../../services/app-state-service/AppStateService.js';
|
||||
|
||||
@@ -25,9 +24,6 @@ export async function getSettings(_req: Request, res: Response<Settings>) {
|
||||
}
|
||||
|
||||
export async function postSettings(req: Request, res: Response<Settings | ErrorResponse>) {
|
||||
if (failEmptyObjects(req.body, res)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const settings = getDataProvider().getSettings();
|
||||
const editorKey = extractPin(req.body?.editorKey, settings.editorKey);
|
||||
@@ -35,13 +31,15 @@ export async function postSettings(req: Request, res: Response<Settings | ErrorR
|
||||
const serverPort = Number(req.body?.serverPort);
|
||||
//TODO: should this not be part of the validator?
|
||||
if (isNaN(serverPort)) {
|
||||
return res.status(400).send({ message: `Invalid value found for server port: ${req.body?.serverPort}` });
|
||||
res.status(400).send({ message: `Invalid value found for server port: ${req.body?.serverPort}` });
|
||||
return;
|
||||
}
|
||||
|
||||
const hasChangedPort = settings.serverPort !== serverPort;
|
||||
|
||||
if (isDocker && hasChangedPort) {
|
||||
return res.status(403).json({ message: 'Can`t change port when running inside docker' });
|
||||
res.status(403).json({ message: 'Can`t change port when running inside docker' });
|
||||
return;
|
||||
}
|
||||
|
||||
let timeFormat = settings.timeFormat;
|
||||
|
||||
@@ -1,31 +1,21 @@
|
||||
import { body, validationResult } from 'express-validator';
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import { body } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
/**
|
||||
* @description Validates object for POST /ontime/settings/welcomedialog
|
||||
*/
|
||||
export const validateWelcomeDialog = [
|
||||
body('show').isBoolean(),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
];
|
||||
export const validateWelcomeDialog = [body('show').isBoolean(), requestValidationFunction];
|
||||
|
||||
/**
|
||||
* @description Validates object for POST /ontime/settings
|
||||
*/
|
||||
export const validateSettings = [
|
||||
body().notEmpty().withMessage('No object found in request'),
|
||||
body('editorKey').isString().isLength({ min: 0, max: 4 }).optional({ nullable: true }),
|
||||
body('operatorKey').isString().isLength({ min: 0, max: 4 }).optional({ nullable: true }),
|
||||
body('timeFormat').isString().isIn(['12', '24']),
|
||||
body('language').isString(),
|
||||
body('serverPort').isPort().optional(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
@@ -2,6 +2,7 @@ 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 = [
|
||||
param('sheetId')
|
||||
@@ -14,27 +15,23 @@ export const validateRequestConnection = [
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
if (!errors.isEmpty()) {
|
||||
res.status(422).json({ errors: errors.array() });
|
||||
return;
|
||||
}
|
||||
// check that the file exists
|
||||
if (!req.file) {
|
||||
return res.status(422).json({ errors: 'File not found' });
|
||||
res.status(422).json({ errors: 'File not found' });
|
||||
return;
|
||||
}
|
||||
next();
|
||||
},
|
||||
];
|
||||
|
||||
export const validateSheetId = [
|
||||
param('sheetId').isString(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
];
|
||||
export const validateSheetId = [param('sheetId').isString().trim().notEmpty(), requestValidationFunction];
|
||||
|
||||
export const validateSheetOptions = [
|
||||
param('sheetId').isString(),
|
||||
param('sheetId').isString().trim().notEmpty(),
|
||||
body('options')
|
||||
.isObject()
|
||||
.custom((content) => {
|
||||
@@ -42,9 +39,5 @@ export const validateSheetOptions = [
|
||||
return isValid;
|
||||
}),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import type { ErrorResponse, URLPreset } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
import { failIsNotArray } from '../../utils/routerUtils.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
|
||||
export async function getUrlPresets(_req: Request, res: Response<URLPreset[]>) {
|
||||
const presets = getDataProvider().getUrlPresets();
|
||||
res.status(200).send(presets as URLPreset[]);
|
||||
}
|
||||
|
||||
export async function postUrlPresets(req: Request, res: Response<URLPreset[] | ErrorResponse>) {
|
||||
if (failIsNotArray(req.body, res)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const newPresets: URLPreset[] = req.body.map((preset: URLPreset) => ({
|
||||
enabled: preset.enabled,
|
||||
alias: preset.alias,
|
||||
pathAndParams: preset.pathAndParams,
|
||||
}));
|
||||
await getDataProvider().setUrlPresets(newPresets);
|
||||
res.status(200).send(newPresets);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(400).send({ message });
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,28 @@
|
||||
import express from 'express';
|
||||
import { getUrlPresets, postUrlPresets } from './urlPresets.controller.js';
|
||||
import type { Request, Response } from 'express';
|
||||
import type { ErrorResponse, URLPreset } from 'ontime-types';
|
||||
import { getErrorMessage } from 'ontime-utils';
|
||||
import { validateUrlPresets } from './urlPresets.validation.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
|
||||
export const router = express.Router();
|
||||
|
||||
router.get('/', getUrlPresets);
|
||||
router.post('/', validateUrlPresets, postUrlPresets);
|
||||
router.get('/', (_req: Request, res: Response<URLPreset[]>) => {
|
||||
const presets = getDataProvider().getUrlPresets();
|
||||
res.status(200).send(presets as URLPreset[]);
|
||||
});
|
||||
|
||||
router.post('/', validateUrlPresets, async (req: Request, res: Response<URLPreset[] | ErrorResponse>) => {
|
||||
try {
|
||||
const newPresets: URLPreset[] = req.body.map((preset: URLPreset) => ({
|
||||
enabled: preset.enabled,
|
||||
alias: preset.alias,
|
||||
pathAndParams: preset.pathAndParams,
|
||||
}));
|
||||
await getDataProvider().setUrlPresets(newPresets);
|
||||
res.status(200).send(newPresets);
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
res.status(400).send({ message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
import { body, validationResult } from 'express-validator';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { body } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
/**
|
||||
* validate array of URL preset objects
|
||||
*/
|
||||
export const validateUrlPresets = [
|
||||
body().isArray(),
|
||||
body().isArray().withMessage('No array found in request'),
|
||||
body('*.enabled').isBoolean(),
|
||||
body('*.alias').isString().trim(),
|
||||
body('*.pathAndParams').isString().trim(),
|
||||
body('*.alias').isString().trim().notEmpty(),
|
||||
body('*.pathAndParams').isString().trim().notEmpty(),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import { param, validationResult } from 'express-validator';
|
||||
|
||||
/**
|
||||
* Runs validation and any error are sent with status 422
|
||||
*/
|
||||
export function requestValidationFunction(req: Request, res: Response, next: NextFunction) {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
res.status(422).json({ errors: errors.array() });
|
||||
return;
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs validation and any error are sent with status 422
|
||||
* Also checks for the presses of a `file` in the body
|
||||
*/
|
||||
export function requestValidationFunctionWithFile(req: Request, res: Response, next: NextFunction) {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
res.status(422).json({ errors: errors.array() });
|
||||
return;
|
||||
}
|
||||
// check that the file exists
|
||||
if (!req.file) {
|
||||
res.status(422).json({ errors: 'File not found' });
|
||||
return;
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
export const paramsWithId = [param('id').isString().trim().notEmpty(), requestValidationFunction];
|
||||
@@ -1,20 +1,16 @@
|
||||
import { check, validationResult } from 'express-validator';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { body } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
/**
|
||||
* @description Validates object for POST /ontime/views
|
||||
*/
|
||||
export const validateViewSettings = [
|
||||
check('dangerColor').isString().trim().withMessage('dangerColor value must be string'),
|
||||
check('endMessage').isString().trim().withMessage('endMessage value must be string'),
|
||||
check('freezeEnd').isBoolean().withMessage('freezeEnd value must be boolean'),
|
||||
check('normalColor').isString().trim().withMessage('normalColor value must be string'),
|
||||
check('overrideStyles').isBoolean().withMessage('overrideStyles value must be boolean'),
|
||||
check('warningColor').isString().trim().withMessage('warningColor value must be string'),
|
||||
body('dangerColor').isString().trim().withMessage('dangerColor value must be string'),
|
||||
body('endMessage').isString().trim().withMessage('endMessage value must be string'),
|
||||
body('freezeEnd').isBoolean().withMessage('freezeEnd value must be boolean'),
|
||||
body('normalColor').isString().trim().withMessage('normalColor value must be string'),
|
||||
body('overrideStyles').isBoolean().withMessage('overrideStyles value must be boolean'),
|
||||
body('warningColor').isString().trim().withMessage('warningColor value must be string'),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
|
||||
next();
|
||||
},
|
||||
requestValidationFunction,
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user