From b3f8d7723810ad39ca38aceb8b3ff66f3706c632 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 23 Jul 2025 15:14:47 -0700 Subject: [PATCH] add maintenance window service --- server/controllers/inviteController.js | 8 +-- .../maintenanceWindowController.js | 57 +++++------------ server/index.js | 22 ++++--- .../business/maintenanceWindowService.js | 64 +++++++++++++++++++ 4 files changed, 95 insertions(+), 56 deletions(-) create mode 100644 server/service/business/maintenanceWindowService.js diff --git a/server/controllers/inviteController.js b/server/controllers/inviteController.js index 06e38a2e2..75e98cb68 100755 --- a/server/controllers/inviteController.js +++ b/server/controllers/inviteController.js @@ -11,16 +11,10 @@ class InviteController { /** * Creates a new InviteController instance * @param {Object} dependencies - Dependencies injected into the controller - * @param {Object} dependencies.db - Database connection instance - * @param {Object} dependencies.settingsService - Service for managing application settings - * @param {Object} dependencies.emailService - Service for sending emails * @param {Object} dependencies.stringService - Service for internationalized strings * @param {Object} dependencies.inviteService - Service for invite-related operations */ - constructor({ db, settingsService, emailService, stringService, inviteService }) { - this.db = db; - this.settingsService = settingsService; - this.emailService = emailService; + constructor({ stringService, inviteService }) { this.stringService = stringService; this.inviteService = inviteService; } diff --git a/server/controllers/maintenanceWindowController.js b/server/controllers/maintenanceWindowController.js index 9807392cc..95349fa66 100755 --- a/server/controllers/maintenanceWindowController.js +++ b/server/controllers/maintenanceWindowController.js @@ -12,14 +12,15 @@ import { asyncHandler } from "../utils/errorUtils.js"; const SERVICE_NAME = "maintenanceWindowController"; class MaintenanceWindowController { - constructor(db, settingsService, stringService) { + constructor({ db, settingsService, stringService, maintenanceWindowService }) { this.db = db; this.settingsService = settingsService; this.stringService = stringService; + this.maintenanceWindowService = maintenanceWindowService; } createMaintenanceWindows = asyncHandler( - async (req, res, next) => { + async (req, res) => { await createMaintenanceWindowBodyValidation.validateAsync(req.body); const teamId = req?.user?.teamId; @@ -27,32 +28,7 @@ class MaintenanceWindowController { 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, - monitorId, - name: req.body.name, - active: req.body.active ? req.body.active : true, - repeat: req.body.repeat, - start: req.body.start, - end: req.body.end, - }); - }); - await Promise.all(dbTransactions); + await this.maintenanceWindowService.createMaintenanceWindow({ teamId, body: req.body }); return res.success({ msg: this.stringService.maintenanceWindowCreate, @@ -63,7 +39,7 @@ class MaintenanceWindowController { ); getMaintenanceWindowById = asyncHandler( - async (req, res, next) => { + async (req, res) => { await getMaintenanceWindowByIdParamValidation.validateAsync(req.params); const teamId = req.user.teamId; @@ -71,7 +47,8 @@ class MaintenanceWindowController { throw new Error("Team ID is required"); } - const maintenanceWindow = await this.db.getMaintenanceWindowById({ id: req.params.id, teamId }); + const maintenanceWindow = await this.maintenanceWindowService.getMaintenanceWindowById({ id: req.params.id, teamId }); + return res.success({ msg: this.stringService.maintenanceWindowGetById, data: maintenanceWindow, @@ -82,7 +59,7 @@ class MaintenanceWindowController { ); getMaintenanceWindowsByTeamId = asyncHandler( - async (req, res, next) => { + async (req, res) => { await getMaintenanceWindowsByTeamIdQueryValidation.validateAsync(req.query); const teamId = req?.user?.teamId; @@ -91,7 +68,7 @@ class MaintenanceWindowController { throw new Error("Team ID is required"); } - const maintenanceWindows = await this.db.getMaintenanceWindowsByTeamId(teamId, req.query); + const maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByTeamId({ teamId, query: req.query }); return res.success({ msg: this.stringService.maintenanceWindowGetByTeam, @@ -103,17 +80,15 @@ class MaintenanceWindowController { ); getMaintenanceWindowsByMonitorId = asyncHandler( - async (req, res, next) => { + async (req, res) => { await getMaintenanceWindowsByMonitorIdParamValidation.validateAsync(req.params); - 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 }); + const maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByMonitorId({ monitorId: req.params.monitorId, teamId }); return res.success({ msg: this.stringService.maintenanceWindowGetByUser, @@ -125,7 +100,7 @@ class MaintenanceWindowController { ); deleteMaintenanceWindow = asyncHandler( - async (req, res, next) => { + async (req, res) => { await deleteMaintenanceWindowByIdParamValidation.validateAsync(req.params); const teamId = req?.user?.teamId; @@ -133,7 +108,8 @@ class MaintenanceWindowController { throw new Error("Team ID is required"); } - await this.db.deleteMaintenanceWindowById({ id: req.params.id, teamId }); + await this.maintenanceWindowService.deleteMaintenanceWindow({ id: req.params.id, teamId }); + return res.success({ msg: this.stringService.maintenanceWindowDelete, }); @@ -143,7 +119,7 @@ class MaintenanceWindowController { ); editMaintenanceWindow = asyncHandler( - async (req, res, next) => { + async (req, res) => { await editMaintenanceWindowByIdParamValidation.validateAsync(req.params); await editMaintenanceByIdWindowBodyValidation.validateAsync(req.body); @@ -152,8 +128,7 @@ class MaintenanceWindowController { throw new Error("Team ID is required"); } - const editedMaintenanceWindow = await this.db.editMaintenanceWindowById({ id: req.params.id, body: req.body, teamId }); - + const editedMaintenanceWindow = await this.maintenanceWindowService.editMaintenanceWindow({ id: req.params.id, body: req.body, teamId }); return res.success({ msg: this.stringService.maintenanceWindowEdit, data: editedMaintenanceWindow, diff --git a/server/index.js b/server/index.js index 2a8b5259b..9c7778a99 100755 --- a/server/index.js +++ b/server/index.js @@ -62,6 +62,7 @@ import UserService from "./service/business/userService.js"; import CheckService from "./service/business/checkService.js"; import DiagnosticService from "./service/business/diagnosticService.js"; import InviteService from "./service/business/inviteService.js"; +import MaintenanceWindowService from "./service/business/maintenanceWindowService.js"; //Network service and dependencies import NetworkService from "./service/infrastructure/networkService.js"; @@ -205,6 +206,11 @@ const startApp = async () => { emailService, stringService, }); + const maintenanceWindowService = new MaintenanceWindowService({ + db, + settingsService, + stringService, + }); // const jobQueueHelper = new JobQueueHelper({ // redisService, // Queue, @@ -265,6 +271,8 @@ const startApp = async () => { ServiceRegistry.register(RedisService.SERVICE_NAME, redisService); ServiceRegistry.register(UserService.SERVICE_NAME, userService); ServiceRegistry.register(CheckService.SERVICE_NAME, checkService); + ServiceRegistry.register(InviteService.SERVICE_NAME, inviteService); + ServiceRegistry.register(MaintenanceWindowService.SERVICE_NAME, maintenanceWindowService); await translationService.initialize(); @@ -311,18 +319,16 @@ const startApp = async () => { }); const inviteController = new InviteController({ - db: ServiceRegistry.get(MongoDB.SERVICE_NAME), - settingsService: ServiceRegistry.get(SettingsService.SERVICE_NAME), - emailService: ServiceRegistry.get(EmailService.SERVICE_NAME), stringService: ServiceRegistry.get(StringService.SERVICE_NAME), inviteService, }); - const maintenanceWindowController = new MaintenanceWindowController( - ServiceRegistry.get(MongoDB.SERVICE_NAME), - ServiceRegistry.get(SettingsService.SERVICE_NAME), - ServiceRegistry.get(StringService.SERVICE_NAME) - ); + const maintenanceWindowController = new MaintenanceWindowController({ + db: ServiceRegistry.get(MongoDB.SERVICE_NAME), + settingsService: ServiceRegistry.get(SettingsService.SERVICE_NAME), + stringService: ServiceRegistry.get(StringService.SERVICE_NAME), + maintenanceWindowService: ServiceRegistry.get(MaintenanceWindowService.SERVICE_NAME), + }); const queueController = new QueueController(ServiceRegistry.get(JobQueue.SERVICE_NAME), ServiceRegistry.get(StringService.SERVICE_NAME)); diff --git a/server/service/business/maintenanceWindowService.js b/server/service/business/maintenanceWindowService.js new file mode 100644 index 000000000..6140a5682 --- /dev/null +++ b/server/service/business/maintenanceWindowService.js @@ -0,0 +1,64 @@ +const SERVICE_NAME = "maintenanceWindowService"; + +class MaintenanceWindowService { + static SERVICE_NAME = SERVICE_NAME; + constructor({ db, settingsService, stringService }) { + this.db = db; + this.settingsService = settingsService; + this.stringService = stringService; + } + + createMaintenanceWindow = async ({ teamId, body }) => { + const monitorIds = 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, + monitorId, + name: body.name, + active: body.active ? body.active : true, + repeat: body.repeat, + start: body.start, + end: body.end, + }); + }); + await Promise.all(dbTransactions); + }; + + getMaintenanceWindowById = async ({ id, teamId }) => { + const maintenanceWindow = await this.db.getMaintenanceWindowById({ id, teamId }); + return maintenanceWindow; + }; + + getMaintenanceWindowsByTeamId = async ({ teamId, query }) => { + const maintenanceWindows = await this.db.getMaintenanceWindowsByTeamId(teamId, query); + return maintenanceWindows; + }; + + getMaintenanceWindowsByMonitorId = async ({ monitorId, teamId }) => { + const maintenanceWindows = await this.db.getMaintenanceWindowsByMonitorId({ monitorId, teamId }); + return maintenanceWindows; + }; + + deleteMaintenanceWindow = async ({ id, teamId }) => { + await this.db.deleteMaintenanceWindowById({ id, teamId }); + }; + + editMaintenanceWindow = async ({ id, teamId, body }) => { + const editedMaintenanceWindow = await this.db.editMaintenanceWindowById({ id, body, teamId }); + return editedMaintenanceWindow; + }; +} + +export default MaintenanceWindowService;