diff --git a/server/src/controllers/notificationController.ts b/server/src/controllers/notificationController.ts index 0cee3726e..770bdcff4 100644 --- a/server/src/controllers/notificationController.ts +++ b/server/src/controllers/notificationController.ts @@ -1,16 +1,21 @@ import { Request, Response, NextFunction } from "express"; -import { Notification } from "@/types/index.js"; -import { createNotificationBodyValidation } from "@/validation/notificationValidation.js"; +import { + createNotificationBodyValidation, + deleteNotificationParamValidation, + getNotificationByIdParamValidation, + testNotificationBodyValidation, + editNotificationParamValidation, + testAllNotificationsBodyValidation, +} from "@/validation/notificationValidation.js"; import { AppError } from "@/utils/AppError.js"; import { IMonitorsRepository } from "@/repositories/index.js"; import { INotificationsService } from "@/service/index.js"; -import { requireTeamId } from "./controllerUtils.js"; +import { requireTeamId, requireUserId } from "./controllerUtils.js"; const SERVICE_NAME = "NotificationController"; class NotificationController { - static SERVICE_NAME = SERVICE_NAME; private notificationsService: INotificationsService; private monitorsRepository: IMonitorsRepository; constructor(notificationsService: INotificationsService, monitorsRepository: IMonitorsRepository) { @@ -18,13 +23,9 @@ class NotificationController { this.monitorsRepository = monitorsRepository; } - get serviceName() { - return NotificationController.SERVICE_NAME; - } - testNotification = async (req: Request, res: Response, next: NextFunction) => { try { - const notification: Notification = req.body; + const notification = testNotificationBodyValidation.parse(req.body); const success = await this.notificationsService.sendTestNotification(notification); if (!success) { @@ -42,23 +43,12 @@ class NotificationController { createNotification = async (req: Request, res: Response, next: NextFunction) => { 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; - 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); + const notification = await this.notificationsService.createNotification(validatedBody, userId, teamId); return res.status(200).json({ success: true, msg: "Notification created successfully", @@ -71,11 +61,7 @@ class NotificationController { getNotificationsByTeamId = 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 teamId = requireTeamId(req.user?.teamId); const notifications = await this.notificationsService.findNotificationsByTeamId(teamId); return res.status(200).json({ @@ -90,17 +76,10 @@ class NotificationController { deleteNotification = 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 teamId = requireTeamId(req.user?.teamId); + const validatedParams = deleteNotificationParamValidation.parse(req.params); - const notificationId = req.params.id as string; - if (!notificationId) { - throw new AppError({ message: "Notification ID is required", status: 400 }); - } - - await this.notificationsService.deleteById(notificationId, teamId); + await this.notificationsService.deleteById(validatedParams.id, teamId); return res.status(200).json({ success: true, msg: "Notification deleted successfully", @@ -113,12 +92,9 @@ class NotificationController { getNotificationById = async (req: Request, res: Response, next: NextFunction) => { try { const teamId = requireTeamId(req.user?.teamId); - const notificationId = req.params.id as string; - if (!notificationId) { - throw new AppError({ message: "Notification ID is required", status: 400 }); - } + const validatedParams = getNotificationByIdParamValidation.parse(req.params); - const notification = await this.notificationsService.findById(notificationId, teamId); + const notification = await this.notificationsService.findById(validatedParams.id, teamId); return res.status(200).json({ success: true, @@ -132,14 +108,15 @@ class NotificationController { editNotification = async (req: Request, res: Response, next: NextFunction) => { try { - createNotificationBodyValidation.parse(req.body); + const validatedBody = createNotificationBodyValidation.parse(req.body); + const validatedParams = editNotificationParamValidation.parse(req.params); 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, req.body); + const editedNotification = await this.notificationsService.updateById(notificationId, teamId, validatedBody); return res.status(200).json({ success: true, msg: "Notification updated successfully", @@ -152,13 +129,11 @@ class NotificationController { testAllNotifications = async (req: Request, res: Response, next: NextFunction) => { try { - const monitorId = req.body.monitorId; - const teamId = req?.user?.teamId; - if (!teamId) { - throw new AppError({ message: "Team ID is required", status: 400 }); - } + const validatedBody = testAllNotificationsBodyValidation.parse(req.body); - 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; if (notifications.length === 0) { diff --git a/server/src/service/infrastructure/notificationsService.ts b/server/src/service/infrastructure/notificationsService.ts index ea7b78a4f..ffd12e86a 100644 --- a/server/src/service/infrastructure/notificationsService.ts +++ b/server/src/service/infrastructure/notificationsService.ts @@ -8,14 +8,14 @@ import { ILogger } from "@/utils/logger.js"; import type { INotificationMessageBuilder } from "@/service/infrastructure/notificationMessageBuilder.js"; export interface INotificationsService { - createNotification: (notificationData: Partial) => Promise; + createNotification: (notificationData: Partial, userId: string, teamId: string) => Promise; findById: (id: string, teamId: string) => Promise; findNotificationsByTeamId: (teamId: string) => Promise; updateById(id: string, teamId: string, updateData: Partial): Promise; deleteById: (id: string, teamId: string) => Promise; handleNotifications: (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => Promise; - sendTestNotification: (notification: Notification) => Promise; + sendTestNotification: (notification: Partial) => Promise; testAllNotifications: (notificationIds: string[]) => Promise; } @@ -174,7 +174,9 @@ export class NotificationsService implements INotificationsService { return true; }; - createNotification = async (notificationData: Partial): Promise => { + createNotification = async (notificationData: Partial, userId: string, teamId: string): Promise => { + notificationData.userId = userId; + notificationData.teamId = teamId; return await this.notificationsRepository.create(notificationData); }; diff --git a/server/src/validation/notificationValidation.ts b/server/src/validation/notificationValidation.ts index 5aa0b976e..9ae4e9fdc 100644 --- a/server/src/validation/notificationValidation.ts +++ b/server/src/validation/notificationValidation.ts @@ -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({ to: z.string().min(1, "To field is required"), systemEmailHost: z.string().optional(),