Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76f550843b | ||
|
|
15d8a8ba1f | ||
|
|
e878f51887 | ||
|
|
16b267d3a5 | ||
|
|
c156a49cc0 | ||
|
|
20ff76df9d | ||
|
|
ff90953f17 | ||
|
|
545926cfcf | ||
|
|
42f6c42ae1 | ||
|
|
456237ba4e | ||
|
|
e887c2308a | ||
|
|
d07f259829 | ||
|
|
566011c4e9 | ||
|
|
cda0ec3a4c | ||
|
|
d00889ff9b | ||
|
|
eafd97b9ad |
No files matched your search
@@ -3,7 +3,7 @@ import { Monitor, type MonitorType, MonitorTypes, UserRole } from "@/types/index
|
|||||||
import sslChecker, { SSLDetails } from "ssl-checker";
|
import sslChecker, { SSLDetails } from "ssl-checker";
|
||||||
type SSLCheckerType = typeof sslChecker;
|
type SSLCheckerType = typeof sslChecker;
|
||||||
|
|
||||||
const fetchMonitorCertificate = async (checker: SSLCheckerType, monitor: Monitor): Promise<SSLDetails> => {
|
export const fetchMonitorCertificate = async (checker: SSLCheckerType, monitor: Monitor): Promise<SSLDetails> => {
|
||||||
const monitorUrl = new URL(monitor.url);
|
const monitorUrl = new URL(monitor.url);
|
||||||
const hostname = monitorUrl.hostname;
|
const hostname = monitorUrl.hostname;
|
||||||
const cert = await checker(hostname);
|
const cert = await checker(hostname);
|
||||||
@@ -12,14 +12,14 @@ const fetchMonitorCertificate = async (checker: SSLCheckerType, monitor: Monitor
|
|||||||
}
|
}
|
||||||
return cert;
|
return cert;
|
||||||
};
|
};
|
||||||
const requireString = (value: unknown, fieldName: string): string => {
|
export const requireString = (value: unknown, fieldName: string): string => {
|
||||||
if (typeof value === "string" && value.trim().length > 0) {
|
if (typeof value === "string" && value.trim().length > 0) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
throw new AppError({ message: `${fieldName} is required`, status: 400 });
|
throw new AppError({ message: `${fieldName} is required`, status: 400 });
|
||||||
};
|
};
|
||||||
|
|
||||||
const optionalString = (value: unknown, fieldName: string): string | undefined => {
|
export const optionalString = (value: unknown, fieldName: string): string | undefined => {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ const optionalString = (value: unknown, fieldName: string): string | undefined =
|
|||||||
throw new AppError({ message: `${fieldName} must be a string`, status: 400 });
|
throw new AppError({ message: `${fieldName} must be a string`, status: 400 });
|
||||||
};
|
};
|
||||||
|
|
||||||
const optionalNumber = (value: unknown, fieldName: string): number | undefined => {
|
export const optionalNumber = (value: unknown, fieldName: string): number | undefined => {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ const optionalNumber = (value: unknown, fieldName: string): number | undefined =
|
|||||||
throw new AppError({ message: `${fieldName} must be a number`, status: 400 });
|
throw new AppError({ message: `${fieldName} must be a number`, status: 400 });
|
||||||
};
|
};
|
||||||
|
|
||||||
const optionalBoolean = (value: unknown, fieldName: string): boolean | undefined => {
|
export const optionalBoolean = (value: unknown, fieldName: string): boolean | undefined => {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ const optionalBoolean = (value: unknown, fieldName: string): boolean | undefined
|
|||||||
throw new AppError({ message: `${fieldName} must be a boolean`, status: 400 });
|
throw new AppError({ message: `${fieldName} must be a boolean`, status: 400 });
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseMonitorTypeFilter = (value: unknown): MonitorType | MonitorType[] | undefined => {
|
export const parseMonitorTypeFilter = (value: unknown): MonitorType | MonitorType[] | undefined => {
|
||||||
const parseSingle = (input: unknown): MonitorType => {
|
const parseSingle = (input: unknown): MonitorType => {
|
||||||
if (typeof input !== "string") {
|
if (typeof input !== "string") {
|
||||||
throw new AppError({ message: "Monitor type must be a string", status: 400 });
|
throw new AppError({ message: "Monitor type must be a string", status: 400 });
|
||||||
@@ -83,7 +83,7 @@ const parseMonitorTypeFilter = (value: unknown): MonitorType | MonitorType[] | u
|
|||||||
return parseSingle(value);
|
return parseSingle(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseSortOrder = (value: unknown): "asc" | "desc" | undefined => {
|
export const parseSortOrder = (value: unknown): "asc" | "desc" | undefined => {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -93,42 +93,36 @@ const parseSortOrder = (value: unknown): "asc" | "desc" | undefined => {
|
|||||||
throw new AppError({ message: "order must be either 'asc' or 'desc'", status: 400 });
|
throw new AppError({ message: "order must be either 'asc' or 'desc'", status: 400 });
|
||||||
};
|
};
|
||||||
|
|
||||||
const requireTeamId = (teamId?: string): string => {
|
export const requireTeamId = (teamId?: string): string => {
|
||||||
if (!teamId) {
|
if (!teamId) {
|
||||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
throw new AppError({ message: "Team ID is required", status: 400 });
|
||||||
}
|
}
|
||||||
return teamId;
|
return teamId;
|
||||||
};
|
};
|
||||||
|
|
||||||
const requireUserId = (userId?: string): string => {
|
export const requireUserId = (userId?: string): string => {
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
throw new AppError({ message: "User ID is required", status: 400 });
|
throw new AppError({ message: "User ID is required", status: 400 });
|
||||||
}
|
}
|
||||||
return userId;
|
return userId;
|
||||||
};
|
};
|
||||||
const requireUserEmail = (userEmail?: string): string => {
|
export const requireUserEmail = (userEmail?: string): string => {
|
||||||
if (!userEmail) {
|
if (!userEmail) {
|
||||||
throw new AppError({ message: "User email is required", status: 400 });
|
throw new AppError({ message: "User email is required", status: 400 });
|
||||||
}
|
}
|
||||||
return userEmail;
|
return userEmail;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const requireFirstName = (firstName?: string): string => {
|
||||||
|
if (!firstName) {
|
||||||
|
throw new AppError({ message: "First name is required", status: 400 });
|
||||||
|
}
|
||||||
|
return firstName;
|
||||||
|
};
|
||||||
|
|
||||||
export const requireUserRoles = (userRoles?: UserRole[]): UserRole[] => {
|
export const requireUserRoles = (userRoles?: UserRole[]): UserRole[] => {
|
||||||
if (!userRoles || userRoles.length === 0) {
|
if (!userRoles || userRoles.length === 0) {
|
||||||
throw new AppError({ message: "User roles are required", status: 400 });
|
throw new AppError({ message: "User roles are required", status: 400 });
|
||||||
}
|
}
|
||||||
return userRoles;
|
return userRoles;
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
|
||||||
fetchMonitorCertificate,
|
|
||||||
requireString,
|
|
||||||
optionalString,
|
|
||||||
optionalNumber,
|
|
||||||
optionalBoolean,
|
|
||||||
parseMonitorTypeFilter,
|
|
||||||
parseSortOrder,
|
|
||||||
requireTeamId,
|
|
||||||
requireUserId,
|
|
||||||
requireUserEmail,
|
|
||||||
};
|
|
||||||
@@ -1,35 +1,30 @@
|
|||||||
import { AppError } from "@/utils/AppError.js";
|
import { AppError } from "@/utils/AppError.js";
|
||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { requireTeamId, requireUserId, requireUserEmail } from "./controllerUtils.js";
|
import { requireTeamId, requireUserId, requireUserEmail } from "./controllerUtils.js";
|
||||||
|
import { IIncidentService } from "@/service/index.js";
|
||||||
|
import { getIncidentsByTeamQueryValidation, getIncidentSummaryQueryValidation } from "@/validation/incidentValidation.js";
|
||||||
|
|
||||||
const SERVICE_NAME = "incidentController";
|
const SERVICE_NAME = "IncidentController";
|
||||||
|
|
||||||
class IncidentController {
|
class IncidentController {
|
||||||
static SERVICE_NAME = SERVICE_NAME;
|
private incidentService: IIncidentService;
|
||||||
|
constructor(incidentService: IIncidentService) {
|
||||||
private incidentService: any;
|
|
||||||
constructor(incidentService: any) {
|
|
||||||
this.incidentService = incidentService;
|
this.incidentService = incidentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
get serviceName() {
|
|
||||||
return IncidentController.SERVICE_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
getIncidentsByTeam = async (req: Request, res: Response, next: NextFunction) => {
|
getIncidentsByTeam = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const { sortOrder, dateRange, page, rowsPerPage, status, monitorId, resolutionType } = req.query || {};
|
const validatedQuery = getIncidentsByTeamQueryValidation.parse(req.query);
|
||||||
|
|
||||||
const teamId = requireTeamId(req.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const result = await this.incidentService.getIncidentsByTeam(
|
const result = await this.incidentService.getIncidentsByTeam(
|
||||||
teamId,
|
teamId,
|
||||||
sortOrder,
|
validatedQuery.sortOrder,
|
||||||
dateRange,
|
validatedQuery.dateRange,
|
||||||
page,
|
validatedQuery.page,
|
||||||
rowsPerPage,
|
validatedQuery.rowsPerPage,
|
||||||
status,
|
validatedQuery.status,
|
||||||
monitorId,
|
validatedQuery.monitorId,
|
||||||
resolutionType
|
validatedQuery.resolutionType
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
@@ -45,10 +40,9 @@ class IncidentController {
|
|||||||
getIncidentSummary = async (req: Request, res: Response, next: NextFunction) => {
|
getIncidentSummary = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const teamId = requireTeamId(req.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
const validatedQuery = getIncidentSummaryQueryValidation.parse(req.query);
|
||||||
|
|
||||||
const limit = req.query.limit ? parseInt(req.query.limit as string, 10) : 10;
|
const summary = await this.incidentService.getIncidentSummary(teamId, validatedQuery.limit);
|
||||||
|
|
||||||
const summary = await this.incidentService.getIncidentSummary(teamId, limit);
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
msg: "Incident summary retrieved successfully",
|
msg: "Incident summary retrieved successfully",
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { inviteBodyValidation, inviteVerificationBodyValidation } from "@/validation/authValidation.js";
|
import { inviteBodyValidation, inviteVerificationBodyValidation } from "@/validation/authValidation.js";
|
||||||
import { requireTeamId, requireUserRoles } from "@/controllers/controllerUtils.js";
|
import { requireFirstName, requireTeamId, requireUserRoles } from "@/controllers/controllerUtils.js";
|
||||||
|
import { IInviteService } from "@/service/index.js";
|
||||||
const SERVICE_NAME = "inviteController";
|
const SERVICE_NAME = "inviteController";
|
||||||
|
|
||||||
class InviteController {
|
class InviteController {
|
||||||
static SERVICE_NAME = SERVICE_NAME;
|
static SERVICE_NAME = SERVICE_NAME;
|
||||||
private inviteService: any;
|
private inviteService: IInviteService;
|
||||||
constructor(inviteService: any) {
|
constructor(inviteService: IInviteService) {
|
||||||
this.inviteService = inviteService;
|
this.inviteService = inviteService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,8 +35,9 @@ class InviteController {
|
|||||||
|
|
||||||
sendInviteEmail = async (req: Request, res: Response, next: NextFunction) => {
|
sendInviteEmail = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const userRoles = requireUserRoles(req?.user?.role);
|
const userRoles = requireUserRoles(req.user?.role);
|
||||||
|
const firstName = requireFirstName(req.user?.firstName);
|
||||||
|
|
||||||
const inviteRequest = req.body;
|
const inviteRequest = req.body;
|
||||||
inviteRequest.teamId = teamId;
|
inviteRequest.teamId = teamId;
|
||||||
@@ -43,7 +45,7 @@ class InviteController {
|
|||||||
|
|
||||||
const inviteToken = await this.inviteService.sendInviteEmail({
|
const inviteToken = await this.inviteService.sendInviteEmail({
|
||||||
invite: inviteRequest,
|
invite: inviteRequest,
|
||||||
firstName: req?.user?.firstName,
|
firstName,
|
||||||
userRoles,
|
userRoles,
|
||||||
});
|
});
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
|
import { ILogger } from "@/utils/logger.js";
|
||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
|
|
||||||
const SERVICE_NAME = "LogController";
|
const SERVICE_NAME = "LogController";
|
||||||
|
|
||||||
class LogController {
|
class LogController {
|
||||||
static SERVICE_NAME = SERVICE_NAME;
|
static SERVICE_NAME = SERVICE_NAME;
|
||||||
private logger: any;
|
private logger: ILogger;
|
||||||
constructor(logger: any) {
|
constructor(logger: ILogger) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
get serviceName() {
|
get serviceName() {
|
||||||
@@ -14,7 +15,7 @@ class LogController {
|
|||||||
|
|
||||||
getLogs = async (req: Request, res: Response, next: NextFunction) => {
|
getLogs = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const logs = await this.logger.getLogs();
|
const logs = this.logger.getLogs();
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
msg: "Logs fetched successfully",
|
msg: "Logs fetched successfully",
|
||||||
|
|||||||
@@ -9,26 +9,19 @@ import {
|
|||||||
deleteMaintenanceWindowByIdParamValidation,
|
deleteMaintenanceWindowByIdParamValidation,
|
||||||
} from "@/validation/maintenanceWindowValidation.js";
|
} from "@/validation/maintenanceWindowValidation.js";
|
||||||
import { requireTeamId } from "@/controllers/controllerUtils.js";
|
import { requireTeamId } from "@/controllers/controllerUtils.js";
|
||||||
|
import { IMaintenanceWindowService } from "@/service/index.js";
|
||||||
const SERVICE_NAME = "maintenanceWindowController";
|
|
||||||
|
|
||||||
class MaintenanceWindowController {
|
class MaintenanceWindowController {
|
||||||
static SERVICE_NAME = SERVICE_NAME;
|
private maintenanceWindowService: IMaintenanceWindowService;
|
||||||
private maintenanceWindowService: any;
|
constructor(maintenanceWindowService: IMaintenanceWindowService) {
|
||||||
constructor(maintenanceWindowService: any) {
|
|
||||||
this.maintenanceWindowService = maintenanceWindowService;
|
this.maintenanceWindowService = maintenanceWindowService;
|
||||||
}
|
}
|
||||||
|
|
||||||
get serviceName() {
|
|
||||||
return MaintenanceWindowController.SERVICE_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
createMaintenanceWindows = async (req: Request, res: Response, next: NextFunction) => {
|
createMaintenanceWindows = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
createMaintenanceWindowBodyValidation.parse(req.body);
|
const validatedBody = createMaintenanceWindowBodyValidation.parse(req.body);
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req?.user?.teamId);
|
||||||
|
await this.maintenanceWindowService.createMaintenanceWindow({ teamId, body: validatedBody });
|
||||||
await this.maintenanceWindowService.createMaintenanceWindow({ teamId, body: req.body });
|
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -40,11 +33,11 @@ class MaintenanceWindowController {
|
|||||||
};
|
};
|
||||||
getMaintenanceWindowById = async (req: Request, res: Response, next: NextFunction) => {
|
getMaintenanceWindowById = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getMaintenanceWindowByIdParamValidation.parse(req.params);
|
const validatedParams = getMaintenanceWindowByIdParamValidation.parse(req.params);
|
||||||
|
|
||||||
const teamId = requireTeamId(req.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const maintenanceWindow = await this.maintenanceWindowService.getMaintenanceWindowById({ id: req.params.id as string, teamId });
|
const maintenanceWindow = await this.maintenanceWindowService.getMaintenanceWindowById({ id: validatedParams.id, teamId });
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -58,11 +51,18 @@ class MaintenanceWindowController {
|
|||||||
|
|
||||||
getMaintenanceWindowsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
getMaintenanceWindowsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getMaintenanceWindowsByTeamIdQueryValidation.parse(req.query);
|
const validatedQuery = getMaintenanceWindowsByTeamIdQueryValidation.parse(req.query);
|
||||||
|
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req?.user?.teamId);
|
||||||
|
|
||||||
const maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByTeamId({ teamId, query: req.query });
|
const maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByTeamId({
|
||||||
|
teamId,
|
||||||
|
active: validatedQuery.active,
|
||||||
|
page: validatedQuery.page,
|
||||||
|
rowsPerPage: validatedQuery.rowsPerPage,
|
||||||
|
field: validatedQuery.field,
|
||||||
|
order: validatedQuery.order,
|
||||||
|
});
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -76,12 +76,12 @@ class MaintenanceWindowController {
|
|||||||
|
|
||||||
getMaintenanceWindowsByMonitorId = async (req: Request, res: Response, next: NextFunction) => {
|
getMaintenanceWindowsByMonitorId = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getMaintenanceWindowsByMonitorIdParamValidation.parse(req.params);
|
const validatedParams = getMaintenanceWindowsByMonitorIdParamValidation.parse(req.params);
|
||||||
|
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req?.user?.teamId);
|
||||||
|
|
||||||
const maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByMonitorId({
|
const maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByMonitorId({
|
||||||
monitorId: req.params.monitorId as string,
|
monitorId: validatedParams.monitorId,
|
||||||
teamId,
|
teamId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -96,11 +96,11 @@ class MaintenanceWindowController {
|
|||||||
};
|
};
|
||||||
deleteMaintenanceWindow = async (req: Request, res: Response, next: NextFunction) => {
|
deleteMaintenanceWindow = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
deleteMaintenanceWindowByIdParamValidation.parse(req.params);
|
const validatedParams = deleteMaintenanceWindowByIdParamValidation.parse(req.params);
|
||||||
|
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req?.user?.teamId);
|
||||||
|
|
||||||
await this.maintenanceWindowService.deleteMaintenanceWindow({ id: req.params.id as string, teamId });
|
await this.maintenanceWindowService.deleteMaintenanceWindow({ id: validatedParams.id, teamId });
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -113,14 +113,14 @@ class MaintenanceWindowController {
|
|||||||
|
|
||||||
editMaintenanceWindow = async (req: Request, res: Response, next: NextFunction) => {
|
editMaintenanceWindow = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
editMaintenanceWindowByIdParamValidation.parse(req.params);
|
const validatedParams = editMaintenanceWindowByIdParamValidation.parse(req.params);
|
||||||
editMaintenanceByIdWindowBodyValidation.parse(req.body);
|
const validatedBody = editMaintenanceByIdWindowBodyValidation.parse(req.body);
|
||||||
|
|
||||||
const teamId = requireTeamId(req.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const editedMaintenanceWindow = await this.maintenanceWindowService.editMaintenanceWindow({
|
const editedMaintenanceWindow = await this.maintenanceWindowService.editMaintenanceWindow({
|
||||||
id: req.params.id as string,
|
id: validatedParams.id,
|
||||||
body: req.body,
|
body: validatedBody,
|
||||||
teamId,
|
teamId,
|
||||||
});
|
});
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { Request, Response, NextFunction } from "express";
|
|||||||
import {
|
import {
|
||||||
getMonitorByIdParamValidation,
|
getMonitorByIdParamValidation,
|
||||||
getMonitorByIdQueryValidation,
|
getMonitorByIdQueryValidation,
|
||||||
getMonitorsByTeamIdParamValidation,
|
|
||||||
getMonitorsByTeamIdQueryValidation,
|
getMonitorsByTeamIdQueryValidation,
|
||||||
getMonitorsWithChecksQueryValidation,
|
getMonitorsWithChecksQueryValidation,
|
||||||
createMonitorBodyValidation,
|
createMonitorBodyValidation,
|
||||||
@@ -12,22 +11,14 @@ import {
|
|||||||
getCertificateParamValidation,
|
getCertificateParamValidation,
|
||||||
getHardwareDetailsByIdParamValidation,
|
getHardwareDetailsByIdParamValidation,
|
||||||
getHardwareDetailsByIdQueryValidation,
|
getHardwareDetailsByIdQueryValidation,
|
||||||
|
getUptimeDetailsByIdParamValidation,
|
||||||
|
getUptimeDetailsByIdQueryValidation,
|
||||||
|
importMonitorsBodyValidation,
|
||||||
} from "@/validation/monitorValidation.js";
|
} from "@/validation/monitorValidation.js";
|
||||||
import sslChecker from "ssl-checker";
|
import sslChecker from "ssl-checker";
|
||||||
import {
|
import { fetchMonitorCertificate, requireTeamId, requireUserId } from "./controllerUtils.js";
|
||||||
fetchMonitorCertificate,
|
|
||||||
requireString,
|
|
||||||
optionalString,
|
|
||||||
optionalNumber,
|
|
||||||
optionalBoolean,
|
|
||||||
parseMonitorTypeFilter,
|
|
||||||
parseSortOrder,
|
|
||||||
requireTeamId,
|
|
||||||
requireUserId,
|
|
||||||
} from "./controllerUtils.js";
|
|
||||||
import { AppError } from "@/utils/AppError.js";
|
import { AppError } from "@/utils/AppError.js";
|
||||||
import { IMonitorService } from "@/service/index.js";
|
import { IMonitorService } from "@/service/index.js";
|
||||||
import { GeoContinent } from "@/types/geoCheck.js";
|
|
||||||
|
|
||||||
const SERVICE_NAME = "monitorController";
|
const SERVICE_NAME = "monitorController";
|
||||||
class MonitorController {
|
class MonitorController {
|
||||||
@@ -45,10 +36,9 @@ class MonitorController {
|
|||||||
|
|
||||||
getMonitorCertificate = async (req: Request, res: Response, next: NextFunction) => {
|
getMonitorCertificate = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getCertificateParamValidation.parse(req.params);
|
const validatedParams = getCertificateParamValidation.parse(req.params);
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const monitorId = requireString(req.params?.monitorId, "Monitor ID");
|
const monitor = await this.monitorService.getMonitorById({ teamId, monitorId: validatedParams.monitorId });
|
||||||
const monitor = await this.monitorService.getMonitorById({ teamId, monitorId });
|
|
||||||
const certificate = await fetchMonitorCertificate(sslChecker, monitor);
|
const certificate = await fetchMonitorCertificate(sslChecker, monitor);
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
@@ -65,10 +55,14 @@ class MonitorController {
|
|||||||
|
|
||||||
getUptimeDetailsById = async (req: Request, res: Response, next: NextFunction) => {
|
getUptimeDetailsById = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
|
const validatedParams = getUptimeDetailsByIdParamValidation.parse(req.params);
|
||||||
const dateRange = requireString(req?.query?.dateRange, "dateRange");
|
const validatedQuery = getUptimeDetailsByIdQueryValidation.parse(req.query);
|
||||||
const normalize = optionalBoolean(req?.query?.normalize, "normalize");
|
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const monitorId = validatedParams.monitorId;
|
||||||
|
const dateRange = validatedQuery.dateRange;
|
||||||
|
const normalize = validatedQuery.normalize;
|
||||||
|
|
||||||
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const data = await this.monitorService.getUptimeDetailsById({
|
const data = await this.monitorService.getUptimeDetailsById({
|
||||||
teamId,
|
teamId,
|
||||||
@@ -88,12 +82,12 @@ class MonitorController {
|
|||||||
|
|
||||||
getHardwareDetailsById = async (req: Request, res: Response, next: NextFunction) => {
|
getHardwareDetailsById = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getHardwareDetailsByIdParamValidation.parse(req.params);
|
const validatedParams = getHardwareDetailsByIdParamValidation.parse(req.params);
|
||||||
getHardwareDetailsByIdQueryValidation.parse(req.query);
|
const validatedQuery = getHardwareDetailsByIdQueryValidation.parse(req.query);
|
||||||
|
|
||||||
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
|
const monitorId = validatedParams.monitorId;
|
||||||
const dateRange = optionalString(req?.query?.dateRange, "dateRange") || "recent";
|
const dateRange = validatedQuery.dateRange || "recent";
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const data = await this.monitorService.getHardwareDetailsById({
|
const data = await this.monitorService.getHardwareDetailsById({
|
||||||
teamId,
|
teamId,
|
||||||
@@ -112,12 +106,12 @@ class MonitorController {
|
|||||||
};
|
};
|
||||||
getPageSpeedDetailsById = async (req: Request, res: Response, next: NextFunction) => {
|
getPageSpeedDetailsById = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getHardwareDetailsByIdParamValidation.parse(req.params);
|
const validatedParams = getHardwareDetailsByIdParamValidation.parse(req.params);
|
||||||
getHardwareDetailsByIdQueryValidation.parse(req.query);
|
const validatedQuery = getHardwareDetailsByIdQueryValidation.parse(req.query);
|
||||||
|
|
||||||
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
|
const monitorId = validatedParams.monitorId;
|
||||||
const dateRange = requireString(req?.query?.dateRange, "dateRange");
|
const dateRange = validatedQuery.dateRange || "recent";
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const data = await this.monitorService.getPageSpeedDetailsById({
|
const data = await this.monitorService.getPageSpeedDetailsById({
|
||||||
teamId,
|
teamId,
|
||||||
@@ -137,18 +131,14 @@ class MonitorController {
|
|||||||
|
|
||||||
getGeoChecksByMonitorId = async (req: Request, res: Response, next: NextFunction) => {
|
getGeoChecksByMonitorId = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getMonitorByIdParamValidation.parse(req.params);
|
const validatedParams = getMonitorByIdParamValidation.parse(req.params);
|
||||||
getMonitorByIdQueryValidation.parse(req.query);
|
const validatedQuery = getMonitorByIdQueryValidation.parse(req.query);
|
||||||
|
|
||||||
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
|
const monitorId = validatedParams.monitorId;
|
||||||
const dateRange = requireString(req?.query?.dateRange, "dateRange");
|
const dateRange = validatedQuery.dateRange || "recent";
|
||||||
const continentParam = req?.query?.continent;
|
const continentParam = validatedQuery.continent;
|
||||||
const continents = continentParam
|
const continents = continentParam ? (Array.isArray(continentParam) ? continentParam : [continentParam]) : undefined;
|
||||||
? Array.isArray(continentParam)
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
? (continentParam as GeoContinent[])
|
|
||||||
: [continentParam as GeoContinent]
|
|
||||||
: undefined;
|
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
|
||||||
|
|
||||||
const data = await this.monitorService.getGeoChecksByMonitorId({
|
const data = await this.monitorService.getGeoChecksByMonitorId({
|
||||||
teamId,
|
teamId,
|
||||||
@@ -169,11 +159,10 @@ class MonitorController {
|
|||||||
|
|
||||||
getMonitorById = async (req: Request, res: Response, next: NextFunction) => {
|
getMonitorById = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getMonitorByIdParamValidation.parse(req.params);
|
const validatedParams = getMonitorByIdParamValidation.parse(req.params);
|
||||||
getMonitorByIdQueryValidation.parse(req.query);
|
|
||||||
|
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
|
const monitorId = validatedParams.monitorId;
|
||||||
|
|
||||||
const monitor = await this.monitorService.getMonitorById({ teamId, monitorId });
|
const monitor = await this.monitorService.getMonitorById({ teamId, monitorId });
|
||||||
|
|
||||||
@@ -189,12 +178,12 @@ class MonitorController {
|
|||||||
|
|
||||||
createMonitor = async (req: Request, res: Response, next: NextFunction) => {
|
createMonitor = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
createMonitorBodyValidation.parse(req.body);
|
const validatedBody = createMonitorBodyValidation.parse(req.body);
|
||||||
|
|
||||||
const userId = requireString(req?.user?.id, "User ID");
|
const userId = requireUserId(req.user?.id);
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const monitor = await this.monitorService.createMonitor(teamId, userId, req.body);
|
const monitor = await this.monitorService.createMonitor(teamId, userId, validatedBody);
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -208,14 +197,10 @@ class MonitorController {
|
|||||||
|
|
||||||
importMonitorsFromJSON = async (req: Request, res: Response, next: NextFunction) => {
|
importMonitorsFromJSON = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const userId = requireUserId(req?.user?.id);
|
const userId = requireUserId(req.user?.id);
|
||||||
|
const validatedBody = importMonitorsBodyValidation.parse(req.body);
|
||||||
const { monitors } = req.body;
|
const monitors = validatedBody.monitors;
|
||||||
|
|
||||||
if (!monitors || !Array.isArray(monitors)) {
|
|
||||||
throw new AppError({ message: "Invalid request: monitors array is required", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.monitorService.importMonitorsFromJSON({ teamId, userId, monitors });
|
const result = await this.monitorService.importMonitorsFromJSON({ teamId, userId, monitors });
|
||||||
|
|
||||||
@@ -231,9 +216,9 @@ class MonitorController {
|
|||||||
|
|
||||||
deleteMonitor = async (req: Request, res: Response, next: NextFunction) => {
|
deleteMonitor = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getMonitorByIdParamValidation.parse(req.params);
|
const validatedParams = getMonitorByIdParamValidation.parse(req.params);
|
||||||
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const monitorId = validatedParams.monitorId;
|
||||||
|
|
||||||
const deletedMonitor = await this.monitorService.deleteMonitor({ teamId, monitorId });
|
const deletedMonitor = await this.monitorService.deleteMonitor({ teamId, monitorId });
|
||||||
|
|
||||||
@@ -249,8 +234,7 @@ class MonitorController {
|
|||||||
|
|
||||||
deleteAllMonitors = async (req: Request, res: Response, next: NextFunction) => {
|
deleteAllMonitors = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const deletedCount = await this.monitorService.deleteAllMonitors({ teamId });
|
const deletedCount = await this.monitorService.deleteAllMonitors({ teamId });
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
@@ -264,12 +248,12 @@ class MonitorController {
|
|||||||
|
|
||||||
editMonitor = async (req: Request, res: Response, next: NextFunction) => {
|
editMonitor = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getMonitorByIdParamValidation.parse(req.params);
|
const validatedParams = getMonitorByIdParamValidation.parse(req.params);
|
||||||
editMonitorBodyValidation.parse(req.body);
|
const validatedBody = editMonitorBodyValidation.parse(req.body);
|
||||||
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
|
const monitorId = validatedParams.monitorId;
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const editedMonitor = await this.monitorService.editMonitor({ teamId, monitorId, body: req.body });
|
const editedMonitor = await this.monitorService.editMonitor({ teamId, monitorId, body: validatedBody });
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -283,10 +267,10 @@ class MonitorController {
|
|||||||
|
|
||||||
pauseMonitor = async (req: Request, res: Response, next: NextFunction) => {
|
pauseMonitor = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
pauseMonitorParamValidation.parse(req.params);
|
const validatedParams = pauseMonitorParamValidation.parse(req.params);
|
||||||
|
|
||||||
const monitorId = requireString(req?.params?.monitorId, "Monitor ID");
|
const monitorId = validatedParams.monitorId;
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const monitor = await this.monitorService.pauseMonitor({ teamId, monitorId });
|
const monitor = await this.monitorService.pauseMonitor({ teamId, monitorId });
|
||||||
|
|
||||||
@@ -302,8 +286,8 @@ class MonitorController {
|
|||||||
|
|
||||||
addDemoMonitors = async (req: Request, res: Response, next: NextFunction) => {
|
addDemoMonitors = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const id = requireString(req?.user?.id, "User ID");
|
const id = requireUserId(req.user?.id);
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const demoMonitors = await this.monitorService.addDemoMonitors({ userId: id, teamId });
|
const demoMonitors = await this.monitorService.addDemoMonitors({ userId: id, teamId });
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
@@ -316,32 +300,13 @@ class MonitorController {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
sendTestEmail = async (req: Request, res: Response, next: NextFunction) => {
|
|
||||||
try {
|
|
||||||
const { to } = req.body;
|
|
||||||
if (!to || typeof to !== "string") {
|
|
||||||
throw new AppError({ message: "Invalid 'to' email address", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const messageId = await this.monitorService.sendTestEmail({ to });
|
|
||||||
return res.status(200).json({
|
|
||||||
success: true,
|
|
||||||
msg: "Test email sent successfully",
|
|
||||||
data: { messageId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
getMonitorsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
getMonitorsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getMonitorsByTeamIdParamValidation.parse(req.params);
|
const validatedQuery = getMonitorsByTeamIdQueryValidation.parse(req.query);
|
||||||
getMonitorsByTeamIdQueryValidation.parse(req.query);
|
|
||||||
|
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const type = parseMonitorTypeFilter(req.query?.type);
|
const type = validatedQuery.type;
|
||||||
const filter = optionalString(req.query?.filter, "filter");
|
const filter = validatedQuery.filter;
|
||||||
|
|
||||||
const monitors = await this.monitorService.getMonitorsByTeamId({ teamId, type, filter });
|
const monitors = await this.monitorService.getMonitorsByTeamId({ teamId, type, filter });
|
||||||
|
|
||||||
@@ -357,17 +322,17 @@ class MonitorController {
|
|||||||
|
|
||||||
getMonitorsWithChecksByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
getMonitorsWithChecksByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
getMonitorsByTeamIdParamValidation.parse(req.params);
|
const validatedQuery = getMonitorsWithChecksQueryValidation.parse(req.query);
|
||||||
getMonitorsWithChecksQueryValidation.parse(req.query);
|
|
||||||
const explain = optionalBoolean(req?.query?.explain, "explain");
|
const explain = validatedQuery.explain;
|
||||||
const limit = optionalNumber(req?.query?.limit, "limit");
|
const limit = validatedQuery.limit;
|
||||||
const page = optionalNumber(req?.query?.page, "page");
|
const page = validatedQuery.page;
|
||||||
const rowsPerPage = optionalNumber(req?.query?.rowsPerPage, "rowsPerPage");
|
const rowsPerPage = validatedQuery.rowsPerPage;
|
||||||
const filter = optionalString(req?.query?.filter, "filter");
|
const filter = validatedQuery.filter;
|
||||||
const field = optionalString(req?.query?.field, "field");
|
const field = validatedQuery.field;
|
||||||
const order = parseSortOrder(req?.query?.order);
|
const order = validatedQuery.order;
|
||||||
const type = parseMonitorTypeFilter(req?.query?.type);
|
const type = validatedQuery.type;
|
||||||
const teamId = requireTeamId(req?.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
const monitors = await this.monitorService.getMonitorsWithChecksByTeamId({
|
const monitors = await this.monitorService.getMonitorsWithChecksByTeamId({
|
||||||
teamId,
|
teamId,
|
||||||
@@ -392,11 +357,7 @@ class MonitorController {
|
|||||||
|
|
||||||
exportMonitorsToJSON = async (req: Request, res: Response, next: NextFunction) => {
|
exportMonitorsToJSON = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const teamId = req?.user?.teamId;
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
if (!teamId) {
|
|
||||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const json = await this.monitorService.exportMonitorsToJSON({ teamId });
|
const json = await this.monitorService.exportMonitorsToJSON({ teamId });
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
@@ -424,11 +385,7 @@ class MonitorController {
|
|||||||
|
|
||||||
getGroupsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
getGroupsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const teamId = req?.user?.teamId;
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
if (!teamId) {
|
|
||||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const groups = await this.monitorService.getGroupsByTeamId({ teamId });
|
const groups = await this.monitorService.getGroupsByTeamId({ teamId });
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
|
|
||||||
import { Notification } from "@/types/index.js";
|
import {
|
||||||
import { createNotificationBodyValidation } from "@/validation/notificationValidation.js";
|
createNotificationBodyValidation,
|
||||||
|
deleteNotificationParamValidation,
|
||||||
|
getNotificationByIdParamValidation,
|
||||||
|
testNotificationBodyValidation,
|
||||||
|
editNotificationParamValidation,
|
||||||
|
testAllNotificationsBodyValidation,
|
||||||
|
} from "@/validation/notificationValidation.js";
|
||||||
import { AppError } from "@/utils/AppError.js";
|
import { AppError } from "@/utils/AppError.js";
|
||||||
import { IMonitorsRepository } from "@/repositories/index.js";
|
import { IMonitorsRepository } from "@/repositories/index.js";
|
||||||
import { INotificationsService } from "@/service/index.js";
|
import { INotificationsService } from "@/service/index.js";
|
||||||
import { requireTeamId } from "./controllerUtils.js";
|
import { requireTeamId, requireUserId } from "./controllerUtils.js";
|
||||||
|
|
||||||
const SERVICE_NAME = "NotificationController";
|
const SERVICE_NAME = "NotificationController";
|
||||||
|
|
||||||
class NotificationController {
|
class NotificationController {
|
||||||
static SERVICE_NAME = SERVICE_NAME;
|
|
||||||
private notificationsService: INotificationsService;
|
private notificationsService: INotificationsService;
|
||||||
private monitorsRepository: IMonitorsRepository;
|
private monitorsRepository: IMonitorsRepository;
|
||||||
constructor(notificationsService: INotificationsService, monitorsRepository: IMonitorsRepository) {
|
constructor(notificationsService: INotificationsService, monitorsRepository: IMonitorsRepository) {
|
||||||
@@ -18,13 +23,9 @@ class NotificationController {
|
|||||||
this.monitorsRepository = monitorsRepository;
|
this.monitorsRepository = monitorsRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
get serviceName() {
|
|
||||||
return NotificationController.SERVICE_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
testNotification = async (req: Request, res: Response, next: NextFunction) => {
|
testNotification = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const notification: Notification = req.body;
|
const notification = testNotificationBodyValidation.parse(req.body);
|
||||||
const success = await this.notificationsService.sendTestNotification(notification);
|
const success = await this.notificationsService.sendTestNotification(notification);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -34,6 +35,7 @@ class NotificationController {
|
|||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
msg: "Notification sent successfully",
|
msg: "Notification sent successfully",
|
||||||
|
details: { service: SERVICE_NAME },
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
@@ -42,23 +44,12 @@ class NotificationController {
|
|||||||
|
|
||||||
createNotification = async (req: Request, res: Response, next: NextFunction) => {
|
createNotification = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
createNotificationBodyValidation.parse(req.body);
|
const validatedBody = createNotificationBodyValidation.parse(req.body);
|
||||||
|
|
||||||
const body = req.body;
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
const userId = requireUserId(req.user?.id);
|
||||||
|
|
||||||
const teamId = req?.user?.teamId;
|
const notification = await this.notificationsService.createNotification(validatedBody, userId, teamId);
|
||||||
if (!teamId) {
|
|
||||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const userId = req?.user?.id;
|
|
||||||
if (!userId) {
|
|
||||||
throw new AppError({ message: "User ID is required", status: 400 });
|
|
||||||
}
|
|
||||||
body.userId = userId;
|
|
||||||
body.teamId = teamId;
|
|
||||||
|
|
||||||
const notification = await this.notificationsService.createNotification(body);
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
msg: "Notification created successfully",
|
msg: "Notification created successfully",
|
||||||
@@ -71,11 +62,7 @@ class NotificationController {
|
|||||||
|
|
||||||
getNotificationsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
getNotificationsByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const teamId = req?.user?.teamId;
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
if (!teamId) {
|
|
||||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const notifications = await this.notificationsService.findNotificationsByTeamId(teamId);
|
const notifications = await this.notificationsService.findNotificationsByTeamId(teamId);
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
@@ -90,17 +77,10 @@ class NotificationController {
|
|||||||
|
|
||||||
deleteNotification = async (req: Request, res: Response, next: NextFunction) => {
|
deleteNotification = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const teamId = req?.user?.teamId;
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
if (!teamId) {
|
const validatedParams = deleteNotificationParamValidation.parse(req.params);
|
||||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const notificationId = req.params.id as string;
|
await this.notificationsService.deleteById(validatedParams.id, teamId);
|
||||||
if (!notificationId) {
|
|
||||||
throw new AppError({ message: "Notification ID is required", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.notificationsService.deleteById(notificationId, teamId);
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
msg: "Notification deleted successfully",
|
msg: "Notification deleted successfully",
|
||||||
@@ -113,12 +93,9 @@ class NotificationController {
|
|||||||
getNotificationById = async (req: Request, res: Response, next: NextFunction) => {
|
getNotificationById = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const teamId = requireTeamId(req.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const notificationId = req.params.id as string;
|
const validatedParams = getNotificationByIdParamValidation.parse(req.params);
|
||||||
if (!notificationId) {
|
|
||||||
throw new AppError({ message: "Notification ID is required", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const notification = await this.notificationsService.findById(notificationId, teamId);
|
const notification = await this.notificationsService.findById(validatedParams.id, teamId);
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -132,14 +109,13 @@ class NotificationController {
|
|||||||
|
|
||||||
editNotification = async (req: Request, res: Response, next: NextFunction) => {
|
editNotification = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
createNotificationBodyValidation.parse(req.body);
|
const validatedBody = createNotificationBodyValidation.parse(req.body);
|
||||||
|
const validatedParams = editNotificationParamValidation.parse(req.params);
|
||||||
|
|
||||||
const teamId = requireTeamId(req.user?.teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
const notificationId = req.params.id as string;
|
const notificationId = validatedParams.id;
|
||||||
if (!notificationId) {
|
|
||||||
throw new AppError({ message: "Notification ID is required", status: 400 });
|
const editedNotification = await this.notificationsService.updateById(notificationId, teamId, validatedBody);
|
||||||
}
|
|
||||||
const editedNotification = await this.notificationsService.updateById(notificationId, teamId, req.body);
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
msg: "Notification updated successfully",
|
msg: "Notification updated successfully",
|
||||||
@@ -152,13 +128,11 @@ class NotificationController {
|
|||||||
|
|
||||||
testAllNotifications = async (req: Request, res: Response, next: NextFunction) => {
|
testAllNotifications = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const monitorId = req.body.monitorId;
|
const validatedBody = testAllNotificationsBodyValidation.parse(req.body);
|
||||||
const teamId = req?.user?.teamId;
|
|
||||||
if (!teamId) {
|
|
||||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const monitor = await this.monitorsRepository.findById(monitorId, teamId);
|
const teamId = requireTeamId(req.user?.teamId);
|
||||||
|
|
||||||
|
const monitor = await this.monitorsRepository.findById(validatedBody.monitorId, teamId);
|
||||||
|
|
||||||
const notifications = monitor.notifications;
|
const notifications = monitor.notifications;
|
||||||
if (notifications.length === 0) {
|
if (notifications.length === 0) {
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ export interface IMaintenanceWindowsRepository {
|
|||||||
// fetch
|
// fetch
|
||||||
findById(id: string, teamId: string): Promise<MaintenanceWindow>;
|
findById(id: string, teamId: string): Promise<MaintenanceWindow>;
|
||||||
findByMonitorId(monitorId: string, teamId: string): Promise<MaintenanceWindow[]>;
|
findByMonitorId(monitorId: string, teamId: string): Promise<MaintenanceWindow[]>;
|
||||||
findByTeamId(teamId: string, active: boolean, page: number, rowsPerPage: number, field: string, order: string): Promise<MaintenanceWindow[]>;
|
findByTeamId(teamId: string, page: number, rowsPerPage: number, field?: string, order?: string, active?: boolean): Promise<MaintenanceWindow[]>;
|
||||||
|
|
||||||
// update
|
// update
|
||||||
updateById(id: string, teamId: string, data: Partial<MaintenanceWindow>): Promise<MaintenanceWindow>;
|
updateById(id: string, teamId: string, data: Partial<MaintenanceWindow>): Promise<MaintenanceWindow>;
|
||||||
// delete
|
// delete
|
||||||
deleteById(id: string, teamId: string): Promise<MaintenanceWindow>;
|
deleteById(id: string, teamId: string): Promise<MaintenanceWindow>;
|
||||||
// other
|
// other
|
||||||
countByTeamId(teamId: string, active: boolean): Promise<number>;
|
countByTeamId(teamId: string, active?: boolean): Promise<number>;
|
||||||
}
|
}
|
||||||
@@ -75,11 +75,11 @@ class MongoMaintenanceWindowsRepository implements IMaintenanceWindowsRepository
|
|||||||
|
|
||||||
findByTeamId = async (
|
findByTeamId = async (
|
||||||
teamId: string,
|
teamId: string,
|
||||||
active: boolean,
|
|
||||||
page: number,
|
page: number,
|
||||||
rowsPerPage: number,
|
rowsPerPage: number,
|
||||||
field: string,
|
field?: string,
|
||||||
order: string
|
order?: string,
|
||||||
|
active?: boolean
|
||||||
): Promise<MaintenanceWindow[]> => {
|
): Promise<MaintenanceWindow[]> => {
|
||||||
const maintenanceQuery: Record<string, any> = { teamId };
|
const maintenanceQuery: Record<string, any> = { teamId };
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ class MongoMaintenanceWindowsRepository implements IMaintenanceWindowsRepository
|
|||||||
}
|
}
|
||||||
return this.toEntity(deleted);
|
return this.toEntity(deleted);
|
||||||
};
|
};
|
||||||
countByTeamId = async (teamId: string, active: boolean) => {
|
countByTeamId = async (teamId: string, active?: boolean) => {
|
||||||
const maintenanceQuery: Record<string, any> = { teamId };
|
const maintenanceQuery: Record<string, any> = { teamId };
|
||||||
|
|
||||||
if (active !== undefined) maintenanceQuery.active = active;
|
if (active !== undefined) maintenanceQuery.active = active;
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ class MonitorRoutes {
|
|||||||
this.router.get("/export/json", isAllowed(["admin", "superadmin"]), this.monitorController.exportMonitorsToJSON);
|
this.router.get("/export/json", isAllowed(["admin", "superadmin"]), this.monitorController.exportMonitorsToJSON);
|
||||||
this.router.post("/import/json", isAllowed(["admin", "superadmin"]), this.monitorController.importMonitorsFromJSON);
|
this.router.post("/import/json", isAllowed(["admin", "superadmin"]), this.monitorController.importMonitorsFromJSON);
|
||||||
|
|
||||||
this.router.post("/test-email", isAllowed(["admin", "superadmin"]), this.monitorController.sendTestEmail);
|
|
||||||
this.router.get("/games", this.monitorController.getAllGames);
|
this.router.get("/games", this.monitorController.getAllGames);
|
||||||
|
|
||||||
// Individual monitor CRUD routes
|
// Individual monitor CRUD routes
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ const SERVICE_NAME = "incidentService";
|
|||||||
import type { Monitor } from "@/types/monitor.js";
|
import type { Monitor } from "@/types/monitor.js";
|
||||||
import type { MonitorStatusResponse } from "@/types/network.js";
|
import type { MonitorStatusResponse } from "@/types/network.js";
|
||||||
import { AppError } from "@/utils/AppError.js";
|
import { AppError } from "@/utils/AppError.js";
|
||||||
import { ParseBoolean } from "@/utils/utils.js";
|
|
||||||
import { getDateForRange } from "@/utils/dataUtils.js";
|
import { getDateForRange } from "@/utils/dataUtils.js";
|
||||||
import type { IIncidentsRepository, IMonitorsRepository, IUsersRepository } from "@/repositories/index.js";
|
import type { IIncidentsRepository, IMonitorsRepository, IUsersRepository } from "@/repositories/index.js";
|
||||||
import type { Incident, IncidentSummary, User } from "@/types/index.js";
|
import type { Incident, IncidentSummary, User } from "@/types/index.js";
|
||||||
@@ -22,13 +21,13 @@ export interface IIncidentService {
|
|||||||
teamId: string,
|
teamId: string,
|
||||||
sortOrder: string,
|
sortOrder: string,
|
||||||
dateRange: string,
|
dateRange: string,
|
||||||
page: string,
|
page: number,
|
||||||
rowsPerPage: string,
|
rowsPerPage: number,
|
||||||
status: string,
|
status: boolean | undefined,
|
||||||
monitorId: string,
|
monitorId: string | undefined,
|
||||||
resolutionType: string
|
resolutionType: string | undefined
|
||||||
): Promise<{ incidents: Incident[]; count: number }>;
|
): Promise<{ incidents: Incident[]; count: number }>;
|
||||||
getIncidentSummary(teamId: string, limit?: string): Promise<IncidentSummary>;
|
getIncidentSummary(teamId: string, limit?: number): Promise<IncidentSummary>;
|
||||||
getIncidentById(incidentId: string, teamId: string): Promise<{ incident: Incident; monitor: Monitor; user: User | null }>;
|
getIncidentById(incidentId: string, teamId: string): Promise<{ incident: Incident; monitor: Monitor; user: User | null }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,13 +163,13 @@ export class IncidentService implements IIncidentService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return resolvedIncident;
|
return resolvedIncident;
|
||||||
} catch (error: any) {
|
} catch (error: unknown) {
|
||||||
this.logger.error({
|
this.logger.error({
|
||||||
service: SERVICE_NAME,
|
service: SERVICE_NAME,
|
||||||
method: "resolveIncident",
|
method: "resolveIncident",
|
||||||
message: error.message,
|
message: error instanceof Error ? error.message : "Unknown error",
|
||||||
details: { id: incidentId },
|
details: { id: incidentId },
|
||||||
stack: error.stack,
|
stack: error instanceof Error ? error.stack : undefined,
|
||||||
});
|
});
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -180,11 +179,11 @@ export class IncidentService implements IIncidentService {
|
|||||||
teamId: string,
|
teamId: string,
|
||||||
sortOrder: string,
|
sortOrder: string,
|
||||||
dateRange: string,
|
dateRange: string,
|
||||||
page: string,
|
page: number,
|
||||||
rowsPerPage: string,
|
rowsPerPage: number,
|
||||||
status: string,
|
status: boolean | undefined,
|
||||||
monitorId: string,
|
monitorId: string | undefined,
|
||||||
resolutionType: string
|
resolutionType: string | undefined
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
if (!teamId) {
|
if (!teamId) {
|
||||||
@@ -193,9 +192,8 @@ export class IncidentService implements IIncidentService {
|
|||||||
|
|
||||||
const startDate = getDateForRange(dateRange);
|
const startDate = getDateForRange(dateRange);
|
||||||
|
|
||||||
const parsedPage = Number.isFinite(parseInt(page)) ? parseInt(page) : 0;
|
const parsedPage = page ?? 0;
|
||||||
const parsedRowsPerPage = Number.isFinite(parseInt(rowsPerPage)) ? parseInt(rowsPerPage) : 20;
|
const parsedRowsPerPage = rowsPerPage ?? 20;
|
||||||
const parsedStatus = typeof status === "undefined" ? undefined : ParseBoolean(status);
|
|
||||||
|
|
||||||
const incidents = await this.incidentsRepository.findByTeamId(
|
const incidents = await this.incidentsRepository.findByTeamId(
|
||||||
teamId,
|
teamId,
|
||||||
@@ -203,43 +201,43 @@ export class IncidentService implements IIncidentService {
|
|||||||
parsedPage,
|
parsedPage,
|
||||||
parsedRowsPerPage,
|
parsedRowsPerPage,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
parsedStatus,
|
status,
|
||||||
monitorId,
|
monitorId,
|
||||||
resolutionType
|
resolutionType
|
||||||
);
|
);
|
||||||
|
|
||||||
const count = await this.incidentsRepository.countByTeamId(teamId, startDate, parsedStatus, monitorId, resolutionType);
|
const count = await this.incidentsRepository.countByTeamId(teamId, startDate, status, monitorId, resolutionType);
|
||||||
|
|
||||||
return { incidents, count };
|
return { incidents, count };
|
||||||
} catch (error: any) {
|
} catch (error: unknown) {
|
||||||
this.logger.error({
|
this.logger.error({
|
||||||
service: SERVICE_NAME,
|
service: SERVICE_NAME,
|
||||||
method: "getIncidentsByTeam",
|
method: "getIncidentsByTeam",
|
||||||
message: error.message,
|
message: error instanceof Error ? error.message : "Unknown error",
|
||||||
details: { teamId },
|
details: { teamId },
|
||||||
stack: error.stack,
|
stack: error instanceof Error ? error.stack : undefined,
|
||||||
});
|
});
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getIncidentSummary = async (teamId: string, limit?: string) => {
|
getIncidentSummary = async (teamId: string, limit?: number) => {
|
||||||
try {
|
try {
|
||||||
if (!teamId) {
|
if (!teamId) {
|
||||||
throw new AppError({ message: "No team ID in request", service: SERVICE_NAME, method: "getIncidentSummary", status: 400 });
|
throw new AppError({ message: "No team ID in request", service: SERVICE_NAME, method: "getIncidentSummary", status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedLimit = limit && Number.isFinite(parseInt(limit, 10)) ? parseInt(limit, 10) : 10;
|
const parsedLimit = limit ?? 10;
|
||||||
const summary = await this.incidentsRepository.findSummaryByTeamId(teamId, parsedLimit);
|
const summary = await this.incidentsRepository.findSummaryByTeamId(teamId, parsedLimit);
|
||||||
|
|
||||||
return summary;
|
return summary;
|
||||||
} catch (error: any) {
|
} catch (error: unknown) {
|
||||||
this.logger.error({
|
this.logger.error({
|
||||||
service: SERVICE_NAME,
|
service: SERVICE_NAME,
|
||||||
method: "getIncidentSummary",
|
method: "getIncidentSummary",
|
||||||
message: error.message,
|
message: error instanceof Error ? error.message : "Unknown error",
|
||||||
details: { teamId },
|
details: { teamId },
|
||||||
stack: error.stack,
|
stack: error instanceof Error ? error.stack : undefined,
|
||||||
});
|
});
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -254,13 +252,13 @@ export class IncidentService implements IIncidentService {
|
|||||||
user = await this.usersRepository.findById(incident.resolvedBy);
|
user = await this.usersRepository.findById(incident.resolvedBy);
|
||||||
}
|
}
|
||||||
return { incident, monitor, user };
|
return { incident, monitor, user };
|
||||||
} catch (error: any) {
|
} catch (error: unknown) {
|
||||||
this.logger.error({
|
this.logger.error({
|
||||||
service: SERVICE_NAME,
|
service: SERVICE_NAME,
|
||||||
method: "getIncidentById",
|
method: "getIncidentById",
|
||||||
message: error.message,
|
message: error instanceof Error ? error.message : "Unknown error",
|
||||||
details: { incidentId },
|
details: { incidentId },
|
||||||
stack: error.stack,
|
stack: error instanceof Error ? error.stack : undefined,
|
||||||
});
|
});
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { IMaintenanceWindowsRepository, IMonitorsRepository } from "@/repositories/index.js";
|
import { IMaintenanceWindowsRepository, IMonitorsRepository } from "@/repositories/index.js";
|
||||||
import type { MaintenanceWindow } from "@/types/index.js";
|
import type { MaintenanceWindow } from "@/types/index.js";
|
||||||
import { ParseBoolean } from "@/utils/utils.js";
|
|
||||||
import { AppError } from "@/utils/AppError.js";
|
import { AppError } from "@/utils/AppError.js";
|
||||||
|
|
||||||
const SERVICE_NAME = "maintenanceWindowService";
|
const SERVICE_NAME = "maintenanceWindowService";
|
||||||
@@ -10,7 +9,11 @@ export interface IMaintenanceWindowService {
|
|||||||
getMaintenanceWindowById(params: { id: string; teamId: string }): Promise<MaintenanceWindow>;
|
getMaintenanceWindowById(params: { id: string; teamId: string }): Promise<MaintenanceWindow>;
|
||||||
getMaintenanceWindowsByTeamId(params: {
|
getMaintenanceWindowsByTeamId(params: {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
query: Record<string, string>;
|
active?: boolean;
|
||||||
|
page?: number;
|
||||||
|
rowsPerPage?: number;
|
||||||
|
field?: string;
|
||||||
|
order?: string;
|
||||||
}): Promise<{ maintenanceWindows: MaintenanceWindow[]; maintenanceWindowCount: number }>;
|
}): Promise<{ maintenanceWindows: MaintenanceWindow[]; maintenanceWindowCount: number }>;
|
||||||
getMaintenanceWindowsByMonitorId(params: { monitorId: string; teamId: string }): Promise<MaintenanceWindow[]>;
|
getMaintenanceWindowsByMonitorId(params: { monitorId: string; teamId: string }): Promise<MaintenanceWindow[]>;
|
||||||
deleteMaintenanceWindow(params: { id: string; teamId: string }): Promise<MaintenanceWindow>;
|
deleteMaintenanceWindow(params: { id: string; teamId: string }): Promise<MaintenanceWindow>;
|
||||||
@@ -72,14 +75,25 @@ export class MaintenanceWindowService implements IMaintenanceWindowService {
|
|||||||
return await this.maintenanceWindowsRepository.findById(id, teamId);
|
return await this.maintenanceWindowsRepository.findById(id, teamId);
|
||||||
};
|
};
|
||||||
|
|
||||||
getMaintenanceWindowsByTeamId = async ({ teamId, query }: { teamId: string; query: any }) => {
|
getMaintenanceWindowsByTeamId = async ({
|
||||||
let { active, page, rowsPerPage, field, order } = query || {};
|
teamId,
|
||||||
|
active,
|
||||||
|
page,
|
||||||
|
rowsPerPage,
|
||||||
|
field,
|
||||||
|
order,
|
||||||
|
}: {
|
||||||
|
teamId: string;
|
||||||
|
active?: boolean;
|
||||||
|
page?: number;
|
||||||
|
rowsPerPage?: number;
|
||||||
|
field?: string;
|
||||||
|
order?: string;
|
||||||
|
}) => {
|
||||||
|
page = page ?? 0;
|
||||||
|
rowsPerPage = rowsPerPage ?? 10;
|
||||||
|
|
||||||
active = typeof active === "undefined" ? undefined : ParseBoolean(active);
|
const maintenanceWindows = await this.maintenanceWindowsRepository.findByTeamId(teamId, page, rowsPerPage, field, order, active);
|
||||||
page = parseInt(page) || 0;
|
|
||||||
rowsPerPage = parseInt(rowsPerPage) || 10;
|
|
||||||
|
|
||||||
const maintenanceWindows = await this.maintenanceWindowsRepository.findByTeamId(teamId, active, page, rowsPerPage, field, order);
|
|
||||||
const maintenanceWindowCount = await this.maintenanceWindowsRepository.countByTeamId(teamId, active);
|
const maintenanceWindowCount = await this.maintenanceWindowsRepository.countByTeamId(teamId, active);
|
||||||
return { maintenanceWindows, maintenanceWindowCount };
|
return { maintenanceWindows, maintenanceWindowCount };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export interface IMonitorService {
|
|||||||
readonly serviceName: string;
|
readonly serviceName: string;
|
||||||
|
|
||||||
// create
|
// create
|
||||||
createMonitor(teamId: string, userId: string, body: Monitor): Promise<void>;
|
createMonitor(teamId: string, userId: string, body: Partial<Monitor>): Promise<void>;
|
||||||
createMonitors(monitors: Array<Monitor>, userId: string, teamId: string): Promise<Monitor[] | null>;
|
createMonitors(monitors: Array<Monitor>, userId: string, teamId: string): Promise<Monitor[] | null>;
|
||||||
addDemoMonitors(args: { userId: string; teamId: string }): Promise<Monitor[]>;
|
addDemoMonitors(args: { userId: string; teamId: string }): Promise<Monitor[]>;
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ export interface IMonitorService {
|
|||||||
getGroupsByTeamId(args: { teamId: string }): Promise<string[]>;
|
getGroupsByTeamId(args: { teamId: string }): Promise<string[]>;
|
||||||
|
|
||||||
// update
|
// update
|
||||||
editMonitor(args: { teamId: string; monitorId: string; body: Monitor }): Promise<Monitor>;
|
editMonitor(args: { teamId: string; monitorId: string; body: Partial<Monitor> }): Promise<Monitor>;
|
||||||
pauseMonitor(args: { teamId: string; monitorId: string }): Promise<Monitor>;
|
pauseMonitor(args: { teamId: string; monitorId: string }): Promise<Monitor>;
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
@@ -72,7 +72,6 @@ export interface IMonitorService {
|
|||||||
deleteAllMonitors(args: { teamId: string }): Promise<number>;
|
deleteAllMonitors(args: { teamId: string }): Promise<number>;
|
||||||
|
|
||||||
// other
|
// other
|
||||||
sendTestEmail(args: { to: string }): Promise<string>;
|
|
||||||
exportMonitorsToJSON(args: { teamId: string }): Promise<Monitor[]>;
|
exportMonitorsToJSON(args: { teamId: string }): Promise<Monitor[]>;
|
||||||
importMonitorsFromJSON(args: { teamId: string; userId: string; monitors: any[] }): Promise<{ imported: number; errors: string[] }>;
|
importMonitorsFromJSON(args: { teamId: string; userId: string; monitors: any[] }): Promise<{ imported: number; errors: string[] }>;
|
||||||
}
|
}
|
||||||
@@ -430,7 +429,7 @@ export class MonitorService implements IMonitorService {
|
|||||||
return groups;
|
return groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
editMonitor = async ({ teamId, monitorId, body }: { teamId: string; monitorId: string; body: Monitor }) => {
|
editMonitor = async ({ teamId, monitorId, body }: { teamId: string; monitorId: string; body: Partial<Monitor> }) => {
|
||||||
const editedMonitor = await this.monitorsRepository.updateById(monitorId, teamId, body);
|
const editedMonitor = await this.monitorsRepository.updateById(monitorId, teamId, body);
|
||||||
await this.jobQueue.updateJob(editedMonitor);
|
await this.jobQueue.updateJob(editedMonitor);
|
||||||
return editedMonitor;
|
return editedMonitor;
|
||||||
@@ -509,20 +508,6 @@ export class MonitorService implements IMonitorService {
|
|||||||
return deletedCount;
|
return deletedCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
sendTestEmail = async ({ to }: { to: string }): Promise<string> => {
|
|
||||||
const subject = "Test email from Checkmate";
|
|
||||||
const context = { testName: "Monitoring System" };
|
|
||||||
|
|
||||||
const html = await this.emailService.buildEmail("testEmailTemplate", context);
|
|
||||||
const messageId = await this.emailService.sendEmail(to, subject, html);
|
|
||||||
|
|
||||||
if (!messageId) {
|
|
||||||
throw new AppError({ message: "Failed to send test email.", service: SERVICE_NAME, method: "sendTestEmail", status: 500 });
|
|
||||||
}
|
|
||||||
|
|
||||||
return messageId;
|
|
||||||
};
|
|
||||||
|
|
||||||
exportMonitorsToJSON = async ({ teamId }: { teamId: string }): Promise<any[]> => {
|
exportMonitorsToJSON = async ({ teamId }: { teamId: string }): Promise<any[]> => {
|
||||||
const monitors = await this.monitorsRepository.findByTeamId(teamId, {});
|
const monitors = await this.monitorsRepository.findByTeamId(teamId, {});
|
||||||
|
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ import type { NotificationMessage } from "@/types/notificationMessage.js";
|
|||||||
|
|
||||||
export interface INotificationProvider {
|
export interface INotificationProvider {
|
||||||
sendMessage: (notification: Notification, message: NotificationMessage) => Promise<boolean>;
|
sendMessage: (notification: Notification, message: NotificationMessage) => Promise<boolean>;
|
||||||
sendTestAlert(notification: Notification): Promise<boolean>;
|
sendTestAlert(notification: Partial<Notification>): Promise<boolean>;
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ export class DiscordProvider implements INotificationProvider {
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendTestAlert = async (notification: Notification) => {
|
sendTestAlert = async (notification: Partial<Notification>) => {
|
||||||
if (!notification.address) {
|
if (!notification.address) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export class EmailProvider implements INotificationProvider {
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendTestAlert(notification: Notification): Promise<boolean> {
|
async sendTestAlert(notification: Partial<Notification>): Promise<boolean> {
|
||||||
const subject = "Test notification";
|
const subject = "Test notification";
|
||||||
const html = await buildTestEmail(this.emailService);
|
const html = await buildTestEmail(this.emailService);
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export class MatrixProvider implements INotificationProvider {
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendTestAlert = async (notification: Notification) => {
|
sendTestAlert = async (notification: Partial<Notification>) => {
|
||||||
const { homeserverUrl, accessToken, roomId } = notification;
|
const { homeserverUrl, accessToken, roomId } = notification;
|
||||||
if (!homeserverUrl || !accessToken || !roomId) {
|
if (!homeserverUrl || !accessToken || !roomId) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export class PagerDutyProvider implements INotificationProvider {
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendTestAlert(notification: Notification): Promise<boolean> {
|
async sendTestAlert(notification: Partial<Notification>): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
await got.post("https://events.pagerduty.com/v2/enqueue", {
|
await got.post("https://events.pagerduty.com/v2/enqueue", {
|
||||||
json: {
|
json: {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export class SlackProvider implements INotificationProvider {
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendTestAlert(notification: Notification): Promise<boolean> {
|
async sendTestAlert(notification: Partial<Notification>): Promise<boolean> {
|
||||||
if (!notification.address) {
|
if (!notification.address) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export class TeamsProvider implements INotificationProvider {
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendTestAlert(notification: Notification): Promise<boolean> {
|
async sendTestAlert(notification: Partial<Notification>): Promise<boolean> {
|
||||||
if (!notification.address) {
|
if (!notification.address) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export class WebhookProvider implements INotificationProvider {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
sendTestAlert = async (notification: Notification) => {
|
sendTestAlert = async (notification: Partial<Notification>) => {
|
||||||
if (!notification.address) {
|
if (!notification.address) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ import { ILogger } from "@/utils/logger.js";
|
|||||||
import type { INotificationMessageBuilder } from "@/service/infrastructure/notificationMessageBuilder.js";
|
import type { INotificationMessageBuilder } from "@/service/infrastructure/notificationMessageBuilder.js";
|
||||||
|
|
||||||
export interface INotificationsService {
|
export interface INotificationsService {
|
||||||
createNotification: (notificationData: Partial<Notification>) => Promise<Notification>;
|
createNotification: (notificationData: Partial<Notification>, userId: string, teamId: string) => Promise<Notification>;
|
||||||
findById: (id: string, teamId: string) => Promise<Notification>;
|
findById: (id: string, teamId: string) => Promise<Notification>;
|
||||||
findNotificationsByTeamId: (teamId: string) => Promise<Notification[]>;
|
findNotificationsByTeamId: (teamId: string) => Promise<Notification[]>;
|
||||||
updateById(id: string, teamId: string, updateData: Partial<Notification>): Promise<Notification>;
|
updateById(id: string, teamId: string, updateData: Partial<Notification>): Promise<Notification>;
|
||||||
deleteById: (id: string, teamId: string) => Promise<Notification>;
|
deleteById: (id: string, teamId: string) => Promise<Notification>;
|
||||||
handleNotifications: (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => Promise<boolean>;
|
handleNotifications: (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => Promise<boolean>;
|
||||||
|
|
||||||
sendTestNotification: (notification: Notification) => Promise<boolean>;
|
sendTestNotification: (notification: Partial<Notification>) => Promise<boolean>;
|
||||||
testAllNotifications: (notificationIds: string[]) => Promise<boolean>;
|
testAllNotifications: (notificationIds: string[]) => Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ export class NotificationsService implements INotificationsService {
|
|||||||
return await this.sendNotifications(monitor, monitorStatusResponse, decision);
|
return await this.sendNotifications(monitor, monitorStatusResponse, decision);
|
||||||
};
|
};
|
||||||
|
|
||||||
sendTestNotification = async (notification: Notification) => {
|
sendTestNotification = async (notification: Partial<Notification>) => {
|
||||||
switch (notification.type) {
|
switch (notification.type) {
|
||||||
case "email":
|
case "email":
|
||||||
return await this.emailProvider.sendTestAlert(notification);
|
return await this.emailProvider.sendTestAlert(notification);
|
||||||
@@ -174,7 +174,9 @@ export class NotificationsService implements INotificationsService {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
createNotification = async (notificationData: Partial<Notification>): Promise<Notification> => {
|
createNotification = async (notificationData: Partial<Notification>, userId: string, teamId: string): Promise<Notification> => {
|
||||||
|
notificationData.userId = userId;
|
||||||
|
notificationData.teamId = teamId;
|
||||||
return await this.notificationsRepository.create(notificationData);
|
return await this.notificationsRepository.create(notificationData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ export const supportsGeoCheck = (type: MonitorType): boolean => GeoCheckSupporte
|
|||||||
export const MonitorStatuses = ["up", "down", "paused", "initializing", "maintenance", "breached"] as const;
|
export const MonitorStatuses = ["up", "down", "paused", "initializing", "maintenance", "breached"] as const;
|
||||||
export type MonitorStatus = (typeof MonitorStatuses)[number];
|
export type MonitorStatus = (typeof MonitorStatuses)[number];
|
||||||
|
|
||||||
export type MonitorMatchMethod = "equal" | "include" | "regex" | "";
|
export const MonitorMatchMethods = ["equal", "include", "regex"] as const;
|
||||||
|
export type MonitorMatchMethod = (typeof MonitorMatchMethods)[number] | "";
|
||||||
|
|
||||||
export interface Monitor {
|
export interface Monitor {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
import { booleanCoercion } from "./shared.js";
|
||||||
|
|
||||||
|
//****************************************
|
||||||
|
// Incident Validations
|
||||||
|
//****************************************
|
||||||
|
|
||||||
|
export const getIncidentsByTeamQueryValidation = z.object({
|
||||||
|
sortOrder: z.enum(["asc", "desc"]),
|
||||||
|
dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]),
|
||||||
|
page: z.coerce.number().int().min(0),
|
||||||
|
rowsPerPage: z.coerce.number().int().min(1),
|
||||||
|
status: booleanCoercion.optional(),
|
||||||
|
monitorId: z.string().optional(),
|
||||||
|
resolutionType: z.enum(["manual", "automatic"]).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getIncidentSummaryQueryValidation = z.object({
|
||||||
|
limit: z.coerce.number().int().min(1).optional(),
|
||||||
|
});
|
||||||
@@ -20,3 +20,4 @@ export * from "./settingsValidation.js";
|
|||||||
export * from "./statusPageValidation.js";
|
export * from "./statusPageValidation.js";
|
||||||
export * from "./notificationValidation.js";
|
export * from "./notificationValidation.js";
|
||||||
export * from "./userValidation.js";
|
export * from "./userValidation.js";
|
||||||
|
export * from "./incidentValidation.js";
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { booleanCoercion } from "./shared.js";
|
import { booleanCoercion } from "./shared.js";
|
||||||
|
|
||||||
|
const dateToString = z.coerce.date().transform((d) => d.toISOString());
|
||||||
|
|
||||||
//****************************************
|
//****************************************
|
||||||
// Maintenance Window Validations
|
// Maintenance Window Validations
|
||||||
//****************************************
|
//****************************************
|
||||||
@@ -11,10 +13,10 @@ export const createMaintenanceWindowBodyValidation = z.object({
|
|||||||
active: z.boolean().optional(),
|
active: z.boolean().optional(),
|
||||||
duration: z.number().min(1, "Duration is required"),
|
duration: z.number().min(1, "Duration is required"),
|
||||||
durationUnit: z.enum(["seconds", "minutes", "hours", "days"]),
|
durationUnit: z.enum(["seconds", "minutes", "hours", "days"]),
|
||||||
start: z.coerce.date(),
|
start: dateToString,
|
||||||
end: z.coerce.date(),
|
end: dateToString,
|
||||||
repeat: z.number().min(0, "Repeat must be a non-negative number"),
|
repeat: z.number().min(0, "Repeat must be a non-negative number"),
|
||||||
expiry: z.coerce.date().optional(),
|
expiry: dateToString.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getMaintenanceWindowByIdParamValidation = z.object({
|
export const getMaintenanceWindowByIdParamValidation = z.object({
|
||||||
@@ -45,10 +47,10 @@ export const editMaintenanceByIdWindowBodyValidation = z.object({
|
|||||||
active: z.boolean().optional(),
|
active: z.boolean().optional(),
|
||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
repeat: z.number().optional(),
|
repeat: z.number().optional(),
|
||||||
start: z.coerce.date().optional(),
|
start: dateToString.optional(),
|
||||||
end: z.coerce.date().optional(),
|
end: dateToString.optional(),
|
||||||
expiry: z.coerce.date().optional(),
|
expiry: dateToString.optional(),
|
||||||
monitors: z.array(z.unknown()).optional(),
|
monitors: z.array(z.string()).optional(),
|
||||||
duration: z.number().optional(),
|
duration: z.number().optional(),
|
||||||
durationUnit: z.enum(["seconds", "minutes", "hours", "days"]).optional(),
|
durationUnit: z.enum(["seconds", "minutes", "hours", "days"]).optional(),
|
||||||
});
|
});
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { booleanCoercion } from "./shared.js";
|
import { booleanCoercion } from "./shared.js";
|
||||||
import { GeoContinents } from "@/types/geoCheck.js";
|
import { GeoContinents } from "@/types/geoCheck.js";
|
||||||
|
import { MonitorMatchMethods, MonitorTypes } from "@/types/monitor.js";
|
||||||
|
|
||||||
export const getMonitorByIdParamValidation = z.object({
|
export const getMonitorByIdParamValidation = z.object({
|
||||||
monitorId: z.string().min(1, "Monitor ID is required"),
|
monitorId: z.string().min(1, "Monitor ID is required"),
|
||||||
@@ -13,7 +14,7 @@ export const getMonitorByIdQueryValidation = z.object({
|
|||||||
dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).optional(),
|
dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).optional(),
|
||||||
numToDisplay: z.coerce.number().optional(),
|
numToDisplay: z.coerce.number().optional(),
|
||||||
normalize: booleanCoercion.optional(),
|
normalize: booleanCoercion.optional(),
|
||||||
continent: z.enum(GeoContinents).optional(),
|
continent: z.union([z.enum(GeoContinents), z.array(z.enum(GeoContinents))]).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getMonitorsByTeamIdParamValidation = z.object({});
|
export const getMonitorsByTeamIdParamValidation = z.object({});
|
||||||
@@ -25,14 +26,14 @@ export const getMonitorsByTeamIdQueryValidation = z.object({
|
|||||||
z.array(z.enum(["http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc", "websocket"])),
|
z.array(z.enum(["http", "ping", "pagespeed", "docker", "hardware", "port", "game", "grpc", "websocket"])),
|
||||||
])
|
])
|
||||||
.optional(),
|
.optional(),
|
||||||
filter: z.union([z.string(), z.literal(""), z.null()]).optional(),
|
filter: z.union([z.string(), z.literal("")]).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getMonitorsWithChecksQueryValidation = z.object({
|
export const getMonitorsWithChecksQueryValidation = z.object({
|
||||||
limit: z.coerce.number().int().min(1).max(100).optional(),
|
limit: z.coerce.number().int().min(1).max(100).optional(),
|
||||||
page: z.coerce.number().int().min(0).optional(),
|
page: z.coerce.number().int().min(0).optional(),
|
||||||
rowsPerPage: z.coerce.number().int().min(1).max(100).optional(),
|
rowsPerPage: z.coerce.number().int().min(1).max(100).optional(),
|
||||||
filter: z.union([z.string(), z.literal(""), z.null()]).optional(),
|
filter: z.union([z.string(), z.literal("")]).optional(),
|
||||||
field: z.string().optional(),
|
field: z.string().optional(),
|
||||||
order: z.enum(["asc", "desc"]).optional(),
|
order: z.enum(["asc", "desc"]).optional(),
|
||||||
type: z
|
type: z
|
||||||
@@ -51,8 +52,8 @@ export const getCertificateParamValidation = z.object({
|
|||||||
export const createMonitorBodyValidation = z.object({
|
export const createMonitorBodyValidation = z.object({
|
||||||
_id: z.string().optional(),
|
_id: z.string().optional(),
|
||||||
name: z.string().min(1, "Name is required"),
|
name: z.string().min(1, "Name is required"),
|
||||||
description: z.union([z.string(), z.null(), z.literal("")]).optional(),
|
description: z.union([z.string(), z.literal("")]).optional(),
|
||||||
type: z.string().min(1, "Type is required"),
|
type: z.enum(MonitorTypes, "Invalid monitor type"),
|
||||||
statusWindowSize: z.number().min(1).max(20).default(5),
|
statusWindowSize: z.number().min(1).max(20).default(5),
|
||||||
statusWindowThreshold: z.number().min(1).max(100).default(60),
|
statusWindowThreshold: z.number().min(1).max(100).default(60),
|
||||||
url: z.string().min(1, "URL is required"),
|
url: z.string().min(1, "URL is required"),
|
||||||
@@ -69,7 +70,7 @@ export const createMonitorBodyValidation = z.object({
|
|||||||
secret: z.string().optional(),
|
secret: z.string().optional(),
|
||||||
jsonPath: z.union([z.string(), z.literal("")]).optional(),
|
jsonPath: z.union([z.string(), z.literal("")]).optional(),
|
||||||
expectedValue: 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(),
|
matchMethod: z.union([z.enum(MonitorMatchMethods), z.literal("")]).optional(),
|
||||||
gameId: z.union([z.string(), z.literal("")]).optional(),
|
gameId: z.union([z.string(), z.literal("")]).optional(),
|
||||||
grpcServiceName: z.union([z.string(), z.literal("")]).default(""),
|
grpcServiceName: z.union([z.string(), z.literal("")]).default(""),
|
||||||
selectedDisks: z.array(z.string()).optional(),
|
selectedDisks: z.array(z.string()).optional(),
|
||||||
@@ -81,11 +82,11 @@ export const createMonitorBodyValidation = z.object({
|
|||||||
|
|
||||||
export const editMonitorBodyValidation = z.object({
|
export const editMonitorBodyValidation = z.object({
|
||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
type: z.string().optional(),
|
type: z.enum(MonitorTypes).optional(),
|
||||||
url: z.string().optional(),
|
url: z.string().optional(),
|
||||||
statusWindowSize: z.number().min(1).max(20).default(5),
|
statusWindowSize: z.number().min(1).max(20).default(5),
|
||||||
statusWindowThreshold: z.number().min(1).max(100).default(60),
|
statusWindowThreshold: z.number().min(1).max(100).default(60),
|
||||||
description: z.union([z.string(), z.null(), z.literal("")]).optional(),
|
description: z.union([z.string(), z.literal("")]).optional(),
|
||||||
interval: z.number().optional(),
|
interval: z.number().optional(),
|
||||||
notifications: z.array(z.string()).optional(),
|
notifications: z.array(z.string()).optional(),
|
||||||
secret: z.string().optional(),
|
secret: z.string().optional(),
|
||||||
@@ -93,7 +94,7 @@ export const editMonitorBodyValidation = z.object({
|
|||||||
useAdvancedMatching: z.boolean().optional(),
|
useAdvancedMatching: z.boolean().optional(),
|
||||||
jsonPath: z.union([z.string(), z.literal("")]).optional(),
|
jsonPath: z.union([z.string(), z.literal("")]).optional(),
|
||||||
expectedValue: 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(),
|
matchMethod: z.union([z.enum(MonitorMatchMethods), z.literal("")]).optional(),
|
||||||
port: z.number().min(1).max(65535).optional(),
|
port: z.number().min(1).max(65535).optional(),
|
||||||
cpuAlertThreshold: z.number().optional(),
|
cpuAlertThreshold: z.number().optional(),
|
||||||
memoryAlertThreshold: z.number().optional(),
|
memoryAlertThreshold: z.number().optional(),
|
||||||
@@ -112,6 +113,62 @@ export const pauseMonitorParamValidation = z.object({
|
|||||||
monitorId: z.string().min(1, "Monitor ID is required"),
|
monitorId: z.string().min(1, "Monitor ID is required"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const getUptimeDetailsByIdParamValidation = z.object({
|
||||||
|
monitorId: z.string().min(1, "Monitor ID is required"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getUptimeDetailsByIdQueryValidation = z.object({
|
||||||
|
dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]),
|
||||||
|
normalize: booleanCoercion.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const importedMonitorSchema = z.object({
|
||||||
|
id: z.string().optional(),
|
||||||
|
userId: z.string().optional(),
|
||||||
|
teamId: z.string().optional(),
|
||||||
|
name: z.string().min(1, "Name is required"),
|
||||||
|
description: z.union([z.string(), z.literal("")]).optional(),
|
||||||
|
status: z.enum(["up", "down", "paused", "initializing", "maintenance", "breached"]).optional(),
|
||||||
|
statusWindow: z.array(z.boolean()).optional(),
|
||||||
|
statusWindowSize: z.number().optional(),
|
||||||
|
statusWindowThreshold: z.number().optional(),
|
||||||
|
type: z.enum(MonitorTypes, "Invalid monitor type"),
|
||||||
|
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.enum(MonitorMatchMethods), z.literal("")]).optional(),
|
||||||
|
url: z.string().min(1, "URL is required"),
|
||||||
|
port: z.number().optional(),
|
||||||
|
isActive: z.boolean().optional(),
|
||||||
|
interval: z.number().optional(),
|
||||||
|
uptimePercentage: z.number().optional(),
|
||||||
|
notifications: z.array(z.string()).optional(),
|
||||||
|
secret: z.string().optional(),
|
||||||
|
cpuAlertThreshold: z.number().optional(),
|
||||||
|
cpuAlertCounter: z.number().optional(),
|
||||||
|
memoryAlertThreshold: z.number().optional(),
|
||||||
|
memoryAlertCounter: z.number().optional(),
|
||||||
|
diskAlertThreshold: z.number().optional(),
|
||||||
|
diskAlertCounter: z.number().optional(),
|
||||||
|
tempAlertThreshold: z.number().optional(),
|
||||||
|
tempAlertCounter: z.number().optional(),
|
||||||
|
selectedDisks: z.array(z.string()).optional(),
|
||||||
|
gameId: z.union([z.string(), z.literal("")]).optional(),
|
||||||
|
grpcServiceName: z.union([z.string(), z.literal("")]).optional(),
|
||||||
|
group: z.union([z.string(), z.null()]).optional(),
|
||||||
|
geoCheckEnabled: z.boolean().optional(),
|
||||||
|
geoCheckLocations: z.array(z.enum(GeoContinents)).optional(),
|
||||||
|
geoCheckInterval: z.number().optional(),
|
||||||
|
recentChecks: z.array(z.unknown()).optional(),
|
||||||
|
createdAt: z.string().optional(),
|
||||||
|
updatedAt: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const importMonitorsBodyValidation = z.object({
|
||||||
|
monitors: z.array(importedMonitorSchema).min(1, "At least one monitor is required"),
|
||||||
|
});
|
||||||
|
|
||||||
export const getHardwareDetailsByIdParamValidation = z.object({
|
export const getHardwareDetailsByIdParamValidation = z.object({
|
||||||
monitorId: z.string().min(1, "Monitor ID is required"),
|
monitorId: z.string().min(1, "Monitor ID is required"),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -67,6 +67,22 @@ export const createNotificationBodyValidation = z.discriminatedUnion("type", [
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export const testNotificationBodyValidation = createNotificationBodyValidation;
|
||||||
|
|
||||||
|
export const deleteNotificationParamValidation = z.object({
|
||||||
|
id: z.string().min(1, "Notification ID is required"),
|
||||||
|
});
|
||||||
|
export const getNotificationByIdParamValidation = z.object({
|
||||||
|
id: z.string().min(1, "Notification ID is required"),
|
||||||
|
});
|
||||||
|
export const editNotificationParamValidation = z.object({
|
||||||
|
id: z.string().min(1, "Notification ID is required"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const testAllNotificationsBodyValidation = z.object({
|
||||||
|
monitorId: z.string().min(1, "Monitor ID is required"),
|
||||||
|
});
|
||||||
|
|
||||||
export const sendTestEmailBodyValidation = z.object({
|
export const sendTestEmailBodyValidation = z.object({
|
||||||
to: z.string().min(1, "To field is required"),
|
to: z.string().min(1, "To field is required"),
|
||||||
systemEmailHost: z.string().optional(),
|
systemEmailHost: z.string().optional(),
|
||||||
|
|||||||
Reference in new issue
Block a user