Merge branch 'main' into new-admin
This commit is contained in:
commit
0bbb2113e9
7 changed files with 116 additions and 64 deletions
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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<RunResult> {
|
||||
return await db.run(
|
||||
|
@ -370,7 +377,7 @@ async function updateSkippedNode(
|
|||
async function sendMonitoringMailsBatched(
|
||||
name: string,
|
||||
mailType: MailType,
|
||||
findBatchFun: () => Promise<any[]>
|
||||
findBatchFun: () => Promise<NodeStateRow[]>
|
||||
): Promise<void> {
|
||||
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<any[]> =>
|
||||
await db.all(
|
||||
async (): Promise<NodeStateRow[]> =>
|
||||
await db.all<NodeStateRow>(
|
||||
"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<any[]> => {
|
||||
async (): Promise<NodeStateRow[]> => {
|
||||
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<NodeStateRow>(
|
||||
"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<NodeStateRow>(
|
||||
"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<NodeStateRow>(
|
||||
`SELECT * FROM node_state WHERE mac IN (${placeholders})`,
|
||||
macs
|
||||
);
|
||||
|
|
|
@ -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
|
||||
export enum NodeSortFieldEnum {
|
||||
HOSTNAME = "hostname",
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
24
yarn.lock
24
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"
|
||||
|
|
Loading…
Reference in a new issue