mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-24 11:59:39 -05:00
refactor notifications service
This commit is contained in:
@@ -207,6 +207,7 @@ export const initializeServices = async ({
|
||||
|
||||
const notificationsService = new NotificationsService(
|
||||
notificationsRepository,
|
||||
monitorsRepository,
|
||||
webhookProvider,
|
||||
emailProvider,
|
||||
slackProvider,
|
||||
|
||||
@@ -5,17 +5,16 @@ import { createNotificationBodyValidation } from "@/validation/joi.js";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
import { IMonitorsRepository } from "@/repositories/index.js";
|
||||
import { INotificationsService } from "@/service/index.js";
|
||||
import { requireTeamId } from "./controllerUtils.js";
|
||||
|
||||
const SERVICE_NAME = "NotificationController";
|
||||
|
||||
class NotificationController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
private db: any;
|
||||
private notificationsService: INotificationsService;
|
||||
private monitorsRepository: IMonitorsRepository;
|
||||
constructor(notificationsService: INotificationsService, db: any, monitorsRepository: IMonitorsRepository) {
|
||||
constructor(notificationsService: INotificationsService, monitorsRepository: IMonitorsRepository) {
|
||||
this.notificationsService = notificationsService;
|
||||
this.db = db;
|
||||
this.monitorsRepository = monitorsRepository;
|
||||
}
|
||||
|
||||
@@ -61,7 +60,7 @@ class NotificationController {
|
||||
body.userId = userId;
|
||||
body.teamId = teamId;
|
||||
|
||||
const notification = await this.db.notificationModule.createNotification(body);
|
||||
const notification = await this.notificationsService.createNotification(body);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: "Notification created successfully",
|
||||
@@ -79,7 +78,7 @@ class NotificationController {
|
||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
||||
}
|
||||
|
||||
const notifications = await this.db.notificationModule.getNotificationsByTeamId(teamId);
|
||||
const notifications = await this.notificationsService.findNotificationsByTeamId(teamId);
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
@@ -98,12 +97,12 @@ class NotificationController {
|
||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
||||
}
|
||||
|
||||
const notification = await this.db.notificationModule.getNotificationById(req.params.id);
|
||||
if (!notification.teamId.equals(teamId)) {
|
||||
throw new AppError({ message: "Unauthorized", status: 403 });
|
||||
const notificationId = req.params.id;
|
||||
if (!notificationId) {
|
||||
throw new AppError({ message: "Notification ID is required", status: 400 });
|
||||
}
|
||||
|
||||
await this.db.notificationModule.deleteNotificationById(req.params.id);
|
||||
await this.notificationsService.deleteById(notificationId, teamId);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: "Notification deleted successfully",
|
||||
@@ -115,16 +114,14 @@ class NotificationController {
|
||||
|
||||
getNotificationById = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const notification = await this.db.notificationModule.getNotificationById(req.params.id);
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
||||
const teamId = requireTeamId(req.user?.teamId);
|
||||
const notificationId = req.params.id;
|
||||
if (!notificationId) {
|
||||
throw new AppError({ message: "Notification ID is required", status: 400 });
|
||||
}
|
||||
|
||||
if (!notification.teamId.equals(teamId)) {
|
||||
throw new AppError({ message: "Unauthorized", status: 403 });
|
||||
}
|
||||
const notification = await this.notificationsService.findById(notificationId, teamId);
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: "Notification fetched successfully",
|
||||
@@ -141,18 +138,12 @@ class NotificationController {
|
||||
abortEarly: false,
|
||||
});
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
||||
const teamId = requireTeamId(req.user?.teamId);
|
||||
const notificationId = req.params.id;
|
||||
if (!notificationId) {
|
||||
throw new AppError({ message: "Notification ID is required", status: 400 });
|
||||
}
|
||||
|
||||
const notification = await this.db.notificationModule.getNotificationById(req.params.id);
|
||||
|
||||
if (!notification.teamId.equals(teamId)) {
|
||||
throw new AppError({ message: "Unauthorized", status: 403 });
|
||||
}
|
||||
|
||||
const editedNotification = await this.db.notificationModule.editNotification(req.params.id, req.body);
|
||||
const editedNotification = await this.notificationsService.updateById(notificationId, teamId, req.body);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: "Notification updated successfully",
|
||||
|
||||
@@ -39,4 +39,5 @@ export interface IMonitorsRepository {
|
||||
// other
|
||||
findMonitorsSummaryByTeamId(teamId: string, config?: SummaryConfig): Promise<MonitorsSummary>;
|
||||
findGroupsByTeamId(teamId: string): Promise<string[]>;
|
||||
removeNotificationFromMonitors(notificationId: string): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -189,6 +189,10 @@ class MongoMonitorsRepository implements IMonitorsRepository {
|
||||
return groups.sort();
|
||||
};
|
||||
|
||||
removeNotificationFromMonitors = async (notificationId: string): Promise<void> => {
|
||||
await MonitorModel.updateMany({ notifications: notificationId }, { $pull: { notifications: notificationId } });
|
||||
};
|
||||
|
||||
private mapDocuments = (documents: MonitorDocument[]): Monitor[] => {
|
||||
if (!documents?.length) {
|
||||
return [];
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import type { Notification } from "@/types/index.js";
|
||||
export interface INotificationsRepository {
|
||||
// create
|
||||
create(notificationData: Partial<Notification>): Promise<Notification>;
|
||||
// fetch
|
||||
findById(id: string, teamId: string): Promise<Notification>;
|
||||
findNotificationsByIds(ids: string[]): Promise<Notification[]>;
|
||||
findByTeamId(teamId: string): Promise<Notification[]>;
|
||||
// update
|
||||
updateById(id: string, teamId: string, updateData: Partial<Notification>): Promise<Notification>;
|
||||
// delete
|
||||
deleteById(id: string, teamId: string): Promise<Notification>;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import mongoose from "mongoose";
|
||||
import { NotificationModel, type NotificationDocument } from "@/db/models/index.js";
|
||||
import { INotificationsRepository } from "@/repositories/index.js";
|
||||
import type { Notification } from "@/types/index.js";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
import { not } from "joi";
|
||||
|
||||
class MongoNotificationsRepository implements INotificationsRepository {
|
||||
private mapDocuments = (documents: NotificationDocument[]): Notification[] => {
|
||||
@@ -36,11 +38,61 @@ class MongoNotificationsRepository implements INotificationsRepository {
|
||||
};
|
||||
};
|
||||
|
||||
create = async (notificationData: Partial<Notification>) => {
|
||||
const notification = await NotificationModel.create({ ...notificationData });
|
||||
if (!notification) {
|
||||
throw new AppError({ message: "Failed to create notification", status: 500 });
|
||||
}
|
||||
return this.toEntity(notification);
|
||||
};
|
||||
|
||||
findById = async (id: string, teamId: string): Promise<Notification> => {
|
||||
const notification = await NotificationModel.findOne({
|
||||
_id: new mongoose.Types.ObjectId(id),
|
||||
teamId: new mongoose.Types.ObjectId(teamId),
|
||||
});
|
||||
if (!notification) {
|
||||
throw new AppError({ message: "Notification not found", status: 404 });
|
||||
}
|
||||
return this.toEntity(notification);
|
||||
};
|
||||
|
||||
findNotificationsByIds = async (ids: string[]) => {
|
||||
const mongoIds = ids.map((id) => new mongoose.Types.ObjectId(id));
|
||||
const documents = await NotificationModel.find({ _id: { $in: mongoIds } });
|
||||
return this.mapDocuments(documents);
|
||||
};
|
||||
|
||||
findByTeamId = async (teamId: string): Promise<Notification[]> => {
|
||||
const documents = await NotificationModel.find({ teamId });
|
||||
return this.mapDocuments(documents);
|
||||
};
|
||||
|
||||
updateById = async (id: string, teamId: string, patch: Partial<Notification>): Promise<Notification> => {
|
||||
const notification = await NotificationModel.findOneAndUpdate(
|
||||
{
|
||||
_id: new mongoose.Types.ObjectId(id),
|
||||
teamId: new mongoose.Types.ObjectId(teamId),
|
||||
},
|
||||
{ $set: patch },
|
||||
{ new: true, runValidators: true }
|
||||
);
|
||||
if (!notification) {
|
||||
throw new AppError({ message: "Notification not found or could not be updated", status: 404 });
|
||||
}
|
||||
return this.toEntity(notification);
|
||||
};
|
||||
|
||||
deleteById = async (id: string, teamId: string): Promise<Notification> => {
|
||||
const deleted = await NotificationModel.findOneAndDelete({
|
||||
_id: new mongoose.Types.ObjectId(id),
|
||||
teamId: new mongoose.Types.ObjectId(teamId),
|
||||
});
|
||||
if (!deleted) {
|
||||
throw new AppError({ message: "Notification not found or could not be deleted", status: 404 });
|
||||
}
|
||||
return this.toEntity(deleted);
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoNotificationsRepository;
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import type { HardwareStatusPayload, Monitor, MonitorStatusResponse, Notification } from "@/types/index.js";
|
||||
import { shouldSendHardwareAlert } from "@/service/infrastructure/notificationProviders/utils.js";
|
||||
import { INotificationsRepository } from "@/repositories/index.js";
|
||||
import { IMonitorsRepository, INotificationsRepository } from "@/repositories/index.js";
|
||||
import { INotificationProvider } from "./notificationProviders/INotificationProvider.js";
|
||||
export interface INotificationsService {
|
||||
createNotification: (notificationData: Partial<Notification>) => Promise<Notification>;
|
||||
findById: (id: string, teamId: string) => Promise<Notification>;
|
||||
findNotificationsByTeamId: (teamId: string) => Promise<Notification[]>;
|
||||
updateById(id: string, teamId: string, updateData: Partial<Notification>): Promise<Notification>;
|
||||
deleteById: (id: string, teamId: string) => Promise<Notification>;
|
||||
handleNotifications: (
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
prevStatus: boolean | undefined,
|
||||
statusChanged: boolean
|
||||
) => Promise<boolean>;
|
||||
|
||||
sendTestNotification: (notification: Notification) => Promise<boolean>;
|
||||
testAllNotifications: (notificationIds: string[]) => Promise<boolean>;
|
||||
}
|
||||
@@ -19,6 +25,7 @@ export class NotificationsService implements INotificationsService {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
private notificationsRepository: INotificationsRepository;
|
||||
private monitorsRepository: IMonitorsRepository;
|
||||
private webhookProvider: INotificationProvider;
|
||||
private emailProvider: INotificationProvider;
|
||||
private slackProvider: INotificationProvider;
|
||||
@@ -29,6 +36,7 @@ export class NotificationsService implements INotificationsService {
|
||||
|
||||
constructor(
|
||||
notificationsRepository: INotificationsRepository,
|
||||
monitorsRepository: IMonitorsRepository,
|
||||
webhookProvider: INotificationProvider,
|
||||
emailProvider: INotificationProvider,
|
||||
slackProvider: INotificationProvider,
|
||||
@@ -38,6 +46,7 @@ export class NotificationsService implements INotificationsService {
|
||||
logger: any
|
||||
) {
|
||||
this.notificationsRepository = notificationsRepository;
|
||||
this.monitorsRepository = monitorsRepository;
|
||||
this.webhookProvider = webhookProvider;
|
||||
this.emailProvider = emailProvider;
|
||||
this.slackProvider = slackProvider;
|
||||
@@ -147,4 +156,26 @@ export class NotificationsService implements INotificationsService {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
createNotification = async (notificationData: Partial<Notification>): Promise<Notification> => {
|
||||
return await this.notificationsRepository.create(notificationData);
|
||||
};
|
||||
|
||||
findById = async (id: string, teamId: string): Promise<Notification> => {
|
||||
return await this.notificationsRepository.findById(id, teamId);
|
||||
};
|
||||
|
||||
findNotificationsByTeamId = async (teamId: string): Promise<Notification[]> => {
|
||||
return await this.notificationsRepository.findByTeamId(teamId);
|
||||
};
|
||||
|
||||
updateById = async (id: string, teamId: string, updateData: Partial<Notification>): Promise<Notification> => {
|
||||
return await this.notificationsRepository.updateById(id, teamId, updateData);
|
||||
};
|
||||
|
||||
deleteById = async (id: string, teamId: string): Promise<Notification> => {
|
||||
const deleted = await this.notificationsRepository.deleteById(id, teamId);
|
||||
await this.monitorsRepository.removeNotificationFromMonitors(id);
|
||||
return deleted;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user