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
|
@ -3,9 +3,9 @@ import auth, {BasicAuthCheckerCallback} from "http-auth"
|
||||||
import bodyParser from "body-parser"
|
import bodyParser from "body-parser"
|
||||||
import compress from "compression"
|
import compress from "compression"
|
||||||
import express, {Express, NextFunction, Request, Response} from "express"
|
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();
|
const app: Express = express();
|
||||||
|
|
||||||
|
@ -37,26 +37,25 @@ const jsTemplateFiles = [
|
||||||
'/config.js'
|
'/config.js'
|
||||||
];
|
];
|
||||||
|
|
||||||
router.use(compress());
|
function usePromise(f: (req: Request, res: Response) => Promise<void>): void {
|
||||||
|
router.use((req: Request, res: Response, next: NextFunction): void => {
|
||||||
function serveTemplate (mimeType: string, req: Request, res: Response, next: NextFunction): void {
|
f(req, res).then(next).catch(next)
|
||||||
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
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
router.use(function (req: Request, res: Response, next: NextFunction): void {
|
router.use(compress());
|
||||||
if (jsTemplateFiles.indexOf(req.path) >= 0) {
|
|
||||||
return serveTemplate('application/javascript', req, res, next);
|
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) {
|
||||||
|
await serveTemplate('application/javascript', req, res);
|
||||||
}
|
}
|
||||||
return next();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.use('/internal/admin', express.static(adminDir + '/'));
|
router.use('/internal/admin', express.static(adminDir + '/'));
|
||||||
|
|
|
@ -34,7 +34,7 @@ export class Task {
|
||||||
public lastRunStarted: moment.Moment | null,
|
public lastRunStarted: moment.Moment | null,
|
||||||
public lastRunDuration: number | null,
|
public lastRunDuration: number | null,
|
||||||
public state: TaskState,
|
public state: TaskState,
|
||||||
public enabled: true,
|
public enabled: boolean,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
run(): void {
|
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 app from "./app"
|
||||||
import {config} from "./config"
|
import {config} from "./config"
|
||||||
|
|
||||||
import VersionResource from "./resources/versionResource"
|
import * as VersionResource from "./resources/versionResource"
|
||||||
import StatisticsResource from "./resources/statisticsResource"
|
import StatisticsResource from "./resources/statisticsResource"
|
||||||
import FrontendResource from "./resources/frontendResource"
|
import * as FrontendResource from "./resources/frontendResource"
|
||||||
import NodeResource from "./resources/nodeResource"
|
import NodeResource from "./resources/nodeResource"
|
||||||
import MonitoringResource from "./resources/monitoringResource"
|
import MonitoringResource from "./resources/monitoringResource"
|
||||||
import TaskResource from "./resources/taskResource"
|
import * as TaskResource from "./resources/taskResource"
|
||||||
import MailResource from "./resources/mailResource"
|
import MailResource from "./resources/mailResource"
|
||||||
|
|
||||||
export function init (): void {
|
export function init (): void {
|
||||||
|
|
|
@ -116,7 +116,7 @@ export function getData (req: Request): any {
|
||||||
// TODO: Promisify.
|
// TODO: Promisify.
|
||||||
export function getValidRestParams(
|
export function getValidRestParams(
|
||||||
type: string,
|
type: string,
|
||||||
subtype: string,
|
subtype: string | null,
|
||||||
req: Request,
|
req: Request,
|
||||||
callback: (err: {data: any, type: {code: number}} | null, restParams?: RestParams) => void
|
callback: (err: {data: any, type: {code: number}} | null, restParams?: RestParams) => void
|
||||||
) {
|
) {
|
||||||
|
@ -155,7 +155,7 @@ export function getValidRestParams(
|
||||||
callback(null, restParams as RestParams);
|
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;
|
let query = restParams.q;
|
||||||
if (query) {
|
if (query) {
|
||||||
query = _.toLower(query.trim());
|
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 page = restParams._page;
|
||||||
const perPage = restParams._perPage;
|
const perPage = restParams._perPage;
|
||||||
|
|
||||||
return entities.slice((page - 1) * perPage, page * perPage);
|
return _.slice(entities, (page - 1) * perPage, page * perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {filterCondition as whereCondition};
|
export {filterCondition as whereCondition};
|
||||||
|
|
Loading…
Reference in a new issue