ESLint: Fix more warnings and errors.

This commit is contained in:
baldo 2022-08-23 21:38:37 +02:00
parent 66fb4e5004
commit bfd6ca1d26
9 changed files with 84 additions and 56 deletions

View file

@ -10,6 +10,7 @@ import { Request, Response } from "express";
import { import {
CreateOrUpdateNode, CreateOrUpdateNode,
DomainSpecificNodeResponse, DomainSpecificNodeResponse,
filterUndefinedFromJSON,
isCreateOrUpdateNode, isCreateOrUpdateNode,
isNodeSortField, isNodeSortField,
isString, isString,
@ -108,7 +109,7 @@ export const get = handleJSONWithData<NodeResponse>(async (data) => {
async function doGetAll( async function doGetAll(
req: Request req: Request
): Promise<{ total: number; pageNodes: any }> { ): Promise<{ total: number; pageNodes: DomainSpecificNodeResponse[] }> {
const restParams = await Resources.getValidRestParams("list", "node", req); const restParams = await Resources.getValidRestParams("list", "node", req);
const nodes = await NodeService.getAllNodes(); const nodes = await NodeService.getAllNodes();
@ -159,9 +160,17 @@ async function doGetAll(
export function getAll(req: Request, res: Response): void { export function getAll(req: Request, res: Response): void {
doGetAll(req) doGetAll(req)
.then((result: { total: number; pageNodes: any[] }) => { .then(
res.set("X-Total-Count", result.total.toString(10)); (result: {
return Resources.success(res, result.pageNodes); total: number;
}) pageNodes: DomainSpecificNodeResponse[];
.catch((err: any) => Resources.error(res, err)); }) => {
res.set("X-Total-Count", result.total.toString(10));
return Resources.success(
res,
result.pageNodes.map(filterUndefinedFromJSON)
);
}
)
.catch((err) => Resources.error(res, err));
} }

View file

@ -196,21 +196,23 @@ export async function sendPendingMails(): Promise<void> {
const startTime = moment(); const startTime = moment();
while (true) { let pendingMails = await findPendingMailsBefore(
startTime,
MAIL_QUEUE_DB_BATCH_SIZE
);
while (!_.isEmpty(pendingMails)) {
Logger.tag("mail", "queue").debug("Sending next batch..."); Logger.tag("mail", "queue").debug("Sending next batch...");
const pendingMails = await findPendingMailsBefore(
startTime,
MAIL_QUEUE_DB_BATCH_SIZE
);
if (_.isEmpty(pendingMails)) {
Logger.tag("mail", "queue").debug("Done sending pending mails.");
return;
}
for (const pendingMail of pendingMails) { for (const pendingMail of pendingMails) {
await sendPendingMail(pendingMail); await sendPendingMail(pendingMail);
} }
pendingMails = await findPendingMailsBefore(
startTime,
MAIL_QUEUE_DB_BATCH_SIZE
);
} }
Logger.tag("mail", "queue").debug("Done sending pending mails.");
} }

View file

@ -21,6 +21,7 @@ const templateFunctions: {
| ((unix: number) => string); | ((unix: number) => string);
} = {}; } = {};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function renderSnippet(this: any, name: string, data: MailData): string { function renderSnippet(this: any, name: string, data: MailData): string {
const snippetFile = snippetsBasePath + "/" + name + ".html"; const snippetFile = snippetsBasePath + "/" + name + ".html";
@ -34,7 +35,9 @@ function renderSnippet(this: any, name: string, data: MailData): string {
); );
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function snippet(name: string): (this: any, data: MailData) => string { function snippet(name: string): (this: any, data: MailData) => string {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return function (this: any, data: MailData): string { return function (this: any, data: MailData): string {
return renderSnippet.bind(this)(name, data); return renderSnippet.bind(this)(name, data);
}; };

View file

@ -25,15 +25,6 @@ beforeEach(() => {
mockedLogger.reset(); mockedLogger.reset();
}); });
test("parseNode() should fail parsing node for undefined node data", () => {
// given
const importTimestamp = now();
const nodeData = undefined;
// then
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
});
test("parseNode() should fail parsing node for empty node data", () => { test("parseNode() should fail parsing node for empty node data", () => {
// given // given
const importTimestamp = now(); const importTimestamp = now();

View file

@ -24,9 +24,11 @@ import {
isDomain, isDomain,
isMonitoringSortField, isMonitoringSortField,
isOnlineState, isOnlineState,
isPlainObject,
isSite, isSite,
isString, isString,
isUndefined, isUndefined,
JSONValue,
MAC, MAC,
MailType, MailType,
MonitoringSortField, MonitoringSortField,
@ -35,6 +37,7 @@ import {
NodeId, NodeId,
NodeStateData, NodeStateData,
OnlineState, OnlineState,
parseJSON,
RunResult, RunResult,
Site, Site,
StoredNode, StoredNode,
@ -206,13 +209,13 @@ const isValidMac = forConstraint(CONSTRAINTS.node.mac, false);
export function parseNode( export function parseNode(
importTimestamp: UnixTimestampSeconds, importTimestamp: UnixTimestampSeconds,
nodeData: any nodeData: JSONValue
): ParsedNode { ): ParsedNode {
if (!_.isPlainObject(nodeData)) { if (!isPlainObject(nodeData)) {
throw new Error("Unexpected node type: " + typeof nodeData); throw new Error("Unexpected node type: " + typeof nodeData);
} }
if (!_.isPlainObject(nodeData.nodeinfo)) { if (!isPlainObject(nodeData.nodeinfo)) {
throw new Error( throw new Error(
"Unexpected nodeinfo type: " + typeof nodeData.nodeinfo "Unexpected nodeinfo type: " + typeof nodeData.nodeinfo
); );
@ -225,7 +228,7 @@ export function parseNode(
); );
} }
if (!_.isPlainObject(nodeData.nodeinfo.network)) { if (!isPlainObject(nodeData.nodeinfo.network)) {
throw new Error( throw new Error(
"Node " + "Node " +
nodeId + nodeId +
@ -239,9 +242,9 @@ export function parseNode(
"Node " + nodeId + ": Invalid MAC: " + nodeData.nodeinfo.network.mac "Node " + nodeId + ": Invalid MAC: " + nodeData.nodeinfo.network.mac
); );
} }
const mac = normalizeMac(nodeData.nodeinfo.network.mac) as MAC; const mac = normalizeMac(nodeData.nodeinfo.network.mac as MAC);
if (!_.isPlainObject(nodeData.flags)) { if (!isPlainObject(nodeData.flags)) {
throw new Error( throw new Error(
"Node " + "Node " +
nodeId + nodeId +
@ -271,7 +274,7 @@ export function parseNode(
let site: Site | undefined; let site: Site | undefined;
if ( if (
_.isPlainObject(nodeData.nodeinfo.system) && isPlainObject(nodeData.nodeinfo.system) &&
isSite(nodeData.nodeinfo.system.site_code) isSite(nodeData.nodeinfo.system.site_code)
) { ) {
site = nodeData.nodeinfo.system.site_code; site = nodeData.nodeinfo.system.site_code;
@ -279,7 +282,7 @@ export function parseNode(
let domain: Domain | undefined; let domain: Domain | undefined;
if ( if (
_.isPlainObject(nodeData.nodeinfo.system) && isPlainObject(nodeData.nodeinfo.system) &&
isDomain(nodeData.nodeinfo.system.domain_code) isDomain(nodeData.nodeinfo.system.domain_code)
) { ) {
domain = nodeData.nodeinfo.system.domain_code; domain = nodeData.nodeinfo.system.domain_code;
@ -300,9 +303,9 @@ export function parseNodesJson(body: string): NodesParsingResult {
"Parsing nodes.json..." "Parsing nodes.json..."
); );
const json = JSON.parse(body); const json = parseJSON(body);
if (!_.isPlainObject(json)) { if (!isPlainObject(json)) {
throw new Error( throw new Error(
`Expecting a JSON object as the nodes.json root, but got: ${typeof json}` `Expecting a JSON object as the nodes.json root, but got: ${typeof json}`
); );

View file

@ -405,7 +405,7 @@ function setNodeValue(
case LINE_PREFIX.TOKEN: case LINE_PREFIX.TOKEN:
node.token = value as Token; node.token = value as Token;
break; break;
case LINE_PREFIX.MONITORING: case LINE_PREFIX.MONITORING: {
const active = value === "aktiv"; const active = value === "aktiv";
const pending = value === "pending"; const pending = value === "pending";
node.monitoringState = active node.monitoringState = active
@ -414,6 +414,7 @@ function setNodeValue(
? MonitoringState.PENDING ? MonitoringState.PENDING
: MonitoringState.DISABLED; : MonitoringState.DISABLED;
break; break;
}
case LINE_PREFIX.MONITORING_TOKEN: case LINE_PREFIX.MONITORING_TOKEN:
nodeSecrets.monitoringToken = value as MonitoringToken; nodeSecrets.monitoringToken = value as MonitoringToken;
break; break;

View file

@ -77,6 +77,10 @@ export function isObject(arg: unknown): arg is object {
return arg !== null && typeof arg === "object"; return arg !== null && typeof arg === "object";
} }
export function isPlainObject(arg: unknown): arg is { [key: string]: unknown } {
return isObject(arg) && !Array.isArray(arg);
}
export function hasOwnProperty<Key extends PropertyKey>( export function hasOwnProperty<Key extends PropertyKey>(
arg: unknown, arg: unknown,
key: Key key: Key
@ -84,6 +88,13 @@ export function hasOwnProperty<Key extends PropertyKey>(
return isObject(arg) && key in arg; return isObject(arg) && key in arg;
} }
export function getFieldIfExists(
arg: unknown,
key: PropertyKey
): unknown | undefined {
return hasOwnProperty(arg, key) ? arg[key] : undefined;
}
export function isArray<T>(arg: unknown, isT: TypeGuard<T>): arg is Array<T> { export function isArray<T>(arg: unknown, isT: TypeGuard<T>): arg is Array<T> {
if (!Array.isArray(arg)) { if (!Array.isArray(arg)) {
return false; return false;

View file

@ -25,6 +25,9 @@ export interface Constraint {
} }
export type Constraints = { [key: string]: Constraint }; export type Constraints = { [key: string]: Constraint };
export type NestedConstraints = {
[key: string]: Constraint | Constraints | NestedConstraints;
};
export type Values = { [key: string]: unknown }; export type Values = { [key: string]: unknown };
export function isConstraint(arg: unknown): arg is Constraint { export function isConstraint(arg: unknown): arg is Constraint {

View file

@ -7,12 +7,14 @@ import {
Constraints, Constraints,
forConstraints, forConstraints,
isConstraints, isConstraints,
NestedConstraints,
} from "../shared/validation/validator"; } from "../shared/validation/validator";
import { Request, Response } from "express"; import { Request, Response } from "express";
import { import {
EnumTypeGuard, EnumTypeGuard,
EnumValue, EnumValue,
type GenericSortField, type GenericSortField,
getFieldIfExists,
isJSONObject, isJSONObject,
isNumber, isNumber,
isString, isString,
@ -26,7 +28,7 @@ import {
export type RequestData = JSONObject; export type RequestData = JSONObject;
export type RequestHandler = (request: Request, response: Response) => void; export type RequestHandler = (request: Request, response: Response) => void;
export type Entity = { [key: string]: any }; export type Entity = { [key: string]: unknown };
export type RestParams = { export type RestParams = {
q?: string; q?: string;
@ -180,7 +182,7 @@ export async function getValidRestParams(
subtype: string | null, subtype: string | null,
req: Request req: Request
): Promise<RestParams> { ): Promise<RestParams> {
const restConstraints = CONSTRAINTS.rest as { [key: string]: any }; const restConstraints = CONSTRAINTS.rest as { [key: string]: Constraints };
if (!(type in restConstraints) || !isConstraints(restConstraints[type])) { if (!(type in restConstraints) || !isConstraints(restConstraints[type])) {
Logger.tag("validation", "rest").error( Logger.tag("validation", "rest").error(
"Unknown REST resource type: {}", "Unknown REST resource type: {}",
@ -193,18 +195,16 @@ export async function getValidRestParams(
let filterConstraints: Constraints = {}; let filterConstraints: Constraints = {};
if (subtype) { if (subtype) {
const subtypeFilters = subtype + "Filters"; const subtypeFilters = subtype + "Filters";
const constraintsObj = CONSTRAINTS as { [key: string]: any }; const nestedConstraints = CONSTRAINTS as NestedConstraints;
if ( const subConstraints = nestedConstraints[subtypeFilters];
!(subtypeFilters in constraintsObj) || if (!isConstraints(subConstraints)) {
!isConstraints(constraintsObj[subtypeFilters])
) {
Logger.tag("validation", "rest").error( Logger.tag("validation", "rest").error(
"Unknown REST resource subtype: {}", "Unknown REST resource subtype: {}",
subtype subtype
); );
throw { data: "Internal error.", type: ErrorTypes.internalError }; throw { data: "Internal error.", type: ErrorTypes.internalError };
} }
filterConstraints = constraintsObj[subtypeFilters]; filterConstraints = subConstraints;
} }
const data = getData(req); const data = getData(req);
@ -232,7 +232,7 @@ export function filter<E>(
query = query.trim().toLowerCase(); query = query.trim().toLowerCase();
} }
function queryMatches(entity: Entity): boolean { function queryMatches(entity: E): boolean {
if (!query) { if (!query) {
return true; return true;
} }
@ -240,7 +240,7 @@ export function filter<E>(
if (!query) { if (!query) {
return true; return true;
} }
let value = entity[field]; let value = getFieldIfExists(entity, field);
if (isNumber(value)) { if (isNumber(value)) {
value = value.toString(); value = value.toString();
} }
@ -249,21 +249,21 @@ export function filter<E>(
return false; return false;
} }
value = value.toLowerCase(); const lowerCaseValue = value.toLowerCase();
if (field === "mac") { if (field === "mac") {
return _.includes( return _.includes(
value.replace(/:/g, ""), lowerCaseValue.replace(/:/g, ""),
query.replace(/:/g, "") query.replace(/:/g, "")
); );
} }
return _.includes(value, query); return _.includes(lowerCaseValue, query);
}); });
} }
const filters = restParams.filters; const filters = restParams.filters;
function filtersMatch(entity: Entity): boolean { function filtersMatch(entity: E): boolean {
if (isUndefined(filters) || _.isEmpty(filters)) { if (isUndefined(filters) || _.isEmpty(filters)) {
return true; return true;
} }
@ -275,9 +275,13 @@ export function filter<E>(
if (key.startsWith("has")) { if (key.startsWith("has")) {
const entityKey = const entityKey =
key.substring(3, 4).toLowerCase() + key.substring(4); key.substring(3, 4).toLowerCase() + key.substring(4);
return _.isEmpty(entity[entityKey]).toString() !== value; return (
_.isEmpty(
getFieldIfExists(entity, entityKey)
).toString() !== value
);
} }
return entity[key] === value; return getFieldIfExists(entity, key) === value;
}); });
} }
@ -287,7 +291,8 @@ export function filter<E>(
} }
export function sort< export function sort<
Type extends { [Key in SortField]: unknown }, // eslint-disable-next-line @typescript-eslint/no-explicit-any
Type extends { [Key in SortField]: any },
SortField extends string SortField extends string
>( >(
entities: Type[], entities: Type[],
@ -303,8 +308,8 @@ export function sort<
const sorted = entities.slice(0); const sorted = entities.slice(0);
sorted.sort((a, b) => { sorted.sort((a, b) => {
let as: any = a[sortField]; let as = a[sortField];
let bs: any = b[sortField]; let bs = b[sortField];
if (isString(as)) { if (isString(as)) {
as = as.toLowerCase(); as = as.toLowerCase();