Merge pull request #2654 from bluewave-labs/fix/mw-routes

fix: mw routes
This commit is contained in:
Alexander Holliday
2025-07-21 12:28:44 -07:00
committed by GitHub
5 changed files with 88 additions and 28 deletions

View File

@@ -22,8 +22,25 @@ class MaintenanceWindowController {
async (req, res, next) => {
await createMaintenanceWindowBodyValidation.validateAsync(req.body);
const { teamId } = req.user;
const teamId = req?.user?.teamId;
if (!teamId) {
throw new Error("Team ID is required");
}
const monitorIds = req.body.monitors;
const monitors = await this.db.getMonitorsByIds(monitorIds);
const unauthorizedMonitors = monitors.filter((monitor) => !monitor.teamId.equals(teamId));
if (unauthorizedMonitors.length > 0) {
const error = new Error("Unauthorized access to one or more monitors");
error.status = 403;
error.service = SERVICE_NAME;
error.method = "createMaintenanceWindows";
throw error;
}
const dbTransactions = monitorIds.map((monitorId) => {
return this.db.createMaintenanceWindow({
teamId,
@@ -48,7 +65,13 @@ class MaintenanceWindowController {
getMaintenanceWindowById = asyncHandler(
async (req, res, next) => {
await getMaintenanceWindowByIdParamValidation.validateAsync(req.params);
const maintenanceWindow = await this.db.getMaintenanceWindowById(req.params.id);
const teamId = req.user.teamId;
if (!teamId) {
throw new Error("Team ID is required");
}
const maintenanceWindow = await this.db.getMaintenanceWindowById({ id: req.params.id, teamId });
return res.success({
msg: this.stringService.maintenanceWindowGetById,
data: maintenanceWindow,
@@ -62,7 +85,12 @@ class MaintenanceWindowController {
async (req, res, next) => {
await getMaintenanceWindowsByTeamIdQueryValidation.validateAsync(req.query);
const { teamId } = req.user;
const teamId = req?.user?.teamId;
if (!teamId) {
throw new Error("Team ID is required");
}
const maintenanceWindows = await this.db.getMaintenanceWindowsByTeamId(teamId, req.query);
return res.success({
@@ -78,7 +106,14 @@ class MaintenanceWindowController {
async (req, res, next) => {
await getMaintenanceWindowsByMonitorIdParamValidation.validateAsync(req.params);
const maintenanceWindows = await this.db.getMaintenanceWindowsByMonitorId(req.params.monitorId);
const monitorId = req.params.monitorId;
const teamId = req?.user?.teamId;
if (!teamId) {
throw new Error("Team ID is required");
}
const maintenanceWindows = await this.db.getMaintenanceWindowsByMonitorId({ monitorId, teamId });
return res.success({
msg: this.stringService.maintenanceWindowGetByUser,
@@ -92,7 +127,13 @@ class MaintenanceWindowController {
deleteMaintenanceWindow = asyncHandler(
async (req, res, next) => {
await deleteMaintenanceWindowByIdParamValidation.validateAsync(req.params);
await this.db.deleteMaintenanceWindowById(req.params.id);
const teamId = req?.user?.teamId;
if (!teamId) {
throw new Error("Team ID is required");
}
await this.db.deleteMaintenanceWindowById({ id: req.params.id, teamId });
return res.success({
msg: this.stringService.maintenanceWindowDelete,
});
@@ -105,7 +146,14 @@ class MaintenanceWindowController {
async (req, res, next) => {
await editMaintenanceWindowByIdParamValidation.validateAsync(req.params);
await editMaintenanceByIdWindowBodyValidation.validateAsync(req.body);
const editedMaintenanceWindow = await this.db.editMaintenanceWindowById(req.params.id, req.body);
const teamId = req.user.teamId;
if (!teamId) {
throw new Error("Team ID is required");
}
const editedMaintenanceWindow = await this.db.editMaintenanceWindowById({ id: req.params.id, body: req.body, teamId });
return res.success({
msg: this.stringService.maintenanceWindowEdit,
data: editedMaintenanceWindow,

View File

@@ -34,10 +34,11 @@ const createMaintenanceWindow = async (maintenanceWindowData) => {
}
};
const getMaintenanceWindowById = async (maintenanceWindowId) => {
const getMaintenanceWindowById = async ({ id, teamId }) => {
try {
const maintenanceWindow = await MaintenanceWindow.findById({
_id: maintenanceWindowId,
const maintenanceWindow = await MaintenanceWindow.findOne({
_id: id,
teamId: teamId,
});
return maintenanceWindow;
} catch (error) {
@@ -95,10 +96,11 @@ const getMaintenanceWindowsByTeamId = async (teamId, query) => {
* @returns {Promise<Array<MaintenanceWindow>>} An array of MaintenanceWindow documents.
* @throws {Error} If there is an error retrieving the documents.
*/
const getMaintenanceWindowsByMonitorId = async (monitorId) => {
const getMaintenanceWindowsByMonitorId = async ({ monitorId, teamId }) => {
try {
const maintenanceWindows = await MaintenanceWindow.find({
monitorId: monitorId,
teamId: teamId,
});
return maintenanceWindows;
} catch (error) {
@@ -116,9 +118,9 @@ const getMaintenanceWindowsByMonitorId = async (monitorId) => {
* @returns {Promise<MaintenanceWindow>} The deleted MaintenanceWindow document.
* @throws {Error} If there is an error deleting the document.
*/
const deleteMaintenanceWindowById = async (maintenanceWindowId) => {
const deleteMaintenanceWindowById = async ({ id, teamId }) => {
try {
const maintenanceWindow = await MaintenanceWindow.findByIdAndDelete(maintenanceWindowId);
const maintenanceWindow = await MaintenanceWindow.findOneAndDelete({ _id: id, teamId });
return maintenanceWindow;
} catch (error) {
error.service = SERVICE_NAME;
@@ -167,9 +169,9 @@ const deleteMaintenanceWindowByUserId = async (userId) => {
}
};
const editMaintenanceWindowById = async (maintenanceWindowId, maintenanceWindowData) => {
const editMaintenanceWindowById = async ({ id, body, teamId }) => {
try {
const editedMaintenanceWindow = await MaintenanceWindow.findByIdAndUpdate(maintenanceWindowId, maintenanceWindowData, { new: true });
const editedMaintenanceWindow = await MaintenanceWindow.findByIdAndUpdate(id, body, { new: true });
return editedMaintenanceWindow;
} catch (error) {
error.service = SERVICE_NAME;

View File

@@ -461,6 +461,17 @@ const getMonitorById = async (monitorId) => {
}
};
const getMonitorsByIds = async (monitorIds) => {
try {
const objectIds = monitorIds.map((id) => new ObjectId(id));
return await Monitor.find({ _id: { $in: objectIds } }, { _id: 1, teamId: 1 }).lean();
} catch (error) {
error.service = SERVICE_NAME;
error.method = "getMonitorsByIds";
throw error;
}
};
const getMonitorsByTeamId = async ({ limit, type, page, rowsPerPage, filter, field, order, teamId }) => {
limit = parseInt(limit);
page = parseInt(page);
@@ -753,6 +764,7 @@ export {
getAllMonitorsWithUptimeStats,
getMonitorStatsById,
getMonitorById,
getMonitorsByIds,
getMonitorsByTeamId,
getMonitorsAndSummaryByTeamId,
getMonitorsWithChecksByTeamId,

View File

@@ -343,16 +343,17 @@ const startApp = async () => {
//routes
app.use("/api/v1/auth", authRoutes.getRouter());
app.use("/api/v1/settings", verifyJWT, settingsRoutes.getRouter());
app.use("/api/v1/invite", inviteRoutes.getRouter());
app.use("/api/v1/monitors", verifyJWT, monitorRoutes.getRouter());
app.use("/api/v1/checks", verifyJWT, checkRoutes.getRouter());
app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRoutes.getRouter());
app.use("/api/v1/queue", verifyJWT, queueRoutes.getRouter());
app.use("/api/v1/logs", verifyJWT, logRoutes.getRouter());
app.use("/api/v1/status-page", statusPageRoutes.getRouter());
app.use("/api/v1/notifications", verifyJWT, notificationRoutes.getRouter());
app.use("/api/v1/diagnostic", verifyJWT, diagnosticRoutes.getRouter());
app.use("/api/v1/invite", inviteRoutes.getRouter());
app.use("/api/v1/logs", verifyJWT, logRoutes.getRouter());
app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRoutes.getRouter());
app.use("/api/v1/monitors", verifyJWT, monitorRoutes.getRouter());
app.use("/api/v1/notifications", verifyJWT, notificationRoutes.getRouter());
app.use("/api/v1/queue", verifyJWT, queueRoutes.getRouter());
app.use("/api/v1/settings", verifyJWT, settingsRoutes.getRouter());
app.use("/api/v1/status-page", statusPageRoutes.getRouter());
app.use("/api/v1/health", (req, res) => {
res.json({
status: "OK",

View File

@@ -1,7 +1,4 @@
import { Router } from "express";
import { verifyOwnership } from "../middleware/verifyOwnership.js";
import { verifyTeamAccess } from "../middleware/verifyTeamAccess.js";
import Monitor from "../db/models/Monitor.js";
import MaintenanceWindow from "../db/models/MaintenanceWindow.js";
class MaintenanceWindowRoutes {
constructor(maintenanceWindowController) {
@@ -13,11 +10,11 @@ class MaintenanceWindowRoutes {
this.router.post("/", this.mwController.createMaintenanceWindows);
this.router.get("/team/", this.mwController.getMaintenanceWindowsByTeamId);
this.router.get("/monitor/:monitorId", verifyOwnership(Monitor, "monitorId"), this.mwController.getMaintenanceWindowsByMonitorId);
this.router.get("/monitor/:monitorId", this.mwController.getMaintenanceWindowsByMonitorId);
this.router.get("/:id", this.mwController.getMaintenanceWindowById);
this.router.put("/:id", verifyTeamAccess(MaintenanceWindow, "id"), this.mwController.editMaintenanceWindow);
this.router.delete("/:id", verifyTeamAccess(MaintenanceWindow, "id"), this.mwController.deleteMaintenanceWindow);
this.router.put("/:id", this.mwController.editMaintenanceWindow);
this.router.delete("/:id", this.mwController.deleteMaintenanceWindow);
}
getRouter() {