Typescript migration: Major refactoring.
This commit is contained in:
parent
31ecc0cf4f
commit
52822207a5
31 changed files with 2067 additions and 2267 deletions
|
|
@ -1,18 +1,25 @@
|
|||
# Refactoring ideas
|
||||
|
||||
## TODO:
|
||||
|
||||
* Test email rendering!
|
||||
|
||||
## Short term
|
||||
|
||||
* Integrate typescript in the build and start migrating the server code.
|
||||
* Find a nice way to integrate typescript with grunt.
|
||||
* Replace logging framework.
|
||||
* Bluebird for promises?
|
||||
|
||||
## Mid term
|
||||
|
||||
* Typesafe db queries.
|
||||
* Port complete server to typescript.
|
||||
* Port the server code to promises and `async` / `await`.
|
||||
* Use ES6 style imports instead of `require`.
|
||||
* Store node data in database and export it for gateways.
|
||||
* Write tests (especially testing quirky node data).
|
||||
* Allow terminating running tasks via bluebirds cancellation.
|
||||
|
||||
## Long term
|
||||
|
||||
|
|
|
|||
88
package-lock.json
generated
88
package-lock.json
generated
|
|
@ -26,6 +26,12 @@
|
|||
"integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/async": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.0.tgz",
|
||||
"integrity": "sha512-7dhGj2u7hS+Y/NPxFDaTL/kbTvVjOKvZmD+GZp0jGGOLvnakomncrqSReX+xPAGGZuCUSUsXXy9I9pEpSwxpKA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/babel-types": {
|
||||
"version": "7.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.7.tgz",
|
||||
|
|
@ -53,6 +59,12 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/caseless": {
|
||||
"version": "0.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
|
||||
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/command-line-args": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.0.0.tgz",
|
||||
|
|
@ -137,6 +149,12 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/html-to-text": {
|
||||
"version": "1.4.31",
|
||||
"resolved": "https://registry.npmjs.org/@types/html-to-text/-/html-to-text-1.4.31.tgz",
|
||||
"integrity": "sha512-9vTFw6vYZNnjPOep9WRXs7cw0vg04pAZgcX9bqx70q1BNT7y9sOJovpbiNIcSNyHF/6LscLvGhtb5Og1T0UEvA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.149",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz",
|
||||
|
|
@ -197,6 +215,31 @@
|
|||
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/request": {
|
||||
"version": "2.48.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.4.tgz",
|
||||
"integrity": "sha512-W1t1MTKYR8PxICH+A4HgEIPuAC3sbljoEVfyZbeFJJDbr30guDspJri2XOaM2E+Un7ZjrihaDi7cf6fPa2tbgw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/caseless": "*",
|
||||
"@types/node": "*",
|
||||
"@types/tough-cookie": "*",
|
||||
"form-data": "^2.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
|
||||
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/serve-static": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz",
|
||||
|
|
@ -216,6 +259,12 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/tough-cookie": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
|
||||
"integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/tz-offset": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/tz-offset/-/tz-offset-0.0.0.tgz",
|
||||
|
|
@ -278,9 +327,9 @@
|
|||
"integrity": "sha512-vHiZIDK4QysLXKOGrRJ9IZlUfJuvSUQUELJz4oaj0o70KD7v+Fsate1dMVQd+1LS1VbN73BZe1aEPw8mEjeDcw=="
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz",
|
||||
"integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
|
||||
"integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
|
|
@ -7502,9 +7551,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
|
||||
"integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ=="
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
|
||||
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
|
||||
},
|
||||
"pug": {
|
||||
"version": "2.0.4",
|
||||
|
|
@ -7931,9 +7980,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"request": {
|
||||
"version": "2.88.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
|
||||
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
|
||||
"version": "2.88.2",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
|
||||
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
|
|
@ -7942,7 +7991,7 @@
|
|||
"extend": "~3.0.2",
|
||||
"forever-agent": "~0.6.1",
|
||||
"form-data": "~2.3.2",
|
||||
"har-validator": "~5.1.0",
|
||||
"har-validator": "~5.1.3",
|
||||
"http-signature": "~1.2.0",
|
||||
"is-typedarray": "~1.0.0",
|
||||
"isstream": "~0.1.2",
|
||||
|
|
@ -7952,7 +8001,7 @@
|
|||
"performance-now": "^2.1.0",
|
||||
"qs": "~6.5.2",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"tough-cookie": "~2.4.3",
|
||||
"tough-cookie": "~2.5.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.3.2"
|
||||
},
|
||||
|
|
@ -9194,12 +9243,19 @@
|
|||
"optional": true
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
||||
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
|
||||
"requires": {
|
||||
"psl": "^1.1.24",
|
||||
"punycode": "^1.4.1"
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"trim-newlines": {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
"express": "^4.17.1",
|
||||
"glob": "^7.1.6",
|
||||
"graceful-fs": "^4.2.3",
|
||||
"html-to-text": "^5.1.1",
|
||||
"http-auth": "^3.2.4",
|
||||
"http-errors": "^1.7.3",
|
||||
"lodash": "^4.17.15",
|
||||
|
|
@ -43,7 +44,7 @@
|
|||
"node-cron": "^2.0.1",
|
||||
"nodemailer": "^6.4.2",
|
||||
"nodemailer-html-to-text": "^3.1.0",
|
||||
"request": "^2.88.0",
|
||||
"request": "^2.88.2",
|
||||
"scribe-js": "^2.0.4",
|
||||
"serve-static": "^1.14.1",
|
||||
"sparkson": "^1.3.3",
|
||||
|
|
@ -51,6 +52,7 @@
|
|||
"sqlite3": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/async": "^3.2.0",
|
||||
"@types/command-line-args": "^5.0.0",
|
||||
"@types/command-line-usage": "^5.0.1",
|
||||
"@types/compression": "^1.7.0",
|
||||
|
|
@ -58,10 +60,12 @@
|
|||
"@types/express": "^4.17.4",
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/graceful-fs": "^4.1.3",
|
||||
"@types/html-to-text": "^1.4.31",
|
||||
"@types/lodash": "^4.14.149",
|
||||
"@types/node": "^13.11.0",
|
||||
"@types/node-cron": "^2.0.3",
|
||||
"@types/nodemailer": "^6.4.0",
|
||||
"@types/request": "^2.48.4",
|
||||
"@types/sqlite3": "^3.1.6",
|
||||
"bower": "^1.8.8",
|
||||
"escape-string-regexp": "^2.0.0",
|
||||
|
|
|
|||
5
server/@types/nodemailer-html-to-text/index.d.ts
vendored
Normal file
5
server/@types/nodemailer-html-to-text/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
declare module "nodemailer-html-to-text" {
|
||||
import {PluginFunction} from "nodemailer/lib/mailer";
|
||||
|
||||
export function htmlToText(options: HtmlToTextOptions): PluginFunction;
|
||||
}
|
||||
|
|
@ -2,12 +2,9 @@ import util from "util";
|
|||
import fs from "graceful-fs";
|
||||
import glob from "glob";
|
||||
import path from "path";
|
||||
|
||||
import sqlite from "sqlite";
|
||||
import sqlite3 from "sqlite3";
|
||||
|
||||
import {config} from "../config";
|
||||
import Logger from "../logger";
|
||||
import sqlite, {Database, Statement} from "sqlite";
|
||||
|
||||
const pglob = util.promisify(glob);
|
||||
const pReadFile = util.promisify(fs.readFile);
|
||||
|
|
@ -51,13 +48,15 @@ async function applyMigrations(db: sqlite.Database): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
const file = config.server.databaseFile;
|
||||
const dbPromise = sqlite.open(file);
|
||||
|
||||
export async function init(): Promise<void> {
|
||||
const file = config.server.databaseFile;
|
||||
Logger.tag('database').info('Setting up database: %s', file);
|
||||
|
||||
let db: sqlite.Database;
|
||||
let db: Database;
|
||||
try {
|
||||
db = await sqlite.open(file);
|
||||
db = await dbPromise;
|
||||
}
|
||||
catch (error) {
|
||||
Logger.tag('database').error('Error initialzing database:', error);
|
||||
|
|
@ -73,19 +72,74 @@ export async function init(): Promise<void> {
|
|||
Logger.tag('database').error('Error migrating database:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
await db.close()
|
||||
}
|
||||
|
||||
Logger.tag('database').info('Setting up legacy database: %s', config.server.databaseFile);
|
||||
/**
|
||||
* Wrapper around a Promise<Database> providing the same interface as the Database itself.
|
||||
*/
|
||||
class DatabasePromiseWrapper implements Database {
|
||||
constructor(private db: Promise<Database>) {}
|
||||
|
||||
let legacyDB: sqlite3.Database;
|
||||
try {
|
||||
legacyDB = new sqlite3.Database(config.server.databaseFile);
|
||||
}
|
||||
catch (error) {
|
||||
Logger.tag('database').error('Error initialzing legacy database lib:', error);
|
||||
throw error;
|
||||
async close() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.close.apply(db, arguments);
|
||||
}
|
||||
|
||||
async run() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.run.apply(db, arguments);
|
||||
}
|
||||
|
||||
async get() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.get.apply(db, arguments);
|
||||
}
|
||||
|
||||
async all() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.all.apply(db, arguments);
|
||||
}
|
||||
|
||||
async exec() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.exec.apply(db, arguments);
|
||||
}
|
||||
|
||||
async each() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.each.apply(db, arguments);
|
||||
}
|
||||
|
||||
async prepare() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.prepare.apply(db, arguments);
|
||||
}
|
||||
|
||||
async configure() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.configure.apply(db, arguments);
|
||||
}
|
||||
|
||||
async migrate() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.migrate.apply(db, arguments);
|
||||
}
|
||||
|
||||
async on() {
|
||||
const db = await this.db;
|
||||
// @ts-ignore
|
||||
return await db.on.apply(db, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
export const db = legacyDB;
|
||||
export const db: Database = new DatabasePromiseWrapper(dbPromise);
|
||||
export {Database, Statement};
|
||||
|
|
|
|||
|
|
@ -1,22 +1,8 @@
|
|||
import Logger from "../logger";
|
||||
import NodeService from "../services/nodeService";
|
||||
import {fixNodeFilenames} from "../services/nodeService";
|
||||
|
||||
export default {
|
||||
name: 'FixNodeFilenamesJob',
|
||||
description: 'Makes sure node files (holding fastd key, name, etc.) are correctly named.',
|
||||
|
||||
run: (): Promise<void> => {
|
||||
return new Promise<void>(
|
||||
(resolve, reject) => {
|
||||
NodeService.fixNodeFilenames((err: any): void => {
|
||||
if (err) {
|
||||
Logger.tag('nodes', 'fix-filenames').error('Error fixing filenames:', err);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
run: fixNodeFilenames
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,8 @@
|
|||
import Logger from "../logger"
|
||||
import MailService from "../services/mailService"
|
||||
import * as MailService from "../services/mailService"
|
||||
|
||||
export default {
|
||||
name: 'MailQueueJob',
|
||||
description: 'Send pending emails (up to 5 attempts in case of failures).',
|
||||
|
||||
run: (): Promise<void> => {
|
||||
return new Promise<void>(
|
||||
(resolve, reject) => {
|
||||
MailService.sendPendingMails((err: any): void => {
|
||||
if (err) {
|
||||
Logger.tag('mail', 'queue').error('Error sending pending mails:', err);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
run: MailService.sendPendingMails,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,8 @@
|
|||
import Logger from "../logger";
|
||||
import MonitoringService from "../services/monitoringService";
|
||||
import * as MonitoringService from "../services/monitoringService";
|
||||
|
||||
export default {
|
||||
name: 'MonitoringMailsSendingJob',
|
||||
description: 'Sends monitoring emails depending on the monitoring state of nodes retrieved by the NodeInformationRetrievalJob.',
|
||||
|
||||
run: (): Promise<void> => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
MonitoringService.sendMonitoringMails((err: any): void => {
|
||||
if (err) {
|
||||
Logger.tag('monitoring', 'mail-sending').error('Error sending monitoring mails:', err);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
run: MonitoringService.sendMonitoringMails,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,22 +1,8 @@
|
|||
import Logger from "../logger";
|
||||
import MonitoringService from "../services/monitoringService";
|
||||
import * as MonitoringService from "../services/monitoringService";
|
||||
|
||||
export default {
|
||||
name: 'NodeInformationRetrievalJob',
|
||||
description: 'Fetches the nodes.json and calculates and stores the monitoring / online status for registered nodes.',
|
||||
|
||||
run: (): Promise<void> => {
|
||||
return new Promise<void>(
|
||||
(resolve, reject) => {
|
||||
MonitoringService.retrieveNodeInformation((err: any): void => {
|
||||
if (err) {
|
||||
Logger.tag('monitoring', 'information-retrieval').error('Error retrieving node data:', err);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
run: MonitoringService.retrieveNodeInformation,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,20 +1,8 @@
|
|||
import MonitoringService from "../services/monitoringService";
|
||||
import Logger from "../logger";
|
||||
import * as MonitoringService from "../services/monitoringService";
|
||||
|
||||
export default {
|
||||
name: 'OfflineNodesDeletionJob',
|
||||
description: 'Delete nodes that are offline for more than 100 days.',
|
||||
|
||||
run: (): Promise<void> => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
MonitoringService.deleteOfflineNodes((err: any): void => {
|
||||
if (err) {
|
||||
Logger.tag('nodes', 'delete-offline').error('Error deleting offline nodes:', err);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
run: MonitoringService.deleteOfflineNodes,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const Constraints = require('../validation/constraints')
|
||||
const ErrorTypes = require('../utils/errorTypes')
|
||||
const Logger = require('../logger')
|
||||
const MailService = require('../services/mailService')
|
||||
const Resources = require('../utils/resources')
|
||||
const Strings = require('../utils/strings')
|
||||
const Validator = require('../validation/validator')
|
||||
|
||||
const isValidId = Validator.forConstraint(Constraints.id);
|
||||
|
||||
function withValidMailId(req, res, callback) {
|
||||
const id = Strings.normalizeString(Resources.getData(req).id);
|
||||
|
||||
if (!isValidId(id)) {
|
||||
return callback({data: 'Invalid mail id.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
callback(null, id);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get (req, res) {
|
||||
withValidMailId(req, res, function (err, id) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
MailService.getMail(id, function (err, mail) {
|
||||
if (err) {
|
||||
Logger.tag('mails', 'admin').error('Error getting mail:', err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
}
|
||||
|
||||
if (!mail) {
|
||||
return Resources.error(res, {data: 'Mail not found.', type: ErrorTypes.notFound});
|
||||
}
|
||||
|
||||
return Resources.success(res, mail);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getAll (req, res) {
|
||||
Resources.getValidRestParams('list', null, req, function (err, restParams) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
return MailService.getPendingMails(
|
||||
restParams,
|
||||
function (err, mails, total) {
|
||||
if (err) {
|
||||
Logger.tag('mails', 'admin').error('Could not get pending mails:', err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
}
|
||||
|
||||
res.set('X-Total-Count', total);
|
||||
return Resources.success(res, mails);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
delete (req, res) {
|
||||
withValidMailId(req, res, function (err, id) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
MailService.deleteMail(id, function (err) {
|
||||
if (err) {
|
||||
Logger.tag('mails', 'admin').error('Error deleting mail:', err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
}
|
||||
|
||||
return Resources.success(res);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
resetFailures (req, res) {
|
||||
withValidMailId(req, res, function (err, id) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
MailService.resetFailures(id, function (err, mail) {
|
||||
if (err) {
|
||||
Logger.tag('mails', 'admin').error('Error resetting failure count:', err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
}
|
||||
|
||||
return Resources.success(res, mail);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
67
server/resources/mailResource.ts
Normal file
67
server/resources/mailResource.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import CONSTRAINTS from "../validation/constraints";
|
||||
import ErrorTypes from "../utils/errorTypes";
|
||||
import * as MailService from "../services/mailService";
|
||||
import * as Resources from "../utils/resources";
|
||||
import {normalizeString} from "../utils/strings";
|
||||
import {forConstraint} from "../validation/validator";
|
||||
import {Request, Response} from "express";
|
||||
import {Mail, MailId} from "../types";
|
||||
|
||||
const isValidId = forConstraint(CONSTRAINTS.id, false);
|
||||
|
||||
async function withValidMailId(req: Request): Promise<MailId> {
|
||||
const id = normalizeString(Resources.getData(req).id);
|
||||
|
||||
if (!isValidId(id)) {
|
||||
throw {data: 'Invalid mail id.', type: ErrorTypes.badRequest};
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
async function doGet(req: Request): Promise<Mail> {
|
||||
const id = await withValidMailId(req);
|
||||
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[]}> {
|
||||
const restParams = await Resources.getValidRestParams('list', null, req);
|
||||
return await MailService.getPendingMails(restParams);
|
||||
}
|
||||
|
||||
export function getAll (req: Request, res: Response): void {
|
||||
doGetAll(req)
|
||||
.then(({total, mails}) => {
|
||||
res.set('X-Total-Count', total.toString(10));
|
||||
return Resources.success(res, mails);
|
||||
})
|
||||
.catch(err => Resources.error(res, err))
|
||||
}
|
||||
|
||||
async function doRemove(req: Request): Promise<void> {
|
||||
const id = await withValidMailId(req);
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const _ = require('lodash')
|
||||
|
||||
const Constraints = require('../validation/constraints')
|
||||
const ErrorTypes = require('../utils/errorTypes')
|
||||
const Logger = require('../logger')
|
||||
const MonitoringService = require('../services/monitoringService')
|
||||
const Resources = require('../utils/resources')
|
||||
const Strings = require('../utils/strings')
|
||||
const Validator = require('../validation/validator')
|
||||
|
||||
const isValidToken = Validator.forConstraint(Constraints.token);
|
||||
|
||||
module.exports = {
|
||||
getAll (req, res) {
|
||||
Resources.getValidRestParams('list', null, req, function (err, restParams) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
return MonitoringService.getAll(
|
||||
restParams,
|
||||
function (err, monitoringStates, total) {
|
||||
if (err) {
|
||||
Logger.tag('monitoring', 'admin').error('Could not get monitoring states:', err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
}
|
||||
|
||||
res.set('X-Total-Count', total);
|
||||
return Resources.success(res, _.map(monitoringStates, function (state) {
|
||||
state.mapId = _.toLower(state.mac).replace(/:/g, '');
|
||||
return state;
|
||||
}));
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
confirm (req, res) {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
const token = Strings.normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
return MonitoringService.confirm(token, function (err, node) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
return Resources.success(res, {
|
||||
hostname: node.hostname,
|
||||
mac: node.mac,
|
||||
email: node.email,
|
||||
monitoring: node.monitoring,
|
||||
monitoringConfirmed: node.monitoringConfirmed
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
disable (req, res) {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
const token = Strings.normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
return MonitoringService.disable(token, function (err, node) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
return Resources.success(res, {
|
||||
hostname: node.hostname,
|
||||
mac: node.mac,
|
||||
email: node.email,
|
||||
monitoring: node.monitoring
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
69
server/resources/monitoringResource.ts
Normal file
69
server/resources/monitoringResource.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import _ from "lodash";
|
||||
|
||||
import CONSTRAINTS from "../validation/constraints";
|
||||
import ErrorTypes from "../utils/errorTypes";
|
||||
import * as MonitoringService from "../services/monitoringService";
|
||||
import * as Resources from "../utils/resources";
|
||||
import {normalizeString} from "../utils/strings";
|
||||
import {forConstraint} from "../validation/validator";
|
||||
import {Request, Response} from "express";
|
||||
|
||||
const isValidToken = forConstraint(CONSTRAINTS.token, false);
|
||||
|
||||
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 {
|
||||
total,
|
||||
result: _.map(monitoringStates, function (state) {
|
||||
state.mapId = _.toLower(state.mac).replace(/:/g, '');
|
||||
return state;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
export function getAll(req: Request, res: Response): void {
|
||||
doGetAll(req)
|
||||
.then(({total, result}) => {
|
||||
res.set('X-Total-Count', total.toString(10));
|
||||
Resources.success(res, result)
|
||||
})
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
export function confirm(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});
|
||||
}
|
||||
|
||||
MonitoringService.confirm(token)
|
||||
.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 token = normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
MonitoringService.disable(token)
|
||||
.then(node => Resources.success(res, {
|
||||
hostname: node.hostname,
|
||||
mac: node.mac,
|
||||
email: node.email,
|
||||
monitoring: node.monitoring
|
||||
}))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const _ = require('lodash')
|
||||
const deepExtend = require('deep-extend')
|
||||
|
||||
const Constraints = require('../validation/constraints')
|
||||
const ErrorTypes = require('../utils/errorTypes')
|
||||
const Logger = require('../logger')
|
||||
const MonitoringService = require('../services/monitoringService')
|
||||
const NodeService = require('../services/nodeService')
|
||||
const Strings = require('../utils/strings')
|
||||
const Validator = require('../validation/validator')
|
||||
const Resources = require('../utils/resources')
|
||||
|
||||
const nodeFields = ['hostname', 'key', 'email', 'nickname', 'mac', 'coords', 'monitoring'];
|
||||
|
||||
function getNormalizedNodeData(reqData) {
|
||||
const node = {};
|
||||
_.each(nodeFields, function (field) {
|
||||
let value = Strings.normalizeString(reqData[field]);
|
||||
if (field === 'mac') {
|
||||
value = Strings.normalizeMac(value);
|
||||
}
|
||||
node[field] = value;
|
||||
});
|
||||
return node;
|
||||
}
|
||||
|
||||
const isValidNode = Validator.forConstraints(Constraints.node);
|
||||
const isValidToken = Validator.forConstraint(Constraints.token);
|
||||
|
||||
module.exports = {
|
||||
create: function (req, res) {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
const node = getNormalizedNodeData(data);
|
||||
if (!isValidNode(node)) {
|
||||
return Resources.error(res, {data: 'Invalid node data.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
return NodeService.createNode(node, function (err, token, node) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
return Resources.success(res, {token: token, node: node});
|
||||
});
|
||||
},
|
||||
|
||||
update: function (req, res) {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
const token = Strings.normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
const node = getNormalizedNodeData(data);
|
||||
if (!isValidNode(node)) {
|
||||
return Resources.error(res, {data: 'Invalid node data.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
return NodeService.updateNode(token, node, function (err, token, node) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
return Resources.success(res, {token: token, node: node});
|
||||
});
|
||||
},
|
||||
|
||||
delete: function (req, res) {
|
||||
const data = Resources.getData(req);
|
||||
|
||||
const token = Strings.normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
return NodeService.deleteNode(token, function (err) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
return Resources.success(res, {});
|
||||
});
|
||||
},
|
||||
|
||||
get: function (req, res) {
|
||||
const token = Strings.normalizeString(Resources.getData(req).token);
|
||||
if (!isValidToken(token)) {
|
||||
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
return NodeService.getNodeDataByToken(token, function (err, node) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
return Resources.success(res, node);
|
||||
});
|
||||
},
|
||||
|
||||
getAll: function (req, res) {
|
||||
Resources.getValidRestParams('list', 'node', req, function (err, restParams) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
return NodeService.getAllNodes(function (err, nodes) {
|
||||
if (err) {
|
||||
return Resources.error(res, err);
|
||||
}
|
||||
|
||||
const realNodes = _.filter(nodes, function (node) {
|
||||
// We ignore nodes without tokens as those are only manually added ones like gateways.
|
||||
return node.token;
|
||||
});
|
||||
|
||||
const macs = _.map(realNodes, function (node) {
|
||||
return node.mac;
|
||||
});
|
||||
|
||||
MonitoringService.getByMacs(macs, function (err, nodeStateByMac) {
|
||||
if (err) {
|
||||
Logger.tag('nodes', 'admin').error('Error getting nodes by MACs:', err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
}
|
||||
|
||||
const enhancedNodes = _.map(realNodes, function (node) {
|
||||
const nodeState = nodeStateByMac[node.mac];
|
||||
if (nodeState) {
|
||||
return deepExtend({}, node, {
|
||||
site: nodeState.site,
|
||||
domain: nodeState.domain,
|
||||
onlineState: nodeState.state
|
||||
});
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
const filteredNodes = Resources.filter(
|
||||
enhancedNodes,
|
||||
[
|
||||
'hostname',
|
||||
'nickname',
|
||||
'email',
|
||||
'token',
|
||||
'mac',
|
||||
'site',
|
||||
'domain',
|
||||
'key',
|
||||
'onlineState'
|
||||
],
|
||||
restParams
|
||||
);
|
||||
const total = filteredNodes.length;
|
||||
|
||||
const sortedNodes = Resources.sort(
|
||||
filteredNodes,
|
||||
[
|
||||
'hostname',
|
||||
'nickname',
|
||||
'email',
|
||||
'token',
|
||||
'mac',
|
||||
'key',
|
||||
'site',
|
||||
'domain',
|
||||
'coords',
|
||||
'onlineState',
|
||||
'monitoringState'
|
||||
],
|
||||
restParams
|
||||
);
|
||||
const pageNodes = Resources.getPageEntities(sortedNodes, restParams);
|
||||
|
||||
res.set('X-Total-Count', total);
|
||||
return Resources.success(res, pageNodes);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
160
server/resources/nodeResource.ts
Normal file
160
server/resources/nodeResource.ts
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
import _ from "lodash";
|
||||
import deepExtend from "deep-extend";
|
||||
|
||||
import Constraints from "../validation/constraints";
|
||||
import ErrorTypes from "../utils/errorTypes";
|
||||
import * as MonitoringService from "../services/monitoringService";
|
||||
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 {Entity} from "../utils/resources";
|
||||
import {Request, Response} from "express";
|
||||
import {Node} from "../types";
|
||||
|
||||
const nodeFields = ['hostname', 'key', 'email', 'nickname', 'mac', 'coords', 'monitoring'];
|
||||
|
||||
function getNormalizedNodeData(reqData: any): Node {
|
||||
const node: {[key: string]: any} = {};
|
||||
_.each(nodeFields, function (field) {
|
||||
let value = normalizeString(reqData[field]);
|
||||
if (field === 'mac') {
|
||||
value = normalizeMac(value);
|
||||
}
|
||||
node[field] = value;
|
||||
});
|
||||
return node as Node;
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
|
||||
const node = getNormalizedNodeData(data);
|
||||
if (!isValidNode(node)) {
|
||||
return Resources.error(res, {data: 'Invalid node data.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
NodeService.updateNode(token, node)
|
||||
.then(result => Resources.success(res, result))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
|
||||
NodeService.deleteNode(token)
|
||||
.then(() => Resources.success(res, {}))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
|
||||
NodeService.getNodeDataByToken(token)
|
||||
.then(node => Resources.success(res, node))
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
async function doGetAll(req: Request): Promise<{ total: number; pageNodes: any }> {
|
||||
const restParams = await Resources.getValidRestParams('list', 'node', req);
|
||||
|
||||
const nodes = await NodeService.getAllNodes();
|
||||
|
||||
const realNodes = _.filter(nodes, node =>
|
||||
// We ignore nodes without tokens as those are only manually added ones like gateways.
|
||||
!!node.token
|
||||
);
|
||||
|
||||
const macs = _.map(realNodes, (node: Node): string => node.mac);
|
||||
const nodeStateByMac = await MonitoringService.getByMacs(macs);
|
||||
|
||||
const enhancedNodes: Entity[] = _.map(realNodes, (node: Node) => {
|
||||
const nodeState = nodeStateByMac[node.mac];
|
||||
if (nodeState) {
|
||||
return deepExtend({}, node, {
|
||||
site: nodeState.site,
|
||||
domain: nodeState.domain,
|
||||
onlineState: nodeState.state
|
||||
});
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
const filteredNodes = Resources.filter(
|
||||
enhancedNodes,
|
||||
[
|
||||
'hostname',
|
||||
'nickname',
|
||||
'email',
|
||||
'token',
|
||||
'mac',
|
||||
'site',
|
||||
'domain',
|
||||
'key',
|
||||
'onlineState'
|
||||
],
|
||||
restParams
|
||||
);
|
||||
|
||||
const total = filteredNodes.length;
|
||||
|
||||
const sortedNodes = Resources.sort(
|
||||
filteredNodes,
|
||||
[
|
||||
'hostname',
|
||||
'nickname',
|
||||
'email',
|
||||
'token',
|
||||
'mac',
|
||||
'key',
|
||||
'site',
|
||||
'domain',
|
||||
'coords',
|
||||
'onlineState',
|
||||
'monitoringState'
|
||||
],
|
||||
restParams
|
||||
);
|
||||
const pageNodes = Resources.getPageEntities(sortedNodes, restParams);
|
||||
|
||||
return {total, pageNodes};
|
||||
}
|
||||
|
||||
export function getAll(req: Request, res: Response): void {
|
||||
doGetAll(req)
|
||||
.then((result: {total: number, pageNodes: any[]}) => {
|
||||
res.set('X-Total-Count', result.total.toString(10));
|
||||
return Resources.success(res, result.pageNodes);
|
||||
})
|
||||
.catch((err: any) => Resources.error(res, err));
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const ErrorTypes = require('../utils/errorTypes')
|
||||
const Logger = require('../logger')
|
||||
const NodeService = require('../services/nodeService')
|
||||
const Resources = require('../utils/resources')
|
||||
|
||||
module.exports = {
|
||||
get (req, res) {
|
||||
NodeService.getNodeStatistics((err, nodeStatistics) => {
|
||||
if (err) {
|
||||
Logger.tag('statistics').error('Error getting statistics:', err);
|
||||
return Resources.error(res, {data: 'Internal error.', type: ErrorTypes.internalError});
|
||||
}
|
||||
|
||||
return Resources.success(
|
||||
res,
|
||||
{
|
||||
nodes: nodeStatistics
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
20
server/resources/statisticsResource.ts
Normal file
20
server/resources/statisticsResource.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
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";
|
||||
|
||||
export function get (req: Request, res: Response): void {
|
||||
// TODO: Promises and types.
|
||||
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});
|
||||
});
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import {getTasks, Task} from "../jobs/scheduler";
|
|||
import {normalizeString} from "../utils/strings";
|
||||
import {forConstraint} from "../validation/validator";
|
||||
import {Request, Response} from "express";
|
||||
import {Entity} from "../utils/resources";
|
||||
|
||||
const isValidId = forConstraint(CONSTRAINTS.id, false);
|
||||
|
||||
|
|
@ -71,39 +72,36 @@ function setTaskEnabled(req: Request, res: Response, enable: boolean) {
|
|||
.catch(err => Resources.error(res, err))
|
||||
}
|
||||
|
||||
async function doGetAll(req: Request): Promise<{total: number, pageTasks: Entity[]}> {
|
||||
const restParams = await Resources.getValidRestParams('list', null, req);
|
||||
|
||||
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);
|
||||
|
||||
return {
|
||||
total,
|
||||
pageTasks,
|
||||
};
|
||||
}
|
||||
|
||||
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));
|
||||
});
|
||||
doGetAll(req)
|
||||
.then(({total, pageTasks}) => {
|
||||
res.set('X-Total-Count', total.toString(10));
|
||||
Resources.success(res, _.map(pageTasks, toExternalTask));
|
||||
})
|
||||
.catch(err => Resources.error(res, err));
|
||||
}
|
||||
|
||||
export function run (req: Request, res: Response): void {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import app from "./app"
|
|||
import {config} from "./config"
|
||||
|
||||
import * as VersionResource from "./resources/versionResource"
|
||||
import StatisticsResource from "./resources/statisticsResource"
|
||||
import * as StatisticsResource from "./resources/statisticsResource"
|
||||
import * as FrontendResource from "./resources/frontendResource"
|
||||
import NodeResource from "./resources/nodeResource"
|
||||
import MonitoringResource from "./resources/monitoringResource"
|
||||
import * as NodeResource from "./resources/nodeResource"
|
||||
import * as MonitoringResource from "./resources/monitoringResource"
|
||||
import * as TaskResource from "./resources/taskResource"
|
||||
import MailResource from "./resources/mailResource"
|
||||
import * as MailResource from "./resources/mailResource"
|
||||
|
||||
export function init (): void {
|
||||
const router = express.Router();
|
||||
|
|
@ -20,7 +20,7 @@ export function init (): void {
|
|||
|
||||
router.post('/api/node', NodeResource.create);
|
||||
router.put('/api/node/:token', NodeResource.update);
|
||||
router.delete('/api/node/:token', NodeResource.delete);
|
||||
router.delete('/api/node/:token', NodeResource.remove);
|
||||
router.get('/api/node/:token', NodeResource.get);
|
||||
|
||||
router.put('/api/monitoring/confirm/:token', MonitoringResource.confirm);
|
||||
|
|
@ -37,11 +37,11 @@ export function init (): void {
|
|||
|
||||
router.get('/internal/api/mails', MailResource.getAll);
|
||||
router.get('/internal/api/mails/:id', MailResource.get);
|
||||
router.delete('/internal/api/mails/:id', MailResource.delete);
|
||||
router.delete('/internal/api/mails/:id', MailResource.remove);
|
||||
router.put('/internal/api/mails/reset/:id', MailResource.resetFailures);
|
||||
|
||||
router.put('/internal/api/nodes/:token', NodeResource.update);
|
||||
router.delete('/internal/api/nodes/:token', NodeResource.delete);
|
||||
router.delete('/internal/api/nodes/:token', NodeResource.remove);
|
||||
router.get('/internal/api/nodes', NodeResource.getAll);
|
||||
router.get('/internal/api/nodes/:token', NodeResource.get);
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue