initial commit
This commit is contained in:
1 parent
2d023de568
commit
42fdc47d86
14 files changed
+530
No files matched your search
@@ -0,0 +1,57 @@
|
||||
export const GeoContinents = ["EU", "NA", "AS", "SA", "AF", "OC"] as const;
|
||||
export type GeoContinent = (typeof GeoContinents)[number];
|
||||
|
||||
export interface GeoCheckMetadata {
|
||||
monitorId: string;
|
||||
teamId: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface GeoCheckTimings {
|
||||
total: number;
|
||||
dns: number;
|
||||
tcp: number;
|
||||
tls: number;
|
||||
firstByte: number;
|
||||
download: number;
|
||||
}
|
||||
|
||||
export interface GeoCheckLocation {
|
||||
continent: GeoContinent;
|
||||
region: string;
|
||||
country: string;
|
||||
state: string;
|
||||
city: string;
|
||||
longitude: number;
|
||||
latitude: number;
|
||||
}
|
||||
|
||||
export interface GeoCheckResult {
|
||||
location: GeoCheckLocation;
|
||||
status: boolean;
|
||||
statusCode: number;
|
||||
timings: GeoCheckTimings;
|
||||
}
|
||||
|
||||
export interface GeoCheck {
|
||||
id: string;
|
||||
metadata: GeoCheckMetadata;
|
||||
results: GeoCheckResult[];
|
||||
expiry: string;
|
||||
__v: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface GroupedGeoCheck {
|
||||
bucketDate: string;
|
||||
continent: GeoContinent;
|
||||
avgResponseTime: number;
|
||||
totalChecks: number;
|
||||
uptimePercentage: number;
|
||||
}
|
||||
|
||||
export interface GeoChecksResult {
|
||||
monitorType: string;
|
||||
groupedGeoChecks: GroupedGeoCheck[];
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { GroupedCheck, CheckSnapshot } from "@/Types/Check";
|
||||
import type { PageSpeedGroupedCheck } from "@/Types/Check";
|
||||
import type { GeoContinent } from "@/Types/GeoCheck";
|
||||
export type { GeoContinent } from "@/Types/GeoCheck";
|
||||
|
||||
export const MonitorTypes = [
|
||||
"http",
|
||||
@@ -59,6 +61,9 @@ export interface Monitor {
|
||||
selectedDisks: string[];
|
||||
gameId?: string;
|
||||
group: string | null;
|
||||
geoCheckEnabled?: boolean;
|
||||
geoCheckLocations?: GeoContinent[];
|
||||
geoCheckInterval?: number;
|
||||
recentChecks: CheckSnapshot[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { z } from "zod";
|
||||
import { GeoContinents } from "@/Types/GeoCheck";
|
||||
|
||||
// URL schema with custom error message
|
||||
const urlSchema = z.url({ message: "Please enter a valid URL" });
|
||||
@@ -20,6 +21,12 @@ const baseSchema = z.object({
|
||||
.number({ message: "Threshold percentage is required" })
|
||||
.min(1, "Incident percentage must be at least 1")
|
||||
.max(100, "Incident percentage must be at most 100"),
|
||||
geoCheckEnabled: z.boolean().optional(),
|
||||
geoCheckLocations: z.array(z.enum(GeoContinents)).optional(),
|
||||
geoCheckInterval: z
|
||||
.number()
|
||||
.min(300000, "Interval must be at least 5 minutes")
|
||||
.optional(),
|
||||
});
|
||||
|
||||
// HTTP monitor schema
|
||||
|
||||
@@ -46,6 +46,7 @@ import jmespath from "jmespath";
|
||||
import {
|
||||
MongoMonitorsRepository,
|
||||
MongoChecksRepository,
|
||||
MongoGeoChecksRepository,
|
||||
MongoMonitorStatsRepository,
|
||||
MongoStatusPagesRepository,
|
||||
MongoUsersRepository,
|
||||
@@ -57,6 +58,7 @@ import {
|
||||
MongoMaintenanceWindowsRepository,
|
||||
IMonitorsRepository,
|
||||
IChecksRepository,
|
||||
IGeoChecksRepository,
|
||||
IMonitorStatsRepository,
|
||||
IStatusPagesRepository,
|
||||
IUsersRepository,
|
||||
@@ -94,6 +96,7 @@ export type InitializedServices = {
|
||||
// Repositories
|
||||
monitorsRepository: IMonitorsRepository;
|
||||
checksRepository: IChecksRepository;
|
||||
geoChecksRepository: IGeoChecksRepository;
|
||||
monitorStatsRepository: IMonitorStatsRepository;
|
||||
statusPagesRepository: IStatusPagesRepository;
|
||||
usersRepository: IUsersRepository;
|
||||
@@ -126,6 +129,7 @@ export const initializeServices = async ({
|
||||
// Repositories
|
||||
const monitorsRepository = new MongoMonitorsRepository();
|
||||
const checksRepository = new MongoChecksRepository(logger);
|
||||
const geoChecksRepository = new MongoGeoChecksRepository(logger);
|
||||
const monitorStatsRepository = new MongoMonitorStatsRepository();
|
||||
const statusPagesRepository = new MongoStatusPagesRepository();
|
||||
const usersRepository = new MongoUsersRepository();
|
||||
@@ -278,6 +282,7 @@ export const initializeServices = async ({
|
||||
// Repositories
|
||||
monitorsRepository,
|
||||
checksRepository,
|
||||
geoChecksRepository,
|
||||
monitorStatsRepository,
|
||||
statusPagesRepository,
|
||||
usersRepository,
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
import { Schema, model, Types } from "mongoose";
|
||||
import { MonitorTypes, type MonitorType } from "@/types/monitor.js";
|
||||
import type { GeoCheck, GeoCheckLocation, GeoCheckMetadata, GeoCheckResult, GeoCheckTimings } from "@/types/geoCheck.js";
|
||||
|
||||
type GeoCheckMetadataDocument = Omit<GeoCheckMetadata, "monitorId" | "teamId"> & {
|
||||
monitorId: Types.ObjectId;
|
||||
teamId: Types.ObjectId;
|
||||
type: MonitorType;
|
||||
};
|
||||
|
||||
type GeoCheckDocumentBase = Omit<GeoCheck, "id" | "metadata" | "expiry" | "createdAt" | "updatedAt" | "results"> & {
|
||||
metadata: GeoCheckMetadataDocument;
|
||||
results: GeoCheckResult[];
|
||||
expiry: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
__v: number;
|
||||
};
|
||||
|
||||
export interface GeoCheckDocument extends GeoCheckDocumentBase {
|
||||
_id: Types.ObjectId;
|
||||
}
|
||||
|
||||
const geoCheckMetadataSchema = new Schema<GeoCheckMetadataDocument>(
|
||||
{
|
||||
monitorId: { type: Schema.Types.ObjectId, required: true, index: true },
|
||||
teamId: { type: Schema.Types.ObjectId, required: true, index: true },
|
||||
type: { type: String, required: true, enum: MonitorTypes },
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const geoCheckTimingsSchema = new Schema<GeoCheckTimings>(
|
||||
{
|
||||
total: { type: Number, default: 0 },
|
||||
dns: { type: Number, default: 0 },
|
||||
tcp: { type: Number, default: 0 },
|
||||
tls: { type: Number, default: 0 },
|
||||
firstByte: { type: Number, default: 0 },
|
||||
download: { type: Number, default: 0 },
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const geoCheckLocationSchema = new Schema<GeoCheckLocation>(
|
||||
{
|
||||
continent: { type: String, required: true },
|
||||
region: { type: String, default: "" },
|
||||
country: { type: String, default: "" },
|
||||
state: { type: String, default: "" },
|
||||
city: { type: String, default: "" },
|
||||
longitude: { type: Number, default: 0 },
|
||||
latitude: { type: Number, default: 0 },
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const geoCheckResultSchema = new Schema<GeoCheckResult>(
|
||||
{
|
||||
location: {
|
||||
type: geoCheckLocationSchema,
|
||||
required: true,
|
||||
},
|
||||
status: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
statusCode: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
timings: {
|
||||
type: geoCheckTimingsSchema,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const GeoCheckSchema = new Schema<GeoCheckDocument>(
|
||||
{
|
||||
metadata: {
|
||||
type: geoCheckMetadataSchema,
|
||||
required: true,
|
||||
},
|
||||
results: {
|
||||
type: [geoCheckResultSchema],
|
||||
required: true,
|
||||
default: [],
|
||||
},
|
||||
expiry: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
strict: false,
|
||||
timeseries: {
|
||||
timeField: "createdAt",
|
||||
metaField: "metadata",
|
||||
granularity: "seconds",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
GeoCheckSchema.index({ "metadata.monitorId": 1, createdAt: -1 });
|
||||
GeoCheckSchema.index({ "metadata.monitorId": 1, createdAt: 1 });
|
||||
GeoCheckSchema.index({ "metadata.monitorId": 1, "results.location.continent": 1, createdAt: -1 });
|
||||
GeoCheckSchema.index({ "metadata.teamId": 1, createdAt: -1 });
|
||||
GeoCheckSchema.index({ "metadata.teamId": 1, "results.status": 1, createdAt: -1 });
|
||||
GeoCheckSchema.index({ createdAt: 1 });
|
||||
|
||||
const GeoCheckModel = model<GeoCheckDocument>("GeoCheck", GeoCheckSchema);
|
||||
|
||||
export type { GeoCheckMetadataDocument };
|
||||
export { GeoCheckModel };
|
||||
export default GeoCheckModel;
|
||||
@@ -169,6 +169,18 @@ const MonitorSchema = new Schema<MonitorDocument>(
|
||||
return value && value.trim() ? value.trim() : null;
|
||||
},
|
||||
},
|
||||
geoCheckEnabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
geoCheckLocations: {
|
||||
type: [String],
|
||||
default: [],
|
||||
},
|
||||
geoCheckInterval: {
|
||||
type: Number,
|
||||
default: 300000,
|
||||
},
|
||||
recentChecks: {
|
||||
type: [checkSnapshotSchema],
|
||||
default: [],
|
||||
|
||||
@@ -33,3 +33,6 @@ export { default as TeamModel } from "@/db/models/Team.js";
|
||||
|
||||
export * from "@/db/models/MaintenanceWindow.js";
|
||||
export { default as MaintenanceWindowModel } from "@/db/models/MaintenanceWindow.js";
|
||||
|
||||
export * from "@/db/models/GeoCheck.js";
|
||||
export { default as GeoCheckModel } from "@/db/models/GeoCheck.js";
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { GeoCheck, GroupedGeoCheck } from "@/types/geoCheck.js";
|
||||
|
||||
export interface IGeoChecksRepository {
|
||||
create(geoCheck: Omit<GeoCheck, "id" | "__v" | "createdAt" | "updatedAt">): Promise<GeoCheck>;
|
||||
findByMonitorIdAndDateRange(monitorId: string, startDate: Date, endDate: Date): Promise<GeoCheck[]>;
|
||||
findGroupedByMonitorIdAndDateRange(monitorId: string, startDate: Date, endDate: Date, dateFormat: string): Promise<GroupedGeoCheck[]>;
|
||||
deleteByMonitorId(monitorId: string): Promise<number>;
|
||||
deleteByTeamId(teamId: string): Promise<number>;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
import { IGeoChecksRepository } from "./IGeoChecksRepository.js";
|
||||
import type { GeoCheck, GeoCheckMetadata, GeoCheckResult, GroupedGeoCheck } from "@/types/geoCheck.js";
|
||||
import { GeoCheckModel, type GeoCheckDocument } from "@/db/models/index.js";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const SERVICE_NAME = "GeoChecksRepository";
|
||||
|
||||
class MongoGeoChecksRepository implements IGeoChecksRepository {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
private logger: any;
|
||||
constructor(logger: any) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
private toEntity = (doc: GeoCheckDocument): GeoCheck => {
|
||||
const toStringId = (value: mongoose.Types.ObjectId | string | undefined | null): string => {
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
return value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);
|
||||
};
|
||||
|
||||
const toDateString = (value?: Date | string | null): string => {
|
||||
if (!value) {
|
||||
return new Date(0).toISOString();
|
||||
}
|
||||
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
||||
};
|
||||
|
||||
const mapMetadata = (metadata: any): GeoCheckMetadata => ({
|
||||
monitorId: toStringId(metadata.monitorId),
|
||||
teamId: toStringId(metadata.teamId),
|
||||
type: metadata.type,
|
||||
});
|
||||
|
||||
const mapResults = (results: any[]): GeoCheckResult[] => {
|
||||
if (!results || !Array.isArray(results)) {
|
||||
return [];
|
||||
}
|
||||
return results.map((result) => ({
|
||||
location: {
|
||||
continent: result.location?.continent ?? "",
|
||||
region: result.location?.region ?? "",
|
||||
country: result.location?.country ?? "",
|
||||
state: result.location?.state ?? "",
|
||||
city: result.location?.city ?? "",
|
||||
longitude: result.location?.longitude ?? 0,
|
||||
latitude: result.location?.latitude ?? 0,
|
||||
},
|
||||
status: result.status ?? false,
|
||||
statusCode: result.statusCode ?? 0,
|
||||
timings: {
|
||||
total: result.timings?.total ?? 0,
|
||||
dns: result.timings?.dns ?? 0,
|
||||
tcp: result.timings?.tcp ?? 0,
|
||||
tls: result.timings?.tls ?? 0,
|
||||
firstByte: result.timings?.firstByte ?? 0,
|
||||
download: result.timings?.download ?? 0,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
return {
|
||||
id: toStringId(doc._id),
|
||||
metadata: mapMetadata(doc.metadata),
|
||||
results: mapResults(doc.results),
|
||||
expiry: toDateString(doc.expiry),
|
||||
__v: doc.__v ?? 0,
|
||||
createdAt: toDateString(doc.createdAt),
|
||||
updatedAt: toDateString(doc.updatedAt),
|
||||
};
|
||||
};
|
||||
|
||||
create = async (geoCheck: Omit<GeoCheck, "id" | "__v" | "createdAt" | "updatedAt">): Promise<GeoCheck> => {
|
||||
try {
|
||||
const doc = await GeoCheckModel.create({
|
||||
metadata: {
|
||||
monitorId: new mongoose.Types.ObjectId(geoCheck.metadata.monitorId),
|
||||
teamId: new mongoose.Types.ObjectId(geoCheck.metadata.teamId),
|
||||
type: geoCheck.metadata.type,
|
||||
},
|
||||
results: geoCheck.results,
|
||||
expiry: new Date(geoCheck.expiry),
|
||||
});
|
||||
return this.toEntity(doc);
|
||||
} catch (error: any) {
|
||||
this.logger.error({
|
||||
message: `Error creating geo check: ${error.message}`,
|
||||
service: SERVICE_NAME,
|
||||
method: "create",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
findByMonitorIdAndDateRange = async (monitorId: string, startDate: Date, endDate: Date): Promise<GeoCheck[]> => {
|
||||
try {
|
||||
const docs = await GeoCheckModel.find({
|
||||
"metadata.monitorId": new mongoose.Types.ObjectId(monitorId),
|
||||
createdAt: {
|
||||
$gte: startDate,
|
||||
$lte: endDate,
|
||||
},
|
||||
}).sort({ createdAt: -1 });
|
||||
return docs.map(this.toEntity);
|
||||
} catch (error: any) {
|
||||
this.logger.error({
|
||||
message: `Error finding geo checks by monitor ID and date range: ${error.message}`,
|
||||
service: SERVICE_NAME,
|
||||
method: "findByMonitorIdAndDateRange",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
findGroupedByMonitorIdAndDateRange = async (monitorId: string, startDate: Date, endDate: Date, dateFormat: string): Promise<GroupedGeoCheck[]> => {
|
||||
try {
|
||||
const pipeline: any[] = [
|
||||
// Match geo checks for this monitor in date range
|
||||
{
|
||||
$match: {
|
||||
"metadata.monitorId": new mongoose.Types.ObjectId(monitorId),
|
||||
createdAt: {
|
||||
$gte: startDate,
|
||||
$lte: endDate,
|
||||
},
|
||||
},
|
||||
},
|
||||
// Unwind the results array to process each location separately
|
||||
{
|
||||
$unwind: "$results",
|
||||
},
|
||||
// Group by date bucket and continent
|
||||
{
|
||||
$group: {
|
||||
_id: {
|
||||
bucketDate: {
|
||||
$dateToString: {
|
||||
format: dateFormat,
|
||||
date: "$createdAt",
|
||||
},
|
||||
},
|
||||
continent: "$results.location.continent",
|
||||
},
|
||||
avgResponseTime: { $avg: "$results.timings.total" },
|
||||
totalChecks: { $sum: 1 },
|
||||
upChecks: {
|
||||
$sum: {
|
||||
$cond: ["$results.status", 1, 0],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// Calculate uptime percentage
|
||||
{
|
||||
$project: {
|
||||
_id: 0,
|
||||
bucketDate: "$_id.bucketDate",
|
||||
continent: "$_id.continent",
|
||||
avgResponseTime: { $round: ["$avgResponseTime", 2] },
|
||||
totalChecks: 1,
|
||||
uptimePercentage: {
|
||||
$round: [
|
||||
{
|
||||
$multiply: [
|
||||
{
|
||||
$divide: ["$upChecks", "$totalChecks"],
|
||||
},
|
||||
100,
|
||||
],
|
||||
},
|
||||
2,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
// Sort by date and continent
|
||||
{
|
||||
$sort: {
|
||||
bucketDate: 1,
|
||||
continent: 1,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const results = await GeoCheckModel.aggregate(pipeline);
|
||||
return results as GroupedGeoCheck[];
|
||||
} catch (error: any) {
|
||||
this.logger.error({
|
||||
message: `Error finding grouped geo checks: ${error.message}`,
|
||||
service: SERVICE_NAME,
|
||||
method: "findGroupedByMonitorIdAndDateRange",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
deleteByMonitorId = async (monitorId: string): Promise<number> => {
|
||||
try {
|
||||
const result = await GeoCheckModel.deleteMany({
|
||||
"metadata.monitorId": new mongoose.Types.ObjectId(monitorId),
|
||||
});
|
||||
return result.deletedCount || 0;
|
||||
} catch (error: any) {
|
||||
this.logger.error({
|
||||
message: `Error deleting geo checks by monitor ID: ${error.message}`,
|
||||
service: SERVICE_NAME,
|
||||
method: "deleteByMonitorId",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
deleteByTeamId = async (teamId: string): Promise<number> => {
|
||||
try {
|
||||
const result = await GeoCheckModel.deleteMany({
|
||||
"metadata.teamId": new mongoose.Types.ObjectId(teamId),
|
||||
});
|
||||
return result.deletedCount || 0;
|
||||
} catch (error: any) {
|
||||
this.logger.error({
|
||||
message: `Error deleting geo checks by team ID: ${error.message}`,
|
||||
service: SERVICE_NAME,
|
||||
method: "deleteByTeamId",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { MongoGeoChecksRepository };
|
||||
export default MongoGeoChecksRepository;
|
||||
@@ -33,3 +33,6 @@ export { default as MongoTeamsRepository } from "@/repositories/teams/MongoTeams
|
||||
|
||||
export * from "@/repositories/maintenance-windows/IMaintenanceWindowsRepository.js";
|
||||
export { default as MongoMaintenanceWindowsRepository } from "@/repositories/maintenance-windows/MongoMaintenanceWindowsRepository.js";
|
||||
|
||||
export * from "@/repositories/geo-checks/IGeoChecksRepository.js";
|
||||
export { default as MongoGeoChecksRepository } from "@/repositories/geo-checks/MongoGeoChecksRepository.js";
|
||||
@@ -0,0 +1,59 @@
|
||||
import type { MonitorType } from "@/types/index.js";
|
||||
|
||||
export const GeoContinents = ["EU", "NA", "AS", "SA", "AF", "OC"] as const;
|
||||
export type GeoContinent = (typeof GeoContinents)[number];
|
||||
|
||||
export interface GeoCheckMetadata {
|
||||
monitorId: string;
|
||||
teamId: string;
|
||||
type: MonitorType;
|
||||
}
|
||||
|
||||
export interface GeoCheckTimings {
|
||||
total: number;
|
||||
dns: number;
|
||||
tcp: number;
|
||||
tls: number;
|
||||
firstByte: number;
|
||||
download: number;
|
||||
}
|
||||
|
||||
export interface GeoCheckLocation {
|
||||
continent: GeoContinent;
|
||||
region: string;
|
||||
country: string;
|
||||
state: string;
|
||||
city: string;
|
||||
longitude: number;
|
||||
latitude: number;
|
||||
}
|
||||
|
||||
export interface GeoCheckResult {
|
||||
location: GeoCheckLocation;
|
||||
status: boolean;
|
||||
statusCode: number;
|
||||
timings: GeoCheckTimings;
|
||||
}
|
||||
|
||||
export interface GeoCheck {
|
||||
id: string;
|
||||
metadata: GeoCheckMetadata;
|
||||
results: GeoCheckResult[];
|
||||
expiry: string;
|
||||
__v: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface GroupedGeoCheck {
|
||||
bucketDate: string;
|
||||
continent: GeoContinent;
|
||||
avgResponseTime: number;
|
||||
totalChecks: number;
|
||||
uptimePercentage: number;
|
||||
}
|
||||
|
||||
export interface GeoChecksResult {
|
||||
monitorType: Exclude<MonitorType, "hardware" | "pagespeed">;
|
||||
groupedGeoChecks: GroupedGeoCheck[];
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "@/types/check.js";
|
||||
export * from "@/types/geoCheck.js";
|
||||
export * from "@/types/monitor.js";
|
||||
export * from "@/types/monitorStats.js";
|
||||
export * from "@/types/statusPage.js";
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { CheckSnapshot } from "@/types/check.js";
|
||||
export type { CheckSnapshot } from "@/types/check.js";
|
||||
import type { GeoContinent } from "@/types/geoCheck.js";
|
||||
export type { GeoContinent } from "@/types/geoCheck.js";
|
||||
|
||||
export const MonitorTypes = ["http", "ping", "pagespeed", "hardware", "docker", "port", "game", "unknown"] as const;
|
||||
export type MonitorType = (typeof MonitorTypes)[number];
|
||||
@@ -43,6 +45,9 @@ export interface Monitor {
|
||||
selectedDisks: string[];
|
||||
gameId?: string;
|
||||
group: string | null;
|
||||
geoCheckEnabled?: boolean;
|
||||
geoCheckLocations?: GeoContinent[];
|
||||
geoCheckInterval?: number;
|
||||
recentChecks: CheckSnapshot[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import joi, { type CustomHelpers } from "joi";
|
||||
import { type UserRole, UserRoles } from "@/types/user.js";
|
||||
import { GeoContinents } from "@/types/geoCheck.js";
|
||||
|
||||
//****************************************
|
||||
// Custom Validators
|
||||
@@ -172,6 +173,12 @@ const createMonitorBodyValidation = joi.object({
|
||||
gameId: joi.string().allow(""),
|
||||
selectedDisks: joi.array().items(joi.string()).optional(),
|
||||
group: joi.string().max(50).trim().allow(null, "").optional(),
|
||||
geoCheckEnabled: joi.boolean().optional(),
|
||||
geoCheckLocations: joi
|
||||
.array()
|
||||
.items(joi.string().valid(...GeoContinents))
|
||||
.optional(),
|
||||
geoCheckInterval: joi.number().min(300000).optional(),
|
||||
});
|
||||
|
||||
const createMonitorsBodyValidation = joi.array().items(
|
||||
@@ -203,6 +210,12 @@ const editMonitorBodyValidation = joi
|
||||
gameId: joi.string().allow(""),
|
||||
selectedDisks: joi.array().items(joi.string()).optional(),
|
||||
group: joi.string().max(50).trim().allow(null, "").optional(),
|
||||
geoCheckEnabled: joi.boolean().optional(),
|
||||
geoCheckLocations: joi
|
||||
.array()
|
||||
.items(joi.string().valid(...GeoContinents))
|
||||
.optional(),
|
||||
geoCheckInterval: joi.number().min(300000).optional(),
|
||||
})
|
||||
.options({ stripUnknown: true });
|
||||
|
||||
|
||||
Reference in new issue
Block a user