check, monitor, maintenance

This commit is contained in:
Alex Holliday
2026-03-02 17:46:33 +00:00
parent a5d3c95145
commit b997c43bd5
5 changed files with 181 additions and 175 deletions
@@ -25,7 +25,7 @@ class MaintenanceWindowController {
createMaintenanceWindows = async (req: Request, res: Response, next: NextFunction) => {
try {
await createMaintenanceWindowBodyValidation.validateAsync(req.body);
createMaintenanceWindowBodyValidation.parse(req.body);
const teamId = requireTeamId(req?.user?.teamId);
await this.maintenanceWindowService.createMaintenanceWindow({ teamId, body: req.body });
@@ -40,7 +40,7 @@ class MaintenanceWindowController {
};
getMaintenanceWindowById = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMaintenanceWindowByIdParamValidation.validateAsync(req.params);
getMaintenanceWindowByIdParamValidation.parse(req.params);
const teamId = requireTeamId(req.user?.teamId);
@@ -58,7 +58,7 @@ class MaintenanceWindowController {
getMaintenanceWindowsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMaintenanceWindowsByTeamIdQueryValidation.validateAsync(req.query);
getMaintenanceWindowsByTeamIdQueryValidation.parse(req.query);
const teamId = requireTeamId(req?.user?.teamId);
@@ -76,7 +76,7 @@ class MaintenanceWindowController {
getMaintenanceWindowsByMonitorId = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMaintenanceWindowsByMonitorIdParamValidation.validateAsync(req.params);
getMaintenanceWindowsByMonitorIdParamValidation.parse(req.params);
const teamId = requireTeamId(req?.user?.teamId);
@@ -96,7 +96,7 @@ class MaintenanceWindowController {
};
deleteMaintenanceWindow = async (req: Request, res: Response, next: NextFunction) => {
try {
await deleteMaintenanceWindowByIdParamValidation.validateAsync(req.params);
deleteMaintenanceWindowByIdParamValidation.parse(req.params);
const teamId = requireTeamId(req?.user?.teamId);
@@ -113,8 +113,8 @@ class MaintenanceWindowController {
editMaintenanceWindow = async (req: Request, res: Response, next: NextFunction) => {
try {
await editMaintenanceWindowByIdParamValidation.validateAsync(req.params);
await editMaintenanceByIdWindowBodyValidation.validateAsync(req.body);
editMaintenanceWindowByIdParamValidation.parse(req.params);
editMaintenanceByIdWindowBodyValidation.parse(req.body);
const teamId = requireTeamId(req.user?.teamId);
+18 -18
View File
@@ -45,7 +45,7 @@ class MonitorController {
getMonitorCertificate = async (req: Request, res: Response, next: NextFunction) => {
try {
await getCertificateParamValidation.validateAsync(req.params);
getCertificateParamValidation.parse(req.params);
const teamId = requireTeamId(req?.user?.teamId);
const monitorId = requireString(req.params?.monitorId, "Monitor ID");
const monitor = await this.monitorService.getMonitorById({ teamId, monitorId });
@@ -88,8 +88,8 @@ class MonitorController {
getHardwareDetailsById = async (req: Request, res: Response, next: NextFunction) => {
try {
await getHardwareDetailsByIdParamValidation.validateAsync(req.params);
await getHardwareDetailsByIdQueryValidation.validateAsync(req.query);
getHardwareDetailsByIdParamValidation.parse(req.params);
getHardwareDetailsByIdQueryValidation.parse(req.query);
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
const dateRange = optionalString(req?.query?.dateRange, "dateRange") || "recent";
@@ -112,8 +112,8 @@ class MonitorController {
};
getPageSpeedDetailsById = async (req: Request, res: Response, next: NextFunction) => {
try {
await getHardwareDetailsByIdParamValidation.validateAsync(req.params);
await getHardwareDetailsByIdQueryValidation.validateAsync(req.query);
getHardwareDetailsByIdParamValidation.parse(req.params);
getHardwareDetailsByIdQueryValidation.parse(req.query);
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
const dateRange = requireString(req?.query?.dateRange, "dateRange");
@@ -137,8 +137,8 @@ class MonitorController {
getGeoChecksByMonitorId = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMonitorByIdParamValidation.validateAsync(req.params);
await getMonitorByIdQueryValidation.validateAsync(req.query);
getMonitorByIdParamValidation.parse(req.params);
getMonitorByIdQueryValidation.parse(req.query);
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
const dateRange = requireString(req?.query?.dateRange, "dateRange");
@@ -169,8 +169,8 @@ class MonitorController {
getMonitorById = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMonitorByIdParamValidation.validateAsync(req.params);
await getMonitorByIdQueryValidation.validateAsync(req.query);
getMonitorByIdParamValidation.parse(req.params);
getMonitorByIdQueryValidation.parse(req.query);
const teamId = requireTeamId(req?.user?.teamId);
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
@@ -189,7 +189,7 @@ class MonitorController {
createMonitor = async (req: Request, res: Response, next: NextFunction) => {
try {
await createMonitorBodyValidation.validateAsync(req.body);
createMonitorBodyValidation.parse(req.body);
const userId = requireString(req?.user?.id, "User ID");
const teamId = requireTeamId(req?.user?.teamId);
@@ -231,7 +231,7 @@ class MonitorController {
deleteMonitor = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMonitorByIdParamValidation.validateAsync(req.params);
getMonitorByIdParamValidation.parse(req.params);
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
const teamId = requireTeamId(req?.user?.teamId);
@@ -264,8 +264,8 @@ class MonitorController {
editMonitor = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMonitorByIdParamValidation.validateAsync(req.params);
await editMonitorBodyValidation.validateAsync(req.body);
getMonitorByIdParamValidation.parse(req.params);
editMonitorBodyValidation.parse(req.body);
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
const teamId = requireTeamId(req?.user?.teamId);
@@ -283,7 +283,7 @@ class MonitorController {
pauseMonitor = async (req: Request, res: Response, next: NextFunction) => {
try {
await pauseMonitorParamValidation.validateAsync(req.params);
pauseMonitorParamValidation.parse(req.params);
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
const teamId = requireTeamId(req?.user?.teamId);
@@ -336,8 +336,8 @@ class MonitorController {
getMonitorsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
getMonitorsByTeamIdParamValidation.parse(req.params);
getMonitorsByTeamIdQueryValidation.parse(req.query);
const teamId = requireTeamId(req?.user?.teamId);
const type = parseMonitorTypeFilter(req.query?.type);
@@ -357,8 +357,8 @@ class MonitorController {
getMonitorsWithChecksByTeamId = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
await getMonitorsWithChecksQueryValidation.validateAsync(req.query);
getMonitorsByTeamIdParamValidation.parse(req.params);
getMonitorsWithChecksQueryValidation.parse(req.query);
const explain = optionalBoolean(req?.query?.explain, "explain");
const limit = optionalNumber(req?.query?.limit, "limit");
const page = optionalNumber(req?.query?.page, "page");
+22 -9
View File
@@ -5,6 +5,19 @@ import { GeoContinents } from "@/types/geoCheck.js";
// Check Validations
//****************************************
export const ackCheckBodyValidation = z.object({
ack: z.coerce.boolean().optional(),
});
export const ackAllChecksParamValidation = z.object({
monitorId: z.string().optional(),
path: z.enum(["monitor", "team"]),
});
export const ackAllChecksBodyValidation = z.object({
ack: z.coerce.boolean().optional(),
});
export const getChecksParamValidation = z.object({
monitorId: z.string().min(1, "Monitor ID is required"),
});
@@ -12,24 +25,24 @@ export const getChecksParamValidation = z.object({
export const getChecksQueryValidation = z.object({
type: z.enum(["http", "ping", "pagespeed", "hardware", "docker", "port", "game", "grpc"]).optional(),
sortOrder: z.enum(["asc", "desc"]).optional(),
limit: z.number().optional(),
limit: z.coerce.number().optional(),
dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).optional(),
filter: z.enum(["all", "up", "down", "resolve"]).optional(),
ack: z.boolean().optional(),
page: z.number().optional(),
rowsPerPage: z.number().optional(),
status: z.boolean().optional(),
ack: z.coerce.boolean().optional(),
page: z.coerce.number().optional(),
rowsPerPage: z.coerce.number().optional(),
status: z.coerce.boolean().optional(),
continent: z.union([z.enum(GeoContinents), z.array(z.enum(GeoContinents))]).optional(),
});
export const getTeamChecksQueryValidation = z.object({
sortOrder: z.enum(["asc", "desc"]).optional(),
limit: z.number().optional(),
limit: z.coerce.number().optional(),
dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).optional(),
filter: z.enum(["all", "up", "down", "resolve"]).optional(),
ack: z.boolean().optional(),
page: z.number().optional(),
rowsPerPage: z.number().optional(),
ack: z.coerce.boolean().optional(),
page: z.coerce.number().optional(),
rowsPerPage: z.coerce.number().optional(),
});
export const deleteChecksParamValidation = z.object({
@@ -1,53 +1,53 @@
import joi from "joi";
import { z } from "zod";
//****************************************
// Maintenance Window Validations
//****************************************
export const createMaintenanceWindowBodyValidation = joi.object({
monitors: joi.array().items(joi.string()).required(),
name: joi.string().required(),
active: joi.boolean(),
duration: joi.number().required(),
durationUnit: joi.string().valid("seconds", "minutes", "hours", "days").required(),
start: joi.date().required(),
end: joi.date().required(),
repeat: joi.number().required(),
expiry: joi.date(),
export const createMaintenanceWindowBodyValidation = z.object({
monitors: z.array(z.string()).min(1, "At least one monitor is required"),
name: z.string().min(1, "Name is required"),
active: z.boolean().optional(),
duration: z.number().min(1, "Duration is required"),
durationUnit: z.enum(["seconds", "minutes", "hours", "days"]),
start: z.coerce.date(),
end: z.coerce.date(),
repeat: z.number().min(0, "Repeat must be a non-negative number"),
expiry: z.coerce.date().optional(),
});
export const getMaintenanceWindowByIdParamValidation = joi.object({
id: joi.string().required(),
export const getMaintenanceWindowByIdParamValidation = z.object({
id: z.string().min(1, "ID is required"),
});
export const getMaintenanceWindowsByTeamIdQueryValidation = joi.object({
active: joi.boolean(),
page: joi.number(),
rowsPerPage: joi.number(),
field: joi.string(),
order: joi.string().valid("asc", "desc"),
export const getMaintenanceWindowsByTeamIdQueryValidation = z.object({
active: z.coerce.boolean().optional(),
page: z.coerce.number().optional(),
rowsPerPage: z.coerce.number().optional(),
field: z.string().optional(),
order: z.enum(["asc", "desc"]).optional(),
});
export const getMaintenanceWindowsByMonitorIdParamValidation = joi.object({
monitorId: joi.string().required(),
export const getMaintenanceWindowsByMonitorIdParamValidation = z.object({
monitorId: z.string().min(1, "Monitor ID is required"),
});
export const deleteMaintenanceWindowByIdParamValidation = joi.object({
id: joi.string().required(),
export const deleteMaintenanceWindowByIdParamValidation = z.object({
id: z.string().min(1, "ID is required"),
});
export const editMaintenanceWindowByIdParamValidation = joi.object({
id: joi.string().required(),
export const editMaintenanceWindowByIdParamValidation = z.object({
id: z.string().min(1, "ID is required"),
});
export const editMaintenanceByIdWindowBodyValidation = joi.object({
active: joi.boolean(),
name: joi.string(),
repeat: joi.number(),
start: joi.date(),
end: joi.date(),
expiry: joi.date(),
monitors: joi.array(),
duration: joi.number(),
durationUnit: joi.string().valid("seconds", "minutes", "hours", "days"),
export const editMaintenanceByIdWindowBodyValidation = z.object({
active: z.boolean().optional(),
name: z.string().optional(),
repeat: z.number().optional(),
start: z.coerce.date().optional(),
end: z.coerce.date().optional(),
expiry: z.coerce.date().optional(),
monitors: z.array(z.unknown()).optional(),
duration: z.number().optional(),
durationUnit: z.enum(["seconds", "minutes", "hours", "days"]).optional(),
});
+99 -106
View File
@@ -1,127 +1,120 @@
import joi from "joi";
import { z } from "zod";
import { GeoContinents } from "@/types/geoCheck.js";
export const getMonitorByIdParamValidation = joi.object({
monitorId: joi.string().required(),
export const getMonitorByIdParamValidation = z.object({
monitorId: z.string().min(1, "Monitor ID is required"),
});
export const getMonitorByIdQueryValidation = joi.object({
status: joi.boolean(),
sortOrder: joi.string().valid("asc", "desc"),
limit: joi.number(),
dateRange: joi.string().valid("recent", "hour", "day", "week", "month", "all"),
numToDisplay: joi.number(),
normalize: joi.boolean(),
continent: joi.string().valid(...GeoContinents),
export const getMonitorByIdQueryValidation = z.object({
status: z.coerce.boolean().optional(),
sortOrder: z.enum(["asc", "desc"]).optional(),
limit: z.coerce.number().optional(),
dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).optional(),
numToDisplay: z.coerce.number().optional(),
normalize: z.coerce.boolean().optional(),
continent: z.enum(GeoContinents).optional(),
});
export const getMonitorsByTeamIdParamValidation = joi.object({});
export const getMonitorsByTeamIdParamValidation = z.object({});
export const getMonitorsByTeamIdQueryValidation = joi.object({
type: joi
.alternatives()
.try(
joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc"),
joi.array().items(joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc"))
),
filter: joi.string().allow("", null),
});
export const getMonitorsWithChecksQueryValidation = joi.object({
limit: joi.number().integer().min(1).max(100).optional(),
page: joi.number().integer().min(0).optional(),
rowsPerPage: joi.number().integer().min(1).max(100).optional(),
filter: joi.string().allow("", null).optional(),
field: joi.string().optional(),
order: joi.string().valid("asc", "desc").optional(),
type: joi
.alternatives()
.try(
joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc"),
joi.array().items(joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc"))
)
export const getMonitorsByTeamIdQueryValidation = z.object({
type: z
.union([
z.enum(["http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc"]),
z.array(z.enum(["http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc"])),
])
.optional(),
explain: joi.boolean().optional(),
filter: z.union([z.string(), z.literal(""), z.null()]).optional(),
});
export const getCertificateParamValidation = joi.object({
monitorId: joi.string().required(),
});
export const createMonitorBodyValidation = joi.object({
_id: joi.string(),
name: joi.string().required(),
description: joi.string().allow(null, ""),
type: joi.string().required(),
statusWindowSize: joi.number().min(1).max(20).default(5),
statusWindowThreshold: joi.number().min(1).max(100).default(60),
url: joi.string().required(),
ignoreTlsErrors: joi.boolean().default(false),
useAdvancedMatching: joi.boolean().default(false),
port: joi.number(),
isActive: joi.boolean(),
interval: joi.number(),
cpuAlertThreshold: joi.number(),
memoryAlertThreshold: joi.number(),
diskAlertThreshold: joi.number(),
tempAlertThreshold: joi.number(),
notifications: joi.array().items(joi.string()),
secret: joi.string(),
jsonPath: joi.string().allow(""),
expectedValue: joi.string().allow(""),
matchMethod: joi.string().allow(null, ""),
gameId: joi.string().allow(""),
grpcServiceName: joi.string().allow("").default(""),
selectedDisks: joi.array().items(joi.string()).optional(),
group: joi.string().max(50).trim().allow(null, "").optional(),
geoCheckEnabled: joi.boolean().optional(),
geoCheckLocations: joi
.array()
.items(joi.string().valid(...GeoContinents))
export const getMonitorsWithChecksQueryValidation = z.object({
limit: z.coerce.number().int().min(1).max(100).optional(),
page: z.coerce.number().int().min(0).optional(),
rowsPerPage: z.coerce.number().int().min(1).max(100).optional(),
filter: z.union([z.string(), z.literal(""), z.null()]).optional(),
field: z.string().optional(),
order: z.enum(["asc", "desc"]).optional(),
type: z
.union([
z.enum(["http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc"]),
z.array(z.enum(["http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc"])),
])
.optional(),
geoCheckInterval: joi.number().min(300000).optional(),
explain: z.coerce.boolean().optional(),
});
export const editMonitorBodyValidation = joi
export const getCertificateParamValidation = z.object({
monitorId: z.string().min(1, "Monitor ID is required"),
});
export const createMonitorBodyValidation = z.object({
_id: z.string().optional(),
name: z.string().min(1, "Name is required"),
description: z.union([z.string(), z.null(), z.literal("")]).optional(),
type: z.string().min(1, "Type is required"),
statusWindowSize: z.number().min(1).max(20).default(5),
statusWindowThreshold: z.number().min(1).max(100).default(60),
url: z.string().min(1, "URL is required"),
ignoreTlsErrors: z.boolean().default(false),
useAdvancedMatching: z.boolean().default(false),
port: z.number().optional(),
isActive: z.boolean().optional(),
interval: z.number().optional(),
cpuAlertThreshold: z.number().optional(),
memoryAlertThreshold: z.number().optional(),
diskAlertThreshold: z.number().optional(),
tempAlertThreshold: z.number().optional(),
notifications: z.array(z.string()).optional(),
secret: z.string().optional(),
jsonPath: z.union([z.string(), z.literal("")]).optional(),
expectedValue: z.union([z.string(), z.literal("")]).optional(),
matchMethod: z.union([z.string(), z.null(), z.literal("")]).optional(),
gameId: z.union([z.string(), z.literal("")]).optional(),
grpcServiceName: z.union([z.string(), z.literal("")]).default(""),
selectedDisks: z.array(z.string()).optional(),
group: z.union([z.string().max(50).trim(), z.null(), z.literal("")]).optional(),
geoCheckEnabled: z.boolean().optional(),
geoCheckLocations: z.array(z.enum(GeoContinents)).optional(),
geoCheckInterval: z.number().min(300000).optional(),
});
export const editMonitorBodyValidation = z
.object({
name: joi.string(),
statusWindowSize: joi.number().min(1).max(20).default(5),
statusWindowThreshold: joi.number().min(1).max(100).default(60),
description: joi.string().allow(null, ""),
interval: joi.number(),
notifications: joi.array().items(joi.string()),
secret: joi.string(),
ignoreTlsErrors: joi.boolean(),
useAdvancedMatching: joi.boolean(),
jsonPath: joi.string().allow(""),
expectedValue: joi.string().allow(""),
matchMethod: joi.string().allow(null, ""),
port: joi.number().min(1).max(65535),
cpuAlertThreshold: joi.number(),
memoryAlertThreshold: joi.number(),
diskAlertThreshold: joi.number(),
tempAlertThreshold: joi.number(),
gameId: joi.string().allow(""),
grpcServiceName: joi.string().allow(""),
selectedDisks: joi.array().items(joi.string()).optional(),
group: joi.string().max(50).trim().allow(null, "").optional(),
geoCheckEnabled: joi.boolean().optional(),
geoCheckLocations: joi
.array()
.items(joi.string().valid(...GeoContinents))
.optional(),
geoCheckInterval: joi.number().min(300000).optional(),
name: z.string().optional(),
statusWindowSize: z.number().min(1).max(20).default(5),
statusWindowThreshold: z.number().min(1).max(100).default(60),
description: z.union([z.string(), z.null(), z.literal("")]).optional(),
interval: z.number().optional(),
notifications: z.array(z.string()).optional(),
secret: z.string().optional(),
ignoreTlsErrors: z.boolean().optional(),
useAdvancedMatching: z.boolean().optional(),
jsonPath: z.union([z.string(), z.literal("")]).optional(),
expectedValue: z.union([z.string(), z.literal("")]).optional(),
matchMethod: z.union([z.string(), z.null(), z.literal("")]).optional(),
port: z.number().min(1).max(65535).optional(),
cpuAlertThreshold: z.number().optional(),
memoryAlertThreshold: z.number().optional(),
diskAlertThreshold: z.number().optional(),
tempAlertThreshold: z.number().optional(),
gameId: z.union([z.string(), z.literal("")]).optional(),
grpcServiceName: z.union([z.string(), z.literal("")]).optional(),
selectedDisks: z.array(z.string()).optional(),
group: z.union([z.string().max(50).trim(), z.null(), z.literal("")]).optional(),
geoCheckEnabled: z.boolean().optional(),
geoCheckLocations: z.array(z.enum(GeoContinents)).optional(),
geoCheckInterval: z.number().min(300000).optional(),
})
.options({ stripUnknown: true });
.strict();
export const pauseMonitorParamValidation = joi.object({
monitorId: joi.string().required(),
export const pauseMonitorParamValidation = z.object({
monitorId: z.string().min(1, "Monitor ID is required"),
});
export const getHardwareDetailsByIdParamValidation = joi.object({
monitorId: joi.string().required(),
export const getHardwareDetailsByIdParamValidation = z.object({
monitorId: z.string().min(1, "Monitor ID is required"),
});
export const getHardwareDetailsByIdQueryValidation = joi.object({
dateRange: joi.string().valid("recent", "hour", "day", "week", "month", "all"),
export const getHardwareDetailsByIdQueryValidation = z.object({
dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).optional(),
});