Major refactoring and fixes.
* Split Node into multiple types and make sure fields are actually set when type says so. * Refactor request handling. * Start getting rid of moment as a dependency by using UnixTimestampSeconds instead.
This commit is contained in:
parent
cfa784dfe2
commit
250353edbf
16 changed files with 676 additions and 455 deletions
|
@ -1,10 +1,4 @@
|
|||
import {success} from "../utils/resources";
|
||||
import {handleJSON} from "../utils/resources";
|
||||
import {config} from "../config";
|
||||
import {Request, Response} from "express";
|
||||
|
||||
export function get (req: Request, res: Response): void {
|
||||
success(
|
||||
res,
|
||||
config.client
|
||||
);
|
||||
}
|
||||
export const get = handleJSON(async () => config.client);
|
||||
|
|
|
@ -2,15 +2,20 @@ import CONSTRAINTS from "../validation/constraints";
|
|||
import ErrorTypes from "../utils/errorTypes";
|
||||
import * as MailService from "../services/mailService";
|
||||
import * as Resources from "../utils/resources";
|
||||
import {handleJSONWithData, RequestData} from "../utils/resources";
|
||||
import {normalizeString, parseInteger} from "../utils/strings";
|
||||
import {forConstraint} from "../validation/validator";
|
||||
import {Request, Response} from "express";
|
||||
import {Mail, MailId} from "../types";
|
||||
import {isString, Mail, MailId} from "../types";
|
||||
|
||||
const isValidId = forConstraint(CONSTRAINTS.id, false);
|
||||
|
||||
async function withValidMailId(req: Request): Promise<MailId> {
|
||||
const id = normalizeString(Resources.getData(req).id);
|
||||
async function withValidMailId(data: RequestData): Promise<MailId> {
|
||||
if (!isString(data.id)) {
|
||||
throw {data: 'Missing mail id.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
|
||||
const id = normalizeString(data.id);
|
||||
|
||||
if (!isValidId(id)) {
|
||||
throw {data: 'Invalid mail id.', type: ErrorTypes.badRequest};
|
||||
|
@ -19,23 +24,17 @@ async function withValidMailId(req: Request): Promise<MailId> {
|
|||
return parseInteger(id) as MailId;
|
||||
}
|
||||
|
||||
async function doGet(req: Request): Promise<Mail> {
|
||||
const id = await withValidMailId(req);
|
||||
export const get = handleJSONWithData(async data => {
|
||||
const id = await withValidMailId(data);
|
||||
return await MailService.getMail(id);
|
||||
}
|
||||
});
|
||||
|
||||
export function get(req: Request, res: Response): void {
|
||||
doGet(req)
|
||||
.then(mail => Resources.success(res, mail))
|
||||
.catch(err => Resources.error(res, err))
|
||||
}
|
||||
|
||||
async function doGetAll(req: Request): Promise<{total: number, mails: Mail[]}> {
|
||||
async function doGetAll(req: Request): Promise<{ total: number, mails: Mail[] }> {
|
||||
const restParams = await Resources.getValidRestParams('list', null, req);
|
||||
return await MailService.getPendingMails(restParams);
|
||||
}
|
||||
|
||||
export function getAll (req: Request, res: Response): void {
|
||||
export function getAll(req: Request, res: Response): void {
|
||||
doGetAll(req)
|
||||
.then(({total, mails}) => {
|
||||
res.set('X-Total-Count', total.toString(10));
|
||||
|
@ -44,24 +43,12 @@ export function getAll (req: Request, res: Response): void {
|
|||
.catch(err => Resources.error(res, err))
|
||||
}
|
||||
|
||||
async function doRemove(req: Request): Promise<void> {
|
||||
const id = await withValidMailId(req);
|
||||
export const remove = handleJSONWithData(async data => {
|
||||
const id = await withValidMailId(data);
|
||||
await MailService.deleteMail(id);
|
||||
}
|
||||
});
|
||||
|
||||
export function remove (req: Request, res: Response): void {
|
||||
doRemove(req)
|
||||
.then(() => Resources.success(res, {}))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
async function doResetFailures(req: Request): Promise<Mail> {
|
||||
const id = await withValidMailId(req);
|
||||
export const resetFailures = handleJSONWithData(async data => {
|
||||
const id = await withValidMailId(data);
|
||||
return await MailService.resetFailures(id);
|
||||
}
|
||||
|
||||
export function resetFailures (req: Request, res: Response): void {
|
||||
doResetFailures(req)
|
||||
.then(mail => Resources.success(res, mail))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,14 +4,15 @@ import CONSTRAINTS from "../validation/constraints";
|
|||
import ErrorTypes from "../utils/errorTypes";
|
||||
import * as MonitoringService from "../services/monitoringService";
|
||||
import * as Resources from "../utils/resources";
|
||||
import {handleJSONWithData} from "../utils/resources";
|
||||
import {normalizeString} from "../utils/strings";
|
||||
import {forConstraint} from "../validation/validator";
|
||||
import {Request, Response} from "express";
|
||||
import {MonitoringToken} from "../types";
|
||||
import {MonitoringResponse, MonitoringToken, toMonitoringResponse} from "../types";
|
||||
|
||||
const isValidToken = forConstraint(CONSTRAINTS.token, false);
|
||||
|
||||
async function doGetAll(req: Request): Promise<{total: number, result: any}> {
|
||||
async function doGetAll(req: Request): Promise<{ total: number, result: any }> {
|
||||
const restParams = await Resources.getValidRestParams('list', null, req);
|
||||
const {monitoringStates, total} = await MonitoringService.getAll(restParams);
|
||||
return {
|
||||
|
@ -32,41 +33,24 @@ export function getAll(req: Request, res: Response): void {
|
|||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
export function confirm(req: Request, res: Response): void {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
export const confirm = handleJSONWithData<MonitoringResponse>(async data => {
|
||||
const token = normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
throw {data: 'Invalid token.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
const validatedToken: MonitoringToken = token as MonitoringToken;
|
||||
|
||||
MonitoringService.confirm(validatedToken)
|
||||
.then(node => Resources.success(res, {
|
||||
hostname: node.hostname,
|
||||
mac: node.mac,
|
||||
email: node.email,
|
||||
monitoring: node.monitoring,
|
||||
monitoringConfirmed: node.monitoringConfirmed
|
||||
}))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
export function disable(req: Request, res: Response): void {
|
||||
const data = Resources.getData(req);
|
||||
const node = await MonitoringService.confirm(validatedToken);
|
||||
return toMonitoringResponse(node);
|
||||
});
|
||||
|
||||
export const disable = handleJSONWithData<MonitoringResponse>(async data => {
|
||||
const token = normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
throw {data: 'Invalid token.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
const validatedToken: MonitoringToken = token as MonitoringToken;
|
||||
|
||||
MonitoringService.disable(validatedToken)
|
||||
.then(node => Resources.success(res, {
|
||||
hostname: node.hostname,
|
||||
mac: node.mac,
|
||||
email: node.email,
|
||||
monitoring: node.monitoring
|
||||
}))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
const node = await MonitoringService.disable(validatedToken);
|
||||
return toMonitoringResponse(node);
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import _ from "lodash";
|
||||
import deepExtend from "deep-extend";
|
||||
|
||||
import Constraints from "../validation/constraints";
|
||||
import ErrorTypes from "../utils/errorTypes";
|
||||
|
@ -8,13 +7,28 @@ import * as NodeService from "../services/nodeService";
|
|||
import {normalizeMac, normalizeString} from "../utils/strings";
|
||||
import {forConstraint, forConstraints} from "../validation/validator";
|
||||
import * as Resources from "../utils/resources";
|
||||
import {handleJSONWithData} from "../utils/resources";
|
||||
import {Request, Response} from "express";
|
||||
import {EnhancedNode, isNodeSortField, MAC, Node, Token} from "../types";
|
||||
import {
|
||||
CreateOrUpdateNode,
|
||||
DomainSpecificNodeResponse,
|
||||
isNodeSortField,
|
||||
isToken, JSONObject,
|
||||
MAC,
|
||||
NodeResponse,
|
||||
NodeStateData,
|
||||
NodeTokenResponse,
|
||||
StoredNode,
|
||||
toDomainSpecificNodeResponse,
|
||||
Token,
|
||||
toNodeResponse,
|
||||
toNodeTokenResponse
|
||||
} from "../types";
|
||||
|
||||
const nodeFields = ['hostname', 'key', 'email', 'nickname', 'mac', 'coords', 'monitoring'];
|
||||
|
||||
function getNormalizedNodeData(reqData: any): Node {
|
||||
const node: {[key: string]: any} = {};
|
||||
function getNormalizedNodeData(reqData: any): CreateOrUpdateNode {
|
||||
const node: { [key: string]: any } = {};
|
||||
_.each(nodeFields, function (field) {
|
||||
let value = normalizeString(reqData[field]);
|
||||
if (field === 'mac') {
|
||||
|
@ -22,69 +36,54 @@ function getNormalizedNodeData(reqData: any): Node {
|
|||
}
|
||||
node[field] = value;
|
||||
});
|
||||
return node as Node;
|
||||
return node as CreateOrUpdateNode;
|
||||
}
|
||||
|
||||
const isValidNode = forConstraints(Constraints.node, false);
|
||||
const isValidToken = forConstraint(Constraints.token, false);
|
||||
|
||||
export function create (req: Request, res: Response): void {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
const node = getNormalizedNodeData(data);
|
||||
if (!isValidNode(node)) {
|
||||
return Resources.error(res, {data: 'Invalid node data.', type: ErrorTypes.badRequest});
|
||||
function getValidatedToken(data: JSONObject): Token {
|
||||
if (!isToken(data.token)) {
|
||||
throw {data: 'Missing token.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
|
||||
NodeService.createNode(node)
|
||||
.then(result => Resources.success(res, result))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
export function update (req: Request, res: Response): void {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
const token = normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
throw {data: 'Invalid token.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
const validatedToken: Token = token as Token;
|
||||
|
||||
const node = getNormalizedNodeData(data);
|
||||
if (!isValidNode(node)) {
|
||||
return Resources.error(res, {data: 'Invalid node data.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
NodeService.updateNode(validatedToken, node)
|
||||
.then(result => Resources.success(res, result))
|
||||
.catch(err => Resources.error(res, err));
|
||||
return token as Token;
|
||||
}
|
||||
|
||||
export function remove(req: Request, res: Response): void {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
const token = normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
export const create = handleJSONWithData<NodeTokenResponse>(async data => {
|
||||
const baseNode = getNormalizedNodeData(data);
|
||||
if (!isValidNode(baseNode)) {
|
||||
throw {data: 'Invalid node data.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
const validatedToken: Token = token as Token;
|
||||
|
||||
NodeService.deleteNode(validatedToken)
|
||||
.then(() => Resources.success(res, {}))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
const node = await NodeService.createNode(baseNode);
|
||||
return toNodeTokenResponse(node);
|
||||
});
|
||||
|
||||
export function get(req: Request, res: Response): void {
|
||||
const token = normalizeString(Resources.getData(req).token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
export const update = handleJSONWithData<NodeTokenResponse>(async data => {
|
||||
const validatedToken: Token = getValidatedToken(data);
|
||||
const baseNode = getNormalizedNodeData(data);
|
||||
if (!isValidNode(baseNode)) {
|
||||
throw {data: 'Invalid node data.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
const validatedToken: Token = token as Token;
|
||||
|
||||
NodeService.getNodeDataByToken(validatedToken)
|
||||
.then(node => Resources.success(res, node))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
const node = await NodeService.updateNode(validatedToken, baseNode);
|
||||
return toNodeTokenResponse(node);
|
||||
});
|
||||
|
||||
export const remove = handleJSONWithData<void>(async data => {
|
||||
const validatedToken = getValidatedToken(data);
|
||||
await NodeService.deleteNode(validatedToken);
|
||||
});
|
||||
|
||||
export const get = handleJSONWithData<NodeResponse>(async data => {
|
||||
const validatedToken: Token = getValidatedToken(data);
|
||||
const node = await NodeService.getNodeDataByToken(validatedToken);
|
||||
return toNodeResponse(node);
|
||||
});
|
||||
|
||||
async function doGetAll(req: Request): Promise<{ total: number; pageNodes: any }> {
|
||||
const restParams = await Resources.getValidRestParams('list', 'node', req);
|
||||
|
@ -96,24 +95,16 @@ async function doGetAll(req: Request): Promise<{ total: number; pageNodes: any }
|
|||
!!node.token
|
||||
);
|
||||
|
||||
const macs: MAC[] = _.map(realNodes, (node: Node): MAC => node.mac);
|
||||
const macs: MAC[] = _.map(realNodes, (node: StoredNode): MAC => node.mac);
|
||||
const nodeStateByMac = await MonitoringService.getByMacs(macs);
|
||||
|
||||
const enhancedNodes: EnhancedNode[] = _.map(realNodes, (node: Node): EnhancedNode => {
|
||||
const nodeState = nodeStateByMac[node.mac];
|
||||
if (nodeState) {
|
||||
return deepExtend({}, node, {
|
||||
site: nodeState.site,
|
||||
domain: nodeState.domain,
|
||||
onlineState: nodeState.state
|
||||
});
|
||||
}
|
||||
|
||||
return node as EnhancedNode;
|
||||
const domainSpecificNodes: DomainSpecificNodeResponse[] = _.map(realNodes, (node: StoredNode): DomainSpecificNodeResponse => {
|
||||
const nodeState: NodeStateData = nodeStateByMac[node.mac] || {};
|
||||
return toDomainSpecificNodeResponse(node, nodeState);
|
||||
});
|
||||
|
||||
const filteredNodes = Resources.filter<EnhancedNode>(
|
||||
enhancedNodes,
|
||||
const filteredNodes = Resources.filter<DomainSpecificNodeResponse>(
|
||||
domainSpecificNodes,
|
||||
[
|
||||
'hostname',
|
||||
'nickname',
|
||||
|
@ -142,7 +133,7 @@ async function doGetAll(req: Request): Promise<{ total: number; pageNodes: any }
|
|||
|
||||
export function getAll(req: Request, res: Response): void {
|
||||
doGetAll(req)
|
||||
.then((result: {total: number, pageNodes: any[]}) => {
|
||||
.then((result: { total: number, pageNodes: any[] }) => {
|
||||
res.set('X-Total-Count', result.total.toString(10));
|
||||
return Resources.success(res, result.pageNodes);
|
||||
})
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
import ErrorTypes from "../utils/errorTypes";
|
||||
import Logger from "../logger";
|
||||
import {getNodeStatistics} from "../services/nodeService";
|
||||
import * as Resources from "../utils/resources";
|
||||
import {Request, Response} from "express";
|
||||
import {handleJSON} from "../utils/resources";
|
||||
|
||||
export function get (req: Request, res: Response): void {
|
||||
getNodeStatistics()
|
||||
.then(nodeStatistics => Resources.success(
|
||||
res,
|
||||
{
|
||||
nodes: nodeStatistics
|
||||
}
|
||||
))
|
||||
.catch(err => {
|
||||
Logger.tag('statistics').error('Error getting statistics:', err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
});
|
||||
}
|
||||
export const get = handleJSON(async () => {
|
||||
try {
|
||||
const nodeStatistics = await getNodeStatistics();
|
||||
return {
|
||||
nodes: nodeStatistics
|
||||
};
|
||||
} catch (error) {
|
||||
Logger.tag('statistics').error('Error getting statistics:', error);
|
||||
throw {data: 'Internal error.', type: ErrorTypes.internalError};
|
||||
}
|
||||
});
|
||||
|
|
|
@ -3,16 +3,16 @@ import _ from "lodash";
|
|||
import CONSTRAINTS from "../validation/constraints";
|
||||
import ErrorTypes from "../utils/errorTypes";
|
||||
import * as Resources from "../utils/resources";
|
||||
import {Entity} from "../utils/resources";
|
||||
import {Entity, handleJSONWithData, RequestData} from "../utils/resources";
|
||||
import {getTasks, Task, TaskState} from "../jobs/scheduler";
|
||||
import {normalizeString} from "../utils/strings";
|
||||
import {forConstraint} from "../validation/validator";
|
||||
import {Request, Response} from "express";
|
||||
import {isTaskSortField} from "../types";
|
||||
import {isString, isTaskSortField} from "../types";
|
||||
|
||||
const isValidId = forConstraint(CONSTRAINTS.id, false);
|
||||
|
||||
interface ExternalTask {
|
||||
interface TaskResponse {
|
||||
id: number,
|
||||
name: string,
|
||||
description: string,
|
||||
|
@ -26,7 +26,7 @@ interface ExternalTask {
|
|||
enabled: boolean,
|
||||
}
|
||||
|
||||
function toExternalTask(task: Task): ExternalTask {
|
||||
function toTaskResponse(task: Task): TaskResponse {
|
||||
return {
|
||||
id: task.id,
|
||||
name: task.name,
|
||||
|
@ -37,13 +37,16 @@ function toExternalTask(task: Task): ExternalTask {
|
|||
lastRunDuration: task.lastRunDuration || null,
|
||||
state: task.state,
|
||||
result: task.state !== TaskState.RUNNING && task.result ? task.result.state : null,
|
||||
message:task.state !== TaskState.RUNNING && task.result ? task.result.message || null : null,
|
||||
message: task.state !== TaskState.RUNNING && task.result ? task.result.message || null : null,
|
||||
enabled: task.enabled
|
||||
};
|
||||
}
|
||||
|
||||
async function withValidTaskId(req: Request): Promise<string> {
|
||||
const id = normalizeString(Resources.getData(req).id);
|
||||
async function withValidTaskId(data: RequestData): Promise<string> {
|
||||
if (!isString(data.id)) {
|
||||
throw {data: 'Missing task id.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
const id = normalizeString(data.id);
|
||||
|
||||
if (!isValidId(id)) {
|
||||
throw {data: 'Invalid task id.', type: ErrorTypes.badRequest};
|
||||
|
@ -63,21 +66,18 @@ async function getTask(id: string): Promise<Task> {
|
|||
return task;
|
||||
}
|
||||
|
||||
async function withTask(req: Request): Promise<Task> {
|
||||
const id = await withValidTaskId(req);
|
||||
async function withTask(data: RequestData): Promise<Task> {
|
||||
const id = await withValidTaskId(data);
|
||||
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))
|
||||
async function setTaskEnabled(data: RequestData, enable: boolean): Promise<TaskResponse> {
|
||||
const task = await withTask(data);
|
||||
task.enabled = enable;
|
||||
return toTaskResponse(task);
|
||||
}
|
||||
|
||||
async function doGetAll(req: Request): Promise<{total: number, pageTasks: Entity[]}> {
|
||||
async function doGetAll(req: Request): Promise<{ total: number, pageTasks: Entity[] }> {
|
||||
const restParams = await Resources.getValidRestParams('list', null, req);
|
||||
|
||||
const tasks = Resources.sort(
|
||||
|
@ -100,33 +100,30 @@ async function doGetAll(req: Request): Promise<{total: number, pageTasks: Entity
|
|||
};
|
||||
}
|
||||
|
||||
export function getAll (req: Request, res: Response): void {
|
||||
export function getAll(req: Request, res: Response): void {
|
||||
doGetAll(req)
|
||||
.then(({total, pageTasks}) => {
|
||||
res.set('X-Total-Count', total.toString(10));
|
||||
Resources.success(res, _.map(pageTasks, toExternalTask));
|
||||
Resources.success(res, _.map(pageTasks, toTaskResponse));
|
||||
})
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
export const run = handleJSONWithData(async data => {
|
||||
const task = await withTask(data);
|
||||
|
||||
task.run();
|
||||
if (task.runningSince) {
|
||||
throw {data: 'Task already running.', type: ErrorTypes.conflict};
|
||||
}
|
||||
|
||||
Resources.success(res, toExternalTask(task));
|
||||
})
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
task.run();
|
||||
return toTaskResponse(task);
|
||||
});
|
||||
|
||||
export function enable (req: Request, res: Response): void {
|
||||
setTaskEnabled(req, res, true);
|
||||
}
|
||||
export const enable = handleJSONWithData(async data => {
|
||||
await setTaskEnabled(data, true);
|
||||
});
|
||||
|
||||
export function disable (req: Request, res: Response): void {
|
||||
setTaskEnabled(req, res, false);
|
||||
}
|
||||
export const disable = handleJSONWithData(async data => {
|
||||
await setTaskEnabled(data, false);
|
||||
});
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import {success} from "../utils/resources";
|
||||
import {handleJSON} from "../utils/resources";
|
||||
import {version} from "../config";
|
||||
import {Request, Response} from "express";
|
||||
|
||||
export function get (req: Request, res: Response): void {
|
||||
success(
|
||||
res,
|
||||
{
|
||||
version
|
||||
}
|
||||
);
|
||||
}
|
||||
export const get = handleJSON(async () => ({
|
||||
version
|
||||
}));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue