remove mongo middleware
This commit is contained in:
1 parent
74a7f0a701
commit
68559741ba
19 files changed
+247
-141
No files matched your search
@@ -70,7 +70,7 @@ import SettingsModule from "../db/modules/settingsModule.js";
|
||||
import IncidentModule from "../db/modules/incidentModule.js";
|
||||
|
||||
// repositories
|
||||
import { MongoMonitorsRepository, MongoChecksRepository, MongoMonitorStatsRepository } from "@/repositories/index.js";
|
||||
import { MongoMonitorsRepository, MongoChecksRepository, MongoMonitorStatsRepository, MongoStatusPagesRepository } from "@/repositories/index.js";
|
||||
|
||||
export const initializeServices = async ({ logger, envSettings, settingsService }: { logger: any; envSettings: any; settingsService: any }) => {
|
||||
const serviceRegistry = new ServiceRegistry({ logger });
|
||||
@@ -124,6 +124,7 @@ export const initializeServices = async ({ logger, envSettings, settingsService
|
||||
const monitorsRepository = new MongoMonitorsRepository();
|
||||
const checksRepository = new MongoChecksRepository();
|
||||
const monitorStatsRepository = new MongoMonitorStatsRepository();
|
||||
const statusPagesRepository = new MongoStatusPagesRepository();
|
||||
|
||||
const networkService = new NetworkService({
|
||||
axios,
|
||||
@@ -217,7 +218,6 @@ export const initializeServices = async ({ logger, envSettings, settingsService
|
||||
errorService,
|
||||
});
|
||||
const monitorService = new MonitorService({
|
||||
db,
|
||||
jobQueue: superSimpleQueue,
|
||||
stringService,
|
||||
emailService,
|
||||
@@ -228,6 +228,7 @@ export const initializeServices = async ({ logger, envSettings, settingsService
|
||||
monitorsRepository,
|
||||
checksRepository,
|
||||
monitorStatsRepository,
|
||||
statusPagesRepository,
|
||||
});
|
||||
|
||||
const services = {
|
||||
|
||||
@@ -374,21 +374,6 @@ class MonitorController {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
exportMonitorsToCSV = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
||||
}
|
||||
|
||||
const csv = await this.monitorService.exportMonitorsToCSV({ teamId });
|
||||
res.setHeader("Content-Type", "text/csv");
|
||||
res.setHeader("Content-Disposition", "attachment; filename=monitors.csv");
|
||||
return res.send(csv);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
exportMonitorsToJSON = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
|
||||
@@ -171,35 +171,6 @@ const MonitorSchema = new Schema<MonitorDocument>(
|
||||
}
|
||||
);
|
||||
|
||||
MonitorSchema.pre("findOneAndDelete", async function (next) {
|
||||
try {
|
||||
const doc = await this.model.findOne(this.getFilter());
|
||||
|
||||
if (!doc) {
|
||||
throw new Error("Monitor not found");
|
||||
}
|
||||
|
||||
await Check.deleteMany({ monitorId: doc._id });
|
||||
await StatusPage.updateMany({ monitors: doc?._id }, { $pull: { monitors: doc?._id } });
|
||||
await MonitorStats.deleteMany({ monitorId: doc?._id.toString() });
|
||||
next();
|
||||
} catch (error) {
|
||||
next(error as Error);
|
||||
}
|
||||
});
|
||||
|
||||
MonitorSchema.pre("deleteMany", async function (next) {
|
||||
const filter = this.getFilter();
|
||||
const monitors = (await this.model.find(filter).select(["_id", "type"]).lean()) as { _id: Types.ObjectId }[];
|
||||
|
||||
for (const monitor of monitors) {
|
||||
await Check.deleteMany({ monitorId: monitor._id });
|
||||
await StatusPage.updateMany({ monitors: monitor._id }, { $pull: { monitors: monitor._id } });
|
||||
await MonitorStats.deleteMany({ monitorId: monitor._id.toString() });
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
MonitorSchema.pre("save", function (next) {
|
||||
if (!this.cpuAlertThreshold || this.isModified("alertThreshold")) {
|
||||
this.cpuAlertThreshold = this.alertThreshold;
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const StatusPageSchema = mongoose.Schema(
|
||||
{
|
||||
userId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "User",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
teamId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Team",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "uptime",
|
||||
enum: ["uptime"],
|
||||
},
|
||||
companyName: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "",
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
unique: true,
|
||||
required: true,
|
||||
default: "",
|
||||
},
|
||||
timezone: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "#4169E1",
|
||||
},
|
||||
monitors: [
|
||||
{
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
subMonitors: [
|
||||
{
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
logo: {
|
||||
data: Buffer,
|
||||
contentType: String,
|
||||
},
|
||||
isPublished: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showCharts: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showUptimePercentage: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showAdminLoginLink: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
customCSS: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
export default mongoose.model("StatusPage", StatusPageSchema);
|
||||
@@ -0,0 +1,112 @@
|
||||
import { Schema, model, type Types } from "mongoose";
|
||||
import type { StatusPage, StatusPageLogo } from "@/types/statusPage.js";
|
||||
import { StatusPageTypes } from "@/types/statusPage.js";
|
||||
|
||||
type StatusPageDocumentBase = Omit<StatusPage, "id" | "userId" | "teamId" | "monitors" | "subMonitors" | "originalMonitors" | "createdAt" | "updatedAt"> & {
|
||||
monitors: Types.ObjectId[];
|
||||
subMonitors: Types.ObjectId[];
|
||||
originalMonitors?: Types.ObjectId[];
|
||||
logo?: StatusPageLogo | null;
|
||||
};
|
||||
|
||||
interface StatusPageDocument extends StatusPageDocumentBase {
|
||||
_id: Types.ObjectId;
|
||||
userId: Types.ObjectId;
|
||||
teamId: Types.ObjectId;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const logoSchema = new Schema<StatusPageLogo & { data: Buffer }>(
|
||||
{
|
||||
data: { type: Buffer },
|
||||
contentType: { type: String },
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const StatusPageSchema = new Schema<StatusPageDocument>(
|
||||
{
|
||||
userId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "User",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "Team",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "uptime",
|
||||
enum: StatusPageTypes,
|
||||
},
|
||||
companyName: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "",
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
unique: true,
|
||||
required: true,
|
||||
default: "",
|
||||
},
|
||||
timezone: {
|
||||
type: String,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: "#4169E1",
|
||||
},
|
||||
monitors: [
|
||||
{
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
subMonitors: [
|
||||
{
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
logo: {
|
||||
type: logoSchema,
|
||||
default: null,
|
||||
},
|
||||
isPublished: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showCharts: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showUptimePercentage: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showAdminLoginLink: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
customCSS: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const StatusPageModel = model<StatusPageDocument>("StatusPage", StatusPageSchema);
|
||||
|
||||
export type { StatusPageDocument };
|
||||
export { StatusPageModel };
|
||||
export default StatusPageModel;
|
||||
@@ -6,3 +6,6 @@ export { default as CheckModel } from "@/db/models/Check.js";
|
||||
|
||||
export * from "@/db/models/MonitorStats.js";
|
||||
export { default as MonitorStatsModel } from "@/db/models/MonitorStats.js";
|
||||
|
||||
export * from "@/db/models/StatusPage.js";
|
||||
export { default as StatusPageModel } from "@/db/models/StatusPage.js";
|
||||
@@ -287,6 +287,7 @@ class StatusPageModule {
|
||||
deleteStatusPagesByMonitorId = async (monitorId) => {
|
||||
try {
|
||||
await this.StatusPage.deleteMany({ monitors: { $in: [monitorId] } });
|
||||
await this.StatusPage.deleteMany({ subMonitors: { $in: [monitorId] } });
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteStatusPageByMonitorId";
|
||||
|
||||
@@ -54,6 +54,9 @@ export interface UptimeChecksResult {
|
||||
}
|
||||
|
||||
export interface IChecksRepository {
|
||||
// create
|
||||
// single fetch
|
||||
// collection fetch
|
||||
findLatestChecksByMonitorIds(monitorIds: string[], options?: { limitPerMonitor?: number }): Promise<LatestChecksMap>;
|
||||
findDateRangeChecksByMonitor(
|
||||
monitorId: string,
|
||||
@@ -62,4 +65,7 @@ export interface IChecksRepository {
|
||||
dateString: string,
|
||||
options?: { type?: MonitorType }
|
||||
): Promise<UptimeChecksResult | HardwareChecksResult | PageSpeedChecksResult>;
|
||||
// update
|
||||
//delete
|
||||
deleteByMonitorId(monitorId: string): Promise<number>;
|
||||
}
|
||||
@@ -385,6 +385,11 @@ class MongoChecksRepository implements IChecksRepository {
|
||||
checks: checks.map((doc) => this.toEntity(doc)),
|
||||
};
|
||||
};
|
||||
|
||||
deleteByMonitorId = async (monitorId: string): Promise<number> => {
|
||||
const result = await CheckModel.deleteMany({ "metadata.monitorId": monitorId });
|
||||
return result.deletedCount;
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoChecksRepository;
|
||||
@@ -6,3 +6,6 @@ export { default as MongoChecksRepository } from "@/repositories/checks/MongoChe
|
||||
|
||||
export * from "@/repositories/monitor-stats/IMonitorStatsRepository.js";
|
||||
export { default as MongoMonitorStatsRepository } from "@/repositories/monitor-stats/MongoMonitorStatsRepository.js";
|
||||
|
||||
export * from "@/repositories/status-pages/IStatusPagesRepository.js";
|
||||
export { default as MongoStatusPagesRepository } from "@/repositories/status-pages/MongoStatusPagesRepository.js";
|
||||
@@ -5,5 +5,6 @@ export interface IMonitorStatsRepository {
|
||||
findByMonitorId(monitorId: string): Promise<MonitorStats>;
|
||||
// update
|
||||
// delete
|
||||
deleteByMonitorId(monitorId: string): Promise<MonitorStats>;
|
||||
// other
|
||||
}
|
||||
@@ -39,6 +39,14 @@ class MongoMonitorStatsRepository implements IMonitorStatsRepository {
|
||||
}
|
||||
return this.toEntity(monitorStats);
|
||||
};
|
||||
|
||||
deleteByMonitorId = async (monitorId: string) => {
|
||||
const deleted = await MonitorStatsModel.findOneAndDelete({ monitorId: new mongoose.Types.ObjectId(monitorId) });
|
||||
if (!deleted) {
|
||||
throw new AppError({ message: "Monitor stats not found", status: 404 });
|
||||
}
|
||||
return this.toEntity(deleted);
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoMonitorStatsRepository;
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MonitorModel } from "@/db/models/index.js";
|
||||
import type { MonitorDocument } from "@/db/models/index.js";
|
||||
import type { Monitor, MonitorType } from "@/types/index.js";
|
||||
import type { Monitor } from "@/types/index.js";
|
||||
import mongoose, { type FilterQuery } from "mongoose";
|
||||
import type { IMonitorsRepository, TeamQueryConfig, SummaryConfig } from "./IMonitorsRepository.js";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { StatusPage } from "@/types/statusPage.js";
|
||||
|
||||
export interface IStatusPagesRepository {
|
||||
// create
|
||||
// single fetch
|
||||
// collection fetch
|
||||
// update
|
||||
// delete
|
||||
// other
|
||||
removeMonitorFromStatusPages(monitorId: string): Promise<number>;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { IStatusPagesRepository } from "@/repositories/index.js";
|
||||
import { type StatusPageDocument, StatusPageModel } from "@/db/models/StatusPage.js";
|
||||
import type { StatusPage } from "@/types/statusPage.js";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
class MongoStatusPagesRepository implements IStatusPagesRepository {
|
||||
private toEntity(doc: StatusPageDocument): StatusPage {
|
||||
const toStringId = (value: unknown): string => {
|
||||
if (value instanceof mongoose.Types.ObjectId) {
|
||||
return value.toString();
|
||||
}
|
||||
return value?.toString() ?? "";
|
||||
};
|
||||
|
||||
const toDateString = (value: Date | string): string => {
|
||||
return value instanceof Date ? value.toISOString() : value;
|
||||
};
|
||||
|
||||
const mapIdArray = (values?: mongoose.Types.ObjectId[]): string[] => {
|
||||
return values?.map((value) => toStringId(value)) ?? [];
|
||||
};
|
||||
|
||||
return {
|
||||
id: toStringId(doc._id),
|
||||
userId: toStringId(doc.userId),
|
||||
teamId: toStringId(doc.teamId),
|
||||
type: doc.type,
|
||||
companyName: doc.companyName,
|
||||
url: doc.url,
|
||||
timezone: doc.timezone ?? undefined,
|
||||
color: doc.color,
|
||||
monitors: mapIdArray(doc.monitors),
|
||||
subMonitors: mapIdArray(doc.subMonitors),
|
||||
originalMonitors: doc.originalMonitors?.map((value) => toStringId(value)),
|
||||
logo: doc.logo ?? undefined,
|
||||
isPublished: doc.isPublished,
|
||||
showCharts: doc.showCharts,
|
||||
showUptimePercentage: doc.showUptimePercentage,
|
||||
showAdminLoginLink: doc.showAdminLoginLink,
|
||||
customCSS: doc.customCSS,
|
||||
createdAt: toDateString(doc.createdAt),
|
||||
updatedAt: toDateString(doc.updatedAt),
|
||||
};
|
||||
}
|
||||
|
||||
removeMonitorFromStatusPages = async (monitorId: string): Promise<number> => {
|
||||
const res = await StatusPageModel.updateMany({ monitors: monitorId }, { $pull: { monitors: monitorId } });
|
||||
return res.modifiedCount;
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoStatusPagesRepository;
|
||||
@@ -43,7 +43,6 @@ class MonitorRoutes {
|
||||
|
||||
// Other static routes
|
||||
this.router.post("/demo", isAllowed(["admin", "superadmin"]), this.monitorController.addDemoMonitors);
|
||||
this.router.get("/export", isAllowed(["admin", "superadmin"]), this.monitorController.exportMonitorsToCSV);
|
||||
this.router.get("/export/json", isAllowed(["admin", "superadmin"]), this.monitorController.exportMonitorsToJSON);
|
||||
this.router.post("/bulk", isAllowed(["admin", "superadmin"]), upload.single("csvFile"), this.monitorController.createBulkMonitors);
|
||||
this.router.post("/test-email", isAllowed(["admin", "superadmin"]), this.monitorController.sendTestEmail);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createMonitorsBodyValidation } from "@/validation/joi.js";
|
||||
import { NormalizeData, NormalizeDataUptimeDetails } from "@/utils/dataUtils.js";
|
||||
import { type Monitor } from "@/types/index.js";
|
||||
import type { MonitorType } from "@/types/monitor.js";
|
||||
import type { IChecksRepository, IMonitorsRepository, IMonitorStatsRepository } from "@/repositories/index.js";
|
||||
import type { IChecksRepository, IMonitorsRepository, IMonitorStatsRepository, IStatusPagesRepository } from "@/repositories/index.js";
|
||||
import fs from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
import path from "path";
|
||||
@@ -76,9 +76,9 @@ export class MonitorService implements IMonitorService {
|
||||
private monitorsRepository: IMonitorsRepository;
|
||||
private checksRepository: IChecksRepository;
|
||||
private monitorStatsRepository: IMonitorStatsRepository;
|
||||
private statusPagesRepository: IStatusPagesRepository;
|
||||
|
||||
constructor({
|
||||
db,
|
||||
jobQueue,
|
||||
stringService,
|
||||
emailService,
|
||||
@@ -89,8 +89,8 @@ export class MonitorService implements IMonitorService {
|
||||
monitorsRepository,
|
||||
checksRepository,
|
||||
monitorStatsRepository,
|
||||
statusPagesRepository,
|
||||
}: {
|
||||
db: any;
|
||||
jobQueue: any;
|
||||
stringService: any;
|
||||
emailService: any;
|
||||
@@ -101,8 +101,8 @@ export class MonitorService implements IMonitorService {
|
||||
monitorsRepository: IMonitorsRepository;
|
||||
checksRepository: IChecksRepository;
|
||||
monitorStatsRepository: IMonitorStatsRepository;
|
||||
statusPagesRepository: IStatusPagesRepository;
|
||||
}) {
|
||||
this.db = db;
|
||||
this.jobQueue = jobQueue;
|
||||
this.stringService = stringService;
|
||||
this.emailService = emailService;
|
||||
@@ -113,6 +113,7 @@ export class MonitorService implements IMonitorService {
|
||||
this.monitorsRepository = monitorsRepository;
|
||||
this.checksRepository = checksRepository;
|
||||
this.monitorStatsRepository = monitorStatsRepository;
|
||||
this.statusPagesRepository = statusPagesRepository;
|
||||
}
|
||||
|
||||
get serviceName(): string {
|
||||
@@ -428,8 +429,10 @@ export class MonitorService implements IMonitorService {
|
||||
|
||||
deleteMonitor = async ({ teamId, monitorId }: { teamId: string; monitorId: string }): Promise<Monitor> => {
|
||||
const monitor = await this.monitorsRepository.deleteById(monitorId, teamId);
|
||||
await this.monitorStatsRepository.deleteByMonitorId(monitor.id);
|
||||
await this.checksRepository.deleteByMonitorId(monitor.id);
|
||||
await this.statusPagesRepository.removeMonitorFromStatusPages(monitor.id);
|
||||
await this.jobQueue.deleteJob(monitor);
|
||||
await this.db.statusPageModule.deleteStatusPagesByMonitorId(monitor.id);
|
||||
return monitor;
|
||||
};
|
||||
|
||||
@@ -439,9 +442,9 @@ export class MonitorService implements IMonitorService {
|
||||
monitors.map(async (monitor) => {
|
||||
try {
|
||||
await this.jobQueue.deleteJob(monitor);
|
||||
await this.db.checkModule.deleteChecks(monitor.id);
|
||||
await this.db.pageSpeedCheckModule.deletePageSpeedChecksByMonitorId(monitor.id);
|
||||
await this.db.notificationsModule.deleteNotificationsByMonitorId(monitor.id);
|
||||
await this.checksRepository.deleteByMonitorId(monitor.id);
|
||||
await this.statusPagesRepository.removeMonitorFromStatusPages(monitor.id);
|
||||
await this.monitorStatsRepository.deleteByMonitorId(monitor.id);
|
||||
} catch (error: any) {
|
||||
this.logger.warn({
|
||||
message: `Error deleting associated records for monitor ${monitor.id} with name ${monitor.name}`,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "@/types/check.js";
|
||||
export * from "@/types/monitor.js";
|
||||
export * from "@/types/monitorStats.js";
|
||||
export * from "@/types/statusPage.js";
|
||||
@@ -0,0 +1,29 @@
|
||||
export const StatusPageTypes = ["uptime"] as const;
|
||||
export type StatusPageType = (typeof StatusPageTypes)[number];
|
||||
|
||||
export interface StatusPageLogo {
|
||||
data: Buffer;
|
||||
contentType: string;
|
||||
}
|
||||
|
||||
export interface StatusPage {
|
||||
id: string;
|
||||
userId: string;
|
||||
teamId: string;
|
||||
type: StatusPageType;
|
||||
companyName: string;
|
||||
url: string;
|
||||
timezone?: string;
|
||||
color: string;
|
||||
monitors: string[];
|
||||
subMonitors: string[];
|
||||
originalMonitors?: string[];
|
||||
logo?: StatusPageLogo | null;
|
||||
isPublished: boolean;
|
||||
showCharts: boolean;
|
||||
showUptimePercentage: boolean;
|
||||
showAdminLoginLink: boolean;
|
||||
customCSS: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
Reference in new issue
Block a user