Typescript migration:
* resources/frontendResource.js * resources/taskResource.js * resources/versionResource.js Also some refactoring towards using promises with async / await.
This commit is contained in:
parent
b1755047af
commit
31ecc0cf4f
10 changed files with 191 additions and 196 deletions
|
@ -3,9 +3,9 @@ import auth, {BasicAuthCheckerCallback} from "http-auth"
|
|||
import bodyParser from "body-parser"
|
||||
import compress from "compression"
|
||||
import express, {Express, NextFunction, Request, Response} from "express"
|
||||
import fs from "graceful-fs"
|
||||
import {promises as fs} from "graceful-fs"
|
||||
|
||||
const config = require('./config').config
|
||||
import {config} from "./config";
|
||||
|
||||
const app: Express = express();
|
||||
|
||||
|
@ -37,26 +37,25 @@ const jsTemplateFiles = [
|
|||
'/config.js'
|
||||
];
|
||||
|
||||
router.use(compress());
|
||||
|
||||
function serveTemplate (mimeType: string, req: Request, res: Response, next: NextFunction): void {
|
||||
return fs.readFile(templateDir + '/' + req.path + '.template', 'utf8', function (err, body) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
res.writeHead(200, { 'Content-Type': mimeType });
|
||||
res.end(_.template(body)({ config: config.client }));
|
||||
|
||||
return null; // to suppress warning
|
||||
function usePromise(f: (req: Request, res: Response) => Promise<void>): void {
|
||||
router.use((req: Request, res: Response, next: NextFunction): void => {
|
||||
f(req, res).then(next).catch(next)
|
||||
});
|
||||
}
|
||||
|
||||
router.use(function (req: Request, res: Response, next: NextFunction): void {
|
||||
router.use(compress());
|
||||
|
||||
async function serveTemplate (mimeType: string, req: Request, res: Response): Promise<void> {
|
||||
const body = await fs.readFile(templateDir + '/' + req.path + '.template', 'utf8');
|
||||
|
||||
res.writeHead(200, { 'Content-Type': mimeType });
|
||||
res.end(_.template(body)({ config: config.client }));
|
||||
}
|
||||
|
||||
usePromise(async (req: Request, res: Response): Promise<void> => {
|
||||
if (jsTemplateFiles.indexOf(req.path) >= 0) {
|
||||
return serveTemplate('application/javascript', req, res, next);
|
||||
await serveTemplate('application/javascript', req, res);
|
||||
}
|
||||
return next();
|
||||
});
|
||||
|
||||
router.use('/internal/admin', express.static(adminDir + '/'));
|
||||
|
|
|
@ -34,7 +34,7 @@ export class Task {
|
|||
public lastRunStarted: moment.Moment | null,
|
||||
public lastRunDuration: number | null,
|
||||
public state: TaskState,
|
||||
public enabled: true,
|
||||
public enabled: boolean,
|
||||
) {}
|
||||
|
||||
run(): void {
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const fs = require('graceful-fs')
|
||||
|
||||
const ErrorTypes = require('../utils/errorTypes')
|
||||
const Logger = require('../logger')
|
||||
const Resources = require('../utils/resources')
|
||||
|
||||
const indexHtml = __dirname + '/../../client/index.html';
|
||||
|
||||
module.exports = {
|
||||
render (req, res) {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
fs.readFile(indexHtml, 'utf8', function (err, body) {
|
||||
if (err) {
|
||||
Logger.tag('frontend').error('Could not read file: ', indexHtml, err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
}
|
||||
|
||||
return Resources.successHtml(
|
||||
res,
|
||||
body.replace(
|
||||
/<body/,
|
||||
'<script>window.__nodeToken = \''+ data.token + '\';</script><body'
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
26
server/resources/frontendResource.ts
Normal file
26
server/resources/frontendResource.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import {promises as fs} from "graceful-fs";
|
||||
|
||||
import ErrorTypes from "../utils/errorTypes";
|
||||
import Logger from "../logger";
|
||||
import * as Resources from "../utils/resources";
|
||||
import {Request, Response} from "express";
|
||||
|
||||
const indexHtml = __dirname + '/../../client/index.html';
|
||||
|
||||
export function render (req: Request, res: Response): void {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
fs.readFile(indexHtml, 'utf8')
|
||||
.then(body =>
|
||||
Resources.successHtml(
|
||||
res,
|
||||
body.replace(
|
||||
/<body/,
|
||||
'<script>window.__nodeToken = \''+ data.token + '\';</script><body'
|
||||
)
|
||||
))
|
||||
.catch(err => {
|
||||
Logger.tag('frontend').error('Could not read file: ', indexHtml, err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
})
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const _ = require('lodash')
|
||||
|
||||
const Constraints = require('../validation/constraints')
|
||||
const ErrorTypes = require('../utils/errorTypes')
|
||||
const Resources = require('../utils/resources')
|
||||
const Scheduler = require('../jobs/scheduler')
|
||||
const Strings = require('../utils/strings')
|
||||
const Validator = require('../validation/validator')
|
||||
|
||||
const isValidId = Validator.forConstraint(Constraints.id);
|
||||
|
||||
function toExternalTask(task) {
|
||||
return {
|
||||
id: task.id,
|
||||
name: task.name,
|
||||
description: task.description,
|
||||
schedule: task.schedule,
|
||||
runningSince: task.runningSince && task.runningSince.unix(),
|
||||
lastRunStarted: task.lastRunStarted && task.lastRunStarted.unix(),
|
||||
lastRunDuration: task.lastRunDuration || undefined,
|
||||
state: task.state,
|
||||
enabled: task.enabled
|
||||
};
|
||||
}
|
||||
|
||||
function withValidTaskId(req, res, callback) {
|
||||
const id = Strings.normalizeString(Resources.getData(req).id);
|
||||
|
||||
if (!isValidId(id)) {
|
||||
return callback({data: 'Invalid task id.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
callback(null, id);
|
||||
}
|
||||
|
||||
function getTask(id, callback) {
|
||||
const tasks = Scheduler.getTasks();
|
||||
const task = tasks[id];
|
||||
|
||||
if (!task) {
|
||||
return callback({data: 'Task not found.', type: ErrorTypes.notFound});
|
||||
}
|
||||
|
||||
callback(null, task);
|
||||
}
|
||||
|
||||
function withTask(req, res, callback) {
|
||||
withValidTaskId(req, res, function (err, id) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
getTask(id, function (err, task) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, task);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setTaskEnabled(req, res, enable) {
|
||||
withTask(req, res, function (err, task) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
task.enabled = !!enable; // ensure boolean
|
||||
|
||||
return Resources.success(res, toExternalTask(task));
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAll (req, res) {
|
||||
Resources.getValidRestParams('list', null, req, function (err, restParams) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
const tasks = Resources.sort(
|
||||
_.values(Scheduler.getTasks()),
|
||||
['id', 'name', 'schedule', 'state', 'runningSince', 'lastRunStarted'],
|
||||
restParams
|
||||
);
|
||||
const filteredTasks = Resources.filter(
|
||||
tasks,
|
||||
['id', 'name', 'schedule', 'state'],
|
||||
restParams
|
||||
);
|
||||
const total = filteredTasks.length;
|
||||
|
||||
const pageTasks = Resources.getPageEntities(filteredTasks, restParams);
|
||||
|
||||
res.set('X-Total-Count', total);
|
||||
return Resources.success(res, _.map(pageTasks, toExternalTask));
|
||||
});
|
||||
},
|
||||
|
||||
run (req, res) {
|
||||
withTask(req, res, function (err, task) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
if (task.runningSince) {
|
||||
return Resources.error(res, {data: 'Task already running.', type: ErrorTypes.conflict});
|
||||
}
|
||||
|
||||
task.run();
|
||||
|
||||
return Resources.success(res, toExternalTask(task));
|
||||
});
|
||||
},
|
||||
|
||||
enable (req, res) {
|
||||
setTaskEnabled(req, res, true);
|
||||
},
|
||||
|
||||
disable (req, res) {
|
||||
setTaskEnabled(req, res, false);
|
||||
}
|
||||
}
|
129
server/resources/taskResource.ts
Normal file
129
server/resources/taskResource.ts
Normal file
|
@ -0,0 +1,129 @@
|
|||
import _ from "lodash";
|
||||
|
||||
import CONSTRAINTS from "../validation/constraints";
|
||||
import ErrorTypes from "../utils/errorTypes";
|
||||
import * as Resources from "../utils/resources";
|
||||
import {getTasks, Task} from "../jobs/scheduler";
|
||||
import {normalizeString} from "../utils/strings";
|
||||
import {forConstraint} from "../validation/validator";
|
||||
import {Request, Response} from "express";
|
||||
|
||||
const isValidId = forConstraint(CONSTRAINTS.id, false);
|
||||
|
||||
interface ExternalTask {
|
||||
id: number,
|
||||
name: string,
|
||||
description: string,
|
||||
schedule: string,
|
||||
runningSince: number | null,
|
||||
lastRunStarted: number | null,
|
||||
lastRunDuration: number | null,
|
||||
state: string,
|
||||
enabled: boolean,
|
||||
}
|
||||
|
||||
function toExternalTask(task: Task): ExternalTask {
|
||||
return {
|
||||
id: task.id,
|
||||
name: task.name,
|
||||
description: task.description,
|
||||
schedule: task.schedule,
|
||||
runningSince: task.runningSince && task.runningSince.unix(),
|
||||
lastRunStarted: task.lastRunStarted && task.lastRunStarted.unix(),
|
||||
lastRunDuration: task.lastRunDuration || null,
|
||||
state: task.state,
|
||||
enabled: task.enabled
|
||||
};
|
||||
}
|
||||
|
||||
async function withValidTaskId(req: Request): Promise<string> {
|
||||
const id = normalizeString(Resources.getData(req).id);
|
||||
|
||||
if (!isValidId(id)) {
|
||||
throw {data: 'Invalid task id.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
async function getTask(id: string): Promise<Task> {
|
||||
const tasks = getTasks();
|
||||
const task = tasks[id];
|
||||
|
||||
if (!task) {
|
||||
throw {data: 'Task not found.', type: ErrorTypes.notFound};
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
async function withTask(req: Request): Promise<Task> {
|
||||
const id = await withValidTaskId(req);
|
||||
return await getTask(id);
|
||||
}
|
||||
|
||||
function setTaskEnabled(req: Request, res: Response, enable: boolean) {
|
||||
withTask(req)
|
||||
.then(task => {
|
||||
task.enabled = enable;
|
||||
Resources.success(res, toExternalTask(task))
|
||||
})
|
||||
.catch(err => Resources.error(res, err))
|
||||
}
|
||||
|
||||
export function getAll (req: Request, res: Response): void {
|
||||
Resources.getValidRestParams('list', null, req, function (err, restParams) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
if (!restParams) {
|
||||
return Resources.error(
|
||||
res,
|
||||
{
|
||||
data: "Unexpected state: restParams is not set.",
|
||||
type: ErrorTypes.internalError
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const tasks = Resources.sort(
|
||||
_.values(getTasks()),
|
||||
['id', 'name', 'schedule', 'state', 'runningSince', 'lastRunStarted'],
|
||||
restParams
|
||||
);
|
||||
const filteredTasks = Resources.filter(
|
||||
tasks,
|
||||
['id', 'name', 'schedule', 'state'],
|
||||
restParams
|
||||
);
|
||||
const total = filteredTasks.length;
|
||||
|
||||
const pageTasks = Resources.getPageEntities(filteredTasks, restParams);
|
||||
|
||||
res.set('X-Total-Count', total.toString(10));
|
||||
return Resources.success(res, _.map(pageTasks, toExternalTask));
|
||||
});
|
||||
}
|
||||
|
||||
export function run (req: Request, res: Response): void {
|
||||
withTask(req)
|
||||
.then(task => {
|
||||
if (task.runningSince) {
|
||||
return Resources.error(res, {data: 'Task already running.', type: ErrorTypes.conflict});
|
||||
}
|
||||
|
||||
task.run();
|
||||
|
||||
Resources.success(res, toExternalTask(task));
|
||||
})
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
export function enable (req: Request, res: Response): void {
|
||||
setTaskEnabled(req, res, true);
|
||||
}
|
||||
|
||||
export function disable (req: Request, res: Response): void {
|
||||
setTaskEnabled(req, res, false);
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const Resources = require('../utils/resources')
|
||||
const version = require('../config').version
|
||||
|
||||
module.exports = {
|
||||
get (req, res) {
|
||||
return Resources.success(
|
||||
res,
|
||||
{
|
||||
version
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
12
server/resources/versionResource.ts
Normal file
12
server/resources/versionResource.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import {success} from "../utils/resources";
|
||||
import {version} from "../config";
|
||||
import {Request, Response} from "express";
|
||||
|
||||
export function get (req: Request, res: Response): void {
|
||||
success(
|
||||
res,
|
||||
{
|
||||
version
|
||||
}
|
||||
);
|
||||
}
|
|
@ -3,12 +3,12 @@ import express from "express"
|
|||
import app from "./app"
|
||||
import {config} from "./config"
|
||||
|
||||
import VersionResource from "./resources/versionResource"
|
||||
import * as VersionResource from "./resources/versionResource"
|
||||
import StatisticsResource from "./resources/statisticsResource"
|
||||
import FrontendResource from "./resources/frontendResource"
|
||||
import * as FrontendResource from "./resources/frontendResource"
|
||||
import NodeResource from "./resources/nodeResource"
|
||||
import MonitoringResource from "./resources/monitoringResource"
|
||||
import TaskResource from "./resources/taskResource"
|
||||
import * as TaskResource from "./resources/taskResource"
|
||||
import MailResource from "./resources/mailResource"
|
||||
|
||||
export function init (): void {
|
||||
|
|
|
@ -116,7 +116,7 @@ export function getData (req: Request): any {
|
|||
// TODO: Promisify.
|
||||
export function getValidRestParams(
|
||||
type: string,
|
||||
subtype: string,
|
||||
subtype: string | null,
|
||||
req: Request,
|
||||
callback: (err: {data: any, type: {code: number}} | null, restParams?: RestParams) => void
|
||||
) {
|
||||
|
@ -155,7 +155,7 @@ export function getValidRestParams(
|
|||
callback(null, restParams as RestParams);
|
||||
}
|
||||
|
||||
export function filter (entities: {[key: string]: Entity}, allowedFilterFields: string[], restParams: RestParams) {
|
||||
export function filter (entities: ArrayLike<Entity>, allowedFilterFields: string[], restParams: RestParams) {
|
||||
let query = restParams.q;
|
||||
if (query) {
|
||||
query = _.toLower(query.trim());
|
||||
|
@ -225,11 +225,11 @@ export function sort<T>(entities: ArrayLike<T>, allowedSortFields: string[], res
|
|||
}
|
||||
}
|
||||
|
||||
export function getPageEntities (entities: Entity[], restParams: RestParams) {
|
||||
export function getPageEntities (entities: ArrayLike<Entity>, restParams: RestParams) {
|
||||
const page = restParams._page;
|
||||
const perPage = restParams._perPage;
|
||||
|
||||
return entities.slice((page - 1) * perPage, page * perPage);
|
||||
return _.slice(entities, (page - 1) * perPage, page * perPage);
|
||||
}
|
||||
|
||||
export {filterCondition as whereCondition};
|
||||
|
|
Loading…
Reference in a new issue