From e17fa4ed73bf92db44a9f5668b31020f7cf01b28 Mon Sep 17 00:00:00 2001 From: baldo Date: Wed, 24 Aug 2022 17:12:00 +0200 Subject: [PATCH 1/3] Update server dependencies. --- package.json | 6 +++--- yarn.lock | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index f49eb04..348a5de 100644 --- a/package.json +++ b/package.json @@ -67,10 +67,10 @@ "@types/express": "^4.17.13", "@types/glob": "^7.2.0", "@types/graceful-fs": "^4.1.5", - "@types/html-to-text": "^8.0.1", - "@types/jest": "^28.1.7", + "@types/html-to-text": "^8.1.1", + "@types/jest": "^28.1.8", "@types/lodash": "^4.14.184", - "@types/node": "^18.7.11", + "@types/node": "^18.7.13", "@types/node-cron": "^3.0.2", "@types/nodemailer": "^6.4.5", "@types/request": "^2.48.8", diff --git a/yarn.lock b/yarn.lock index acdc0d1..a6c7056 100644 --- a/yarn.lock +++ b/yarn.lock @@ -910,10 +910,10 @@ dependencies: "@types/node" "*" -"@types/html-to-text@^8.0.1": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@types/html-to-text/-/html-to-text-8.1.0.tgz#dad0bf5d199f7e3f67eae50a36c13eadb1b56d1b" - integrity sha512-54YF2fGmN4g62/w+T85uQ8n0FyBhMY5cjKZ1imsbIh4Pgbeno1mAaQktC/pv/+C2ToUYkTZis9ADgn9GRRz9nQ== +"@types/html-to-text@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/html-to-text/-/html-to-text-8.1.1.tgz#0c5573207c14f618f24da5a2910c510285573094" + integrity sha512-QFcqfc7TiVbvIX8Fc2kWUxakruI1Ay6uitaGCYHzI5M0WHQROV5D2XeSaVrK0FmvssivXum4yERVnJsiuH61Ww== "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" @@ -934,10 +934,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^28.1.7": - version "28.1.7" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.7.tgz#a680c5d05b69634c2d54a63cb106d7fb1adaba16" - integrity sha512-acDN4VHD40V24tgu0iC44jchXavRNVFXQ/E6Z5XNsswgoSO/4NgsXoEYmPUGookKldlZQyIpmrEXsHI9cA3ZTA== +"@types/jest@^28.1.8": + version "28.1.8" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.8.tgz#6936409f3c9724ea431efd412ea0238a0f03b09b" + integrity sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw== dependencies: expect "^28.0.0" pretty-format "^28.0.0" @@ -984,10 +984,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.34.tgz#3b0b6a50ff797280b8d000c6281d229f9c538cef" integrity sha512-XImEz7XwTvDBtzlTnm8YvMqGW/ErMWBsKZ+hMTvnDIjGCKxwK5Xpc+c/oQjOauwq8M4OS11hEkpjX8rrI/eEgA== -"@types/node@^18.7.11": - version "18.7.11" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.11.tgz#486e72cfccde88da24e1f23ff1b7d8bfb64e6250" - integrity sha512-KZhFpSLlmK/sdocfSAjqPETTMd0ug6HIMIAwkwUpU79olnZdQtMxpQP+G1wDzCH7na+FltSIhbaZuKdwZ8RDrw== +"@types/node@^18.7.13": + version "18.7.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.13.tgz#23e6c5168333480d454243378b69e861ab5c011a" + integrity sha512-46yIhxSe5xEaJZXWdIBP7GU4HDTG8/eo0qd9atdiL+lFpA03y8KS+lkTN834TWJj5767GbWv4n/P6efyTFt1Dw== "@types/nodemailer@^6.4.5": version "6.4.5" From 672369d41929ba58f4eed3177c75b1a2787c78b5 Mon Sep 17 00:00:00 2001 From: baldo Date: Wed, 24 Aug 2022 17:32:36 +0200 Subject: [PATCH 2/3] Fix: Sorting nodes did not work. --- server/utils/resources.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/utils/resources.ts b/server/utils/resources.ts index c57e945..218c939 100644 --- a/server/utils/resources.ts +++ b/server/utils/resources.ts @@ -321,7 +321,7 @@ export function sort< let order = 0; if (as < bs) { order = -1; - } else if (bs > as) { + } else if (as > bs) { order = 1; } From 00d93c33b402295c21af3f823d552e7a8af648ad Mon Sep 17 00:00:00 2001 From: baldo Date: Wed, 24 Aug 2022 18:20:49 +0200 Subject: [PATCH 3/3] Introduce NodeMonitoringStateResponse to get rid of some any --- server/resources/monitoringResource.ts | 11 +++-- server/services/monitoringService.ts | 59 ++++++++++++++++++++------ server/shared/types/index.ts | 49 +++++++++++++++++++++ server/types/index.ts | 29 ------------- 4 files changed, 100 insertions(+), 48 deletions(-) diff --git a/server/resources/monitoringResource.ts b/server/resources/monitoringResource.ts index 467b168..e81ec55 100644 --- a/server/resources/monitoringResource.ts +++ b/server/resources/monitoringResource.ts @@ -11,23 +11,22 @@ import { JSONObject, MonitoringResponse, MonitoringToken, + NodeMonitoringStateResponse, toMonitoringResponse, } from "../types"; const isValidToken = forConstraint(CONSTRAINTS.token, false); -// FIXME: Get rid of any -async function doGetAll(req: Request): Promise<{ total: number; result: any }> { +async function doGetAll( + req: Request +): Promise<{ total: number; result: NodeMonitoringStateResponse[] }> { const restParams = await Resources.getValidRestParams("list", null, req); const { monitoringStates, total } = await MonitoringService.getAll( restParams ); return { total, - result: monitoringStates.map((state) => { - state.mapId = state.mac.toLowerCase().replace(/:/g, ""); - return state; - }), + result: monitoringStates, }; } diff --git a/server/services/monitoringService.ts b/server/services/monitoringService.ts index ef6bb56..6fddf29 100644 --- a/server/services/monitoringService.ts +++ b/server/services/monitoringService.ts @@ -22,7 +22,9 @@ import { Hostname, isBoolean, isDomain, + isMailType, isMonitoringSortField, + isMonitoringState, isOnlineState, isPlainObject, isSite, @@ -30,12 +32,17 @@ import { isUndefined, JSONValue, MAC, + MailId, MailType, + MapId, + mapIdFromMAC, MonitoringSortField, MonitoringState, MonitoringToken, NodeId, + NodeMonitoringStateResponse, NodeStateData, + NodeStateId, OnlineState, parseJSON, RunResult, @@ -55,13 +62,13 @@ import { } from "../utils/time"; type NodeStateRow = { - id: number; + id: NodeStateId; created_at: UnixTimestampSeconds; domain: Domain | null; hostname: Hostname | null; import_timestamp: UnixTimestampSeconds; last_seen: UnixTimestampSeconds; - last_status_mail_sent: string | null; + last_status_mail_sent: UnixTimestampSeconds | null; last_status_mail_type: string | null; mac: MAC; modified_at: UnixTimestampSeconds; @@ -356,7 +363,7 @@ export function parseNodesJson(body: string): NodesParsingResult { } async function updateSkippedNode( - id: NodeId, + id: NodeStateId, node?: StoredNode ): Promise { return await db.run( @@ -370,7 +377,7 @@ async function updateSkippedNode( async function sendMonitoringMailsBatched( name: string, mailType: MailType, - findBatchFun: () => Promise + findBatchFun: () => Promise ): Promise { Logger.tag("monitoring", "mail-sending").debug( 'Sending "%s" mails...', @@ -477,8 +484,8 @@ async function sendOnlineAgainMails( await sendMonitoringMailsBatched( "online again", MailType.MONITORING_ONLINE_AGAIN, - async (): Promise => - await db.all( + async (): Promise => + await db.all( "SELECT * FROM node_state " + "WHERE modified_at < ? AND state = ? AND last_status_mail_type IN (" + "'monitoring-offline-1', 'monitoring-offline-2', 'monitoring-offline-3'" + @@ -497,7 +504,7 @@ async function sendOfflineMails( await sendMonitoringMailsBatched( "offline " + mailNumber, mailType, - async (): Promise => { + async (): Promise => { const previousType = mailNumber === 1 ? "monitoring-online-again" @@ -510,7 +517,7 @@ async function sendOfflineMails( const schedule = MONITORING_OFFLINE_MAILS_SCHEDULE[mailNumber]; const scheduledTimeBefore = subtract(now(), schedule); - return await db.all( + return await db.all( "SELECT * FROM node_state " + "WHERE modified_at < ? AND state = ? AND (last_status_mail_type = ?" + allowNull + @@ -667,10 +674,33 @@ async function retrieveNodeInformationForUrls( }; } -// FIXME: Replace any[] by type. +function toResponse(row: NodeStateRow): NodeMonitoringStateResponse { + // TODO: Handle conversion errors. + return { + id: row.id, + created_at: row.created_at, + domain: row.domain || undefined, + hostname: row.hostname || undefined, + import_timestamp: row.import_timestamp, + last_seen: row.last_seen, + last_status_mail_sent: row.last_status_mail_sent || undefined, + last_status_mail_type: isMailType(row.last_status_mail_type) + ? row.last_status_mail_type + : undefined, + mac: row.mac, + modified_at: row.modified_at, + monitoring_state: isMonitoringState(row.monitoring_state) + ? row.monitoring_state + : undefined, + site: row.site || undefined, + state: isOnlineState(row.state) ? row.state : OnlineState.OFFLINE, + mapId: mapIdFromMAC(row.mac), + }; +} + export async function getAll( restParams: RestParams -): Promise<{ total: number; monitoringStates: any[] }> { +): Promise<{ total: number; monitoringStates: NodeMonitoringStateResponse[] }> { const filterFields = [ "hostname", "mac", @@ -695,12 +725,15 @@ export async function getAll( filterFields ); - const monitoringStates = await db.all( + const monitoringStates = await db.all( "SELECT * FROM node_state WHERE " + filter.query, filter.params ); - return { monitoringStates, total }; + return { + monitoringStates: monitoringStates.map(toResponse), + total, + }; } export async function getByMacs( @@ -877,7 +910,7 @@ async function deleteNeverOnlineNodesBefore( const placeholders = macs.map(() => "?").join(","); - const rows: { mac: MAC }[] = await db.all( + const rows = await db.all( `SELECT * FROM node_state WHERE mac IN (${placeholders})`, macs ); diff --git a/server/shared/types/index.ts b/server/shared/types/index.ts index 1b06342..0421aad 100644 --- a/server/shared/types/index.ts +++ b/server/shared/types/index.ts @@ -368,6 +368,12 @@ export const isFastdKey = toIsNewtype(isString, "" as FastdKey); export type MAC = string & { readonly __tag: unique symbol }; export const isMAC = toIsNewtype(isString, "" as MAC); +export type MapId = string & { readonly __tag: unique symbol }; +export const isMapId = toIsNewtype(isString, "" as MapId); +export function mapIdFromMAC(mac: MAC): MapId { + return mac.toLowerCase().replace(/:/g, "") as MapId; +} + export type DurationSeconds = number & { readonly __tag: unique symbol }; export const isDurationSeconds = toIsNewtype(isNumber, NaN as DurationSeconds); @@ -572,6 +578,49 @@ export function isMonitoringResponse(arg: unknown): arg is MonitoringResponse { ); } +export type NodeStateId = number & { readonly __tag: unique symbol }; +export const isNodeStateId = toIsNewtype(isNumber, 0 as NodeStateId); + +export type NodeMonitoringStateResponse = { + id: NodeStateId; + created_at: UnixTimestampSeconds; + domain?: Domain; + hostname?: Hostname; + import_timestamp: UnixTimestampSeconds; + last_seen: UnixTimestampSeconds; + last_status_mail_sent?: UnixTimestampSeconds; + last_status_mail_type?: MailType; + mac: MAC; + modified_at: UnixTimestampSeconds; + monitoring_state?: MonitoringState; + site?: Site; + state: OnlineState; + mapId: MapId; +}; + +export type MailId = number & { readonly __tag: unique symbol }; +export const isMailId = toIsNewtype(isNumber, NaN as MailId); + +export type MailData = JSONObject; + +export enum MailType { + MONITORING_OFFLINE_1 = "monitoring-offline-1", + MONITORING_OFFLINE_2 = "monitoring-offline-2", + MONITORING_OFFLINE_3 = "monitoring-offline-3", + MONITORING_ONLINE_AGAIN = "monitoring-online-again", + MONITORING_CONFIRMATION = "monitoring-confirmation", +} +export const isMailType = toIsEnum(MailType); + +export type Mail = { + id: MailId; + email: MailType; + sender: EmailAddress; + recipient: EmailAddress; + data: MailData; + failures: number; +}; + // noinspection JSUnusedGlobalSymbols enum NodeSortFieldEnum { HOSTNAME = "hostname", diff --git a/server/types/index.ts b/server/types/index.ts index 98375e0..cba4a55 100644 --- a/server/types/index.ts +++ b/server/types/index.ts @@ -2,9 +2,6 @@ import { CreateOrUpdateNode, Domain, DomainSpecificNodeResponse, - EmailAddress, - isNumber, - JSONObject, MonitoringResponse, MonitoringState, MonitoringToken, @@ -13,8 +10,6 @@ import { OnlineState, Site, StoredNode, - toIsEnum, - toIsNewtype, } from "../shared/types"; export * from "./config"; @@ -98,27 +93,3 @@ export function toMonitoringResponse(node: StoredNode): MonitoringResponse { export type NodeSecrets = { monitoringToken?: MonitoringToken; }; - -export type MailId = number & { readonly __tag: unique symbol }; -export const isMailId = toIsNewtype(isNumber, NaN as MailId); - -export type MailData = JSONObject; - -export enum MailType { - MONITORING_OFFLINE_1 = "monitoring-offline-1", - MONITORING_OFFLINE_2 = "monitoring-offline-2", - MONITORING_OFFLINE_3 = "monitoring-offline-3", - MONITORING_ONLINE_AGAIN = "monitoring-online-again", - MONITORING_CONFIRMATION = "monitoring-confirmation", -} - -export const isMailType = toIsEnum(MailType); - -export type Mail = { - id: MailId; - email: MailType; - sender: EmailAddress; - recipient: EmailAddress; - data: MailData; - failures: number; -};