move to src
This commit is contained in:
1 parent
acc910cbc0
commit
1c47c8ce2c
127 files changed
+71
-19
No files matched your search
+77
@@ -0,0 +1,77 @@
|
||||
import { createAnnouncementValidation } from "../validation/joi.js";
|
||||
import BaseController from "./baseController.js";
|
||||
|
||||
const SERVICE_NAME = "announcementController";
|
||||
|
||||
/**
|
||||
* Controller for managing announcements in the system.
|
||||
* This class handles the creation of new announcements.
|
||||
*
|
||||
* @class AnnouncementController
|
||||
*/
|
||||
|
||||
class AnnouncementController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
constructor(commonDependencies) {
|
||||
super(commonDependencies);
|
||||
this.createAnnouncement = this.createAnnouncement.bind(this);
|
||||
this.getAnnouncement = this.getAnnouncement.bind(this);
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return AnnouncementController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the creation of a new announcement.
|
||||
*
|
||||
* @async
|
||||
* @param {Object} req - The request object, containing the announcement data in the body.
|
||||
* @param {Object} res - The response object used to send the result back to the client.
|
||||
* @param {Function} next - The next middleware function in the stack for error handling.
|
||||
*
|
||||
* @returns {Promise<void>} A promise that resolves once the response is sent.
|
||||
*/
|
||||
createAnnouncement = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
await createAnnouncementValidation.validateAsync(req.body);
|
||||
const { title, message } = req.body;
|
||||
const announcementData = {
|
||||
title: title.trim(),
|
||||
message: message.trim(),
|
||||
userId: req.user._id,
|
||||
};
|
||||
|
||||
const newAnnouncement = await this.db.createAnnouncement(announcementData);
|
||||
return res.success({
|
||||
msg: this.stringService.createAnnouncement,
|
||||
data: newAnnouncement,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"createAnnouncement"
|
||||
);
|
||||
|
||||
/**
|
||||
* Handles retrieving announcements with pagination.
|
||||
*
|
||||
* @async
|
||||
* @param {Object} res - The response object used to send the result back to the client.
|
||||
* - `data`: The list of announcements to be sent back to the client.
|
||||
* - `msg`: A message about the success of the request.
|
||||
* @param {Function} next - The next middleware function in the stack for error handling.
|
||||
*/
|
||||
getAnnouncement = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
const allAnnouncements = await this.db.getAnnouncements();
|
||||
return res.success({
|
||||
msg: this.stringService.getAnnouncement,
|
||||
data: allAnnouncements,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getAnnouncement"
|
||||
);
|
||||
}
|
||||
|
||||
export default AnnouncementController;
|
||||
Executable
+461
@@ -0,0 +1,461 @@
|
||||
import BaseController from "./baseController.js";
|
||||
import {
|
||||
registrationBodyValidation,
|
||||
loginValidation,
|
||||
editUserBodyValidation,
|
||||
recoveryValidation,
|
||||
recoveryTokenBodyValidation,
|
||||
newPasswordValidation,
|
||||
getUserByIdParamValidation,
|
||||
editUserByIdParamValidation,
|
||||
editUserByIdBodyValidation,
|
||||
editSuperadminUserByIdBodyValidation,
|
||||
} from "../validation/joi.js";
|
||||
|
||||
const SERVICE_NAME = "authController";
|
||||
|
||||
/**
|
||||
* Authentication Controller
|
||||
*
|
||||
* Handles all authentication-related HTTP requests including user registration,
|
||||
* login, password recovery, and user management operations.
|
||||
*
|
||||
* @class AuthController
|
||||
* @description Manages user authentication and authorization operations
|
||||
*/
|
||||
class AuthController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
/**
|
||||
* Creates an instance of AuthController.
|
||||
*
|
||||
* @param {Object} commonDependencies - Common dependencies injected into the controller
|
||||
* @param {Object} dependencies - The dependencies required by the controller
|
||||
* @param {Object} dependencies.settingsService - Service for application settings
|
||||
* @param {Object} dependencies.emailService - Service for email operations
|
||||
* @param {Object} dependencies.jobQueue - Service for job queue operations
|
||||
* @param {Object} dependencies.userService - User business logic service
|
||||
*/
|
||||
constructor(commonDependencies, { settingsService, emailService, jobQueue, userService }) {
|
||||
super(commonDependencies);
|
||||
this.settingsService = settingsService;
|
||||
this.emailService = emailService;
|
||||
this.jobQueue = jobQueue;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return AuthController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new user in the system.
|
||||
*
|
||||
* @async
|
||||
* @function registerUser
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing user registration data
|
||||
* @param {string} req.body.firstName - User's first name
|
||||
* @param {string} req.body.lastName - User's last name
|
||||
* @param {string} req.body.email - User's email address (will be converted to lowercase)
|
||||
* @param {string} req.body.password - User's password
|
||||
* @param {string} [req.body.inviteToken] - Invite token for registration (required if superadmin exists)
|
||||
* @param {string} [req.body.teamId] - Team ID (auto-assigned if superadmin)
|
||||
* @param {Array<string>} [req.body.role] - User roles (auto-assigned if superadmin)
|
||||
* @param {Object} [req.file] - Profile image file uploaded via multer
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with user data and JWT token
|
||||
* @throws {Error} 422 - Validation error if request body is invalid
|
||||
* @throws {Error} 409 - Conflict if user already exists
|
||||
* @example
|
||||
* // Register first user (becomes superadmin)
|
||||
* POST /auth/register
|
||||
* {
|
||||
* "firstName": "John",
|
||||
* "lastName": "Doe",
|
||||
* "email": "john@example.com",
|
||||
* "password": "SecurePass123!"
|
||||
* }
|
||||
*
|
||||
* // Register subsequent user (requires invite token)
|
||||
* POST /auth/register
|
||||
* {
|
||||
* "firstName": "Jane",
|
||||
* "lastName": "Smith",
|
||||
* "email": "jane@example.com",
|
||||
* "password": "SecurePass123!",
|
||||
* "inviteToken": "abc123..."
|
||||
* }
|
||||
*/
|
||||
registerUser = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
if (req.body?.email) {
|
||||
req.body.email = req.body.email?.toLowerCase();
|
||||
}
|
||||
await registrationBodyValidation.validateAsync(req.body);
|
||||
const { user, token } = await this.userService.registerUser(req.body, req.file);
|
||||
res.success({
|
||||
msg: this.stringService.authCreateUser,
|
||||
data: { user, token },
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"registerUser"
|
||||
);
|
||||
|
||||
/**
|
||||
* Authenticates a user and returns a JWT token.
|
||||
*
|
||||
* @async
|
||||
* @function loginUser
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing login credentials
|
||||
* @param {string} req.body.email - User's email address (will be converted to lowercase)
|
||||
* @param {string} req.body.password - User's password
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with user data and JWT token
|
||||
* @throws {Error} 422 - Validation error if request body is invalid
|
||||
* @throws {Error} 401 - Unauthorized if credentials are incorrect
|
||||
* @example
|
||||
* POST /auth/login
|
||||
* {
|
||||
* "email": "john@example.com",
|
||||
* "password": "SecurePass123!"
|
||||
* }
|
||||
*/
|
||||
loginUser = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
if (req.body?.email) {
|
||||
req.body.email = req.body.email?.toLowerCase();
|
||||
}
|
||||
await loginValidation.validateAsync(req.body);
|
||||
const { user, token } = await this.userService.loginUser(req.body.email, req.body.password);
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.authLoginUser,
|
||||
data: {
|
||||
user,
|
||||
token,
|
||||
},
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"loginUser"
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the current user's profile information.
|
||||
*
|
||||
* @async
|
||||
* @function editUser
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing user update data
|
||||
* @param {string} [req.body.firstName] - Updated first name
|
||||
* @param {string} [req.body.lastName] - Updated last name
|
||||
* @param {string} [req.body.password] - Current password (required for password change)
|
||||
* @param {string} [req.body.newPassword] - New password (required for password change)
|
||||
* @param {boolean} [req.body.deleteProfileImage] - Flag to delete profile image
|
||||
* @param {Object} [req.file] - New profile image file
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with updated user data
|
||||
* @throws {Error} 422 - Validation error if request body is invalid
|
||||
* @throws {Error} 403 - Forbidden if current password is incorrect
|
||||
* @example
|
||||
* PUT /auth/user
|
||||
* {
|
||||
* "firstName": "John Updated",
|
||||
* "lastName": "Doe Updated"
|
||||
* }
|
||||
*
|
||||
* // Change password
|
||||
* PUT /auth/user
|
||||
* {
|
||||
* "password": "OldPass123!",
|
||||
* "newPassword": "NewPass123!"
|
||||
* }
|
||||
*/
|
||||
editUser = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await editUserBodyValidation.validateAsync(req.body);
|
||||
|
||||
const updatedUser = await this.userService.editUser(req.body, req.file, req.user);
|
||||
|
||||
res.success({
|
||||
msg: this.stringService.authUpdateUser,
|
||||
data: updatedUser,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"editUser"
|
||||
);
|
||||
|
||||
/**
|
||||
* Checks if a superadmin account exists in the system.
|
||||
*
|
||||
* @async
|
||||
* @function checkSuperadminExists
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with boolean indicating superadmin existence
|
||||
* @example
|
||||
* GET /auth/users/superadmin
|
||||
* // Response: { "data": true } or { "data": false }
|
||||
*/
|
||||
checkSuperadminExists = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const superAdminExists = await this.userService.checkSuperadminExists();
|
||||
return res.success({
|
||||
msg: this.stringService.authAdminExists,
|
||||
data: superAdminExists,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"checkSuperadminExists"
|
||||
);
|
||||
|
||||
/**
|
||||
* Initiates password recovery process by sending a recovery email.
|
||||
*
|
||||
* @async
|
||||
* @function requestRecovery
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing email
|
||||
* @param {string} req.body.email - Email address for password recovery
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with message ID
|
||||
* @throws {Error} 422 - Validation error if email is invalid
|
||||
* @throws {Error} 404 - Not found if user doesn't exist
|
||||
* @example
|
||||
* POST /auth/recovery/request
|
||||
* {
|
||||
* "email": "john@example.com"
|
||||
* }
|
||||
*/
|
||||
requestRecovery = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await recoveryValidation.validateAsync(req.body);
|
||||
const email = req?.body?.email;
|
||||
const msgId = await this.userService.requestRecovery(email);
|
||||
return res.success({
|
||||
msg: this.stringService.authCreateRecoveryToken,
|
||||
data: msgId,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"requestRecovery"
|
||||
);
|
||||
|
||||
/**
|
||||
* Validates a password recovery token.
|
||||
*
|
||||
* @async
|
||||
* @function validateRecovery
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing recovery token
|
||||
* @param {string} req.body.recoveryToken - Recovery token to validate
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response if token is valid
|
||||
* @throws {Error} 422 - Validation error if token format is invalid
|
||||
* @throws {Error} 400 - Bad request if token is invalid or expired
|
||||
* @example
|
||||
* POST /auth/recovery/validate
|
||||
* {
|
||||
* "recoveryToken": "abc123..."
|
||||
* }
|
||||
*/
|
||||
validateRecovery = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await recoveryTokenBodyValidation.validateAsync(req.body);
|
||||
await this.userService.validateRecovery(req.body.recoveryToken);
|
||||
return res.success({
|
||||
msg: this.stringService.authVerifyRecoveryToken,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"validateRecovery"
|
||||
);
|
||||
|
||||
/**
|
||||
* Resets user password using a valid recovery token.
|
||||
*
|
||||
* @async
|
||||
* @function resetPassword
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing new password and recovery token
|
||||
* @param {string} req.body.password - New password
|
||||
* @param {string} req.body.recoveryToken - Valid recovery token
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with user data and JWT token
|
||||
* @throws {Error} 422 - Validation error if password format is invalid
|
||||
* @throws {Error} 400 - Bad request if token is invalid or expired
|
||||
* @example
|
||||
* POST /auth/recovery/reset
|
||||
* {
|
||||
* "password": "NewSecurePass123!",
|
||||
* "recoveryToken": "abc123..."
|
||||
* }
|
||||
*/
|
||||
resetPassword = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await newPasswordValidation.validateAsync(req.body);
|
||||
const { user, token } = await this.userService.resetPassword(req.body.password, req.body.recoveryToken);
|
||||
return res.success({
|
||||
msg: this.stringService.authResetPassword,
|
||||
data: { user, token },
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"resetPassword"
|
||||
);
|
||||
|
||||
/**
|
||||
* Deletes the current user's account and associated data.
|
||||
*
|
||||
* @async
|
||||
* @function deleteUser
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user._id - User ID
|
||||
* @param {string} req.user.email - User email
|
||||
* @param {string} req.user.teamId - User's team ID
|
||||
* @param {Array<string>} req.user.role - User roles
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response confirming user deletion
|
||||
* @throws {Error} 400 - Bad request if user is demo user
|
||||
* @throws {Error} 404 - Not found if user doesn't exist
|
||||
* @example
|
||||
* DELETE /auth/user
|
||||
* // Requires JWT authentication
|
||||
*/
|
||||
deleteUser = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await this.userService.deleteUser(req.user);
|
||||
return res.success({
|
||||
msg: this.stringService.authDeleteUser,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteUser"
|
||||
);
|
||||
|
||||
/**
|
||||
* Retrieves all users in the system (admin/superadmin only).
|
||||
*
|
||||
* @async
|
||||
* @function getAllUsers
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with array of users
|
||||
* @throws {Error} 403 - Forbidden if user doesn't have admin/superadmin role
|
||||
* @example
|
||||
* GET /auth/users
|
||||
* // Requires JWT authentication with admin/superadmin role
|
||||
*/
|
||||
getAllUsers = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const allUsers = await this.userService.getAllUsers();
|
||||
return res.success({
|
||||
msg: this.stringService.authGetAllUsers,
|
||||
data: allUsers,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getAllUsers"
|
||||
);
|
||||
|
||||
/**
|
||||
* Retrieves a specific user by ID (superadmin only).
|
||||
*
|
||||
* @async
|
||||
* @function getUserById
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.params - URL parameters
|
||||
* @param {string} req.params.userId - ID of the user to retrieve
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {Array<string>} req.user.role - Current user's roles
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with user data
|
||||
* @throws {Error} 422 - Validation error if userId is invalid
|
||||
* @throws {Error} 403 - Forbidden if user doesn't have superadmin role
|
||||
* @throws {Error} 404 - Not found if user doesn't exist
|
||||
* @example
|
||||
* GET /auth/users/507f1f77bcf86cd799439011
|
||||
* // Requires JWT authentication with superadmin role
|
||||
*/
|
||||
getUserById = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getUserByIdParamValidation.validateAsync(req.params);
|
||||
const userId = req?.params?.userId;
|
||||
const roles = req?.user?.role;
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("No user ID in request");
|
||||
}
|
||||
|
||||
if (!roles || roles.length === 0) {
|
||||
throw new Error("No roles in request");
|
||||
}
|
||||
|
||||
const user = await this.userService.getUserById(roles, userId);
|
||||
|
||||
return res.success({ msg: "ok", data: user });
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getUserById"
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates a specific user by ID (superadmin only).
|
||||
*
|
||||
* @async
|
||||
* @function editUserById
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.params - URL parameters
|
||||
* @param {string} req.params.userId - ID of the user to update
|
||||
* @param {Object} req.body - Request body containing user update data
|
||||
* @param {string} [req.body.firstName] - Updated first name
|
||||
* @param {string} [req.body.lastName] - Updated last name
|
||||
* @param {Array<string>} [req.body.role] - Updated user roles
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user._id - Current user's ID
|
||||
* @param {Array<string>} req.user.role - Current user's roles
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response confirming user update
|
||||
* @throws {Error} 422 - Validation error if parameters or body are invalid
|
||||
* @throws {Error} 403 - Forbidden if user doesn't have superadmin role
|
||||
* @throws {Error} 404 - Not found if user doesn't exist
|
||||
* @example
|
||||
* PUT /auth/users/507f1f77bcf86cd799439011
|
||||
* {
|
||||
* "firstName": "Updated Name",
|
||||
* "role": ["admin"]
|
||||
* }
|
||||
* // Requires JWT authentication with superadmin role
|
||||
*/
|
||||
editUserById = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const roles = req?.user?.role;
|
||||
if (!roles.includes("superadmin")) {
|
||||
throw createError("Unauthorized", 403);
|
||||
}
|
||||
|
||||
const userId = req.params.userId;
|
||||
const user = { ...req.body };
|
||||
|
||||
await editUserByIdParamValidation.validateAsync(req.params);
|
||||
// If this is superadmin self edit, allow "superadmin" role
|
||||
if (userId === req.user._id) {
|
||||
await editSuperadminUserByIdBodyValidation.validateAsync(req.body);
|
||||
} else {
|
||||
await editUserByIdBodyValidation.validateAsync(req.body);
|
||||
}
|
||||
|
||||
await this.userService.editUserById(userId, user);
|
||||
return res.success({ msg: "ok" });
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"editUserById"
|
||||
);
|
||||
}
|
||||
|
||||
export default AuthController;
|
||||
@@ -0,0 +1,83 @@
|
||||
import { AppError } from "../service/infrastructure/errorService.js";
|
||||
|
||||
export const createCommonDependencies = (db, errorService, logger, stringService) => {
|
||||
return {
|
||||
db,
|
||||
errorService,
|
||||
logger,
|
||||
stringService,
|
||||
};
|
||||
};
|
||||
|
||||
class BaseController {
|
||||
constructor({ db, logger, errorService, ...additionalDependencies }) {
|
||||
this.db = db;
|
||||
this.logger = logger;
|
||||
this.errorService = errorService;
|
||||
Object.assign(this, additionalDependencies);
|
||||
|
||||
this.asyncHandler = (fn, serviceName, methodName) => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
await fn(req, res, next);
|
||||
} catch (error) {
|
||||
// Handle validation errors
|
||||
if (error.isJoi) {
|
||||
const validationError = this.errorService.createValidationError(error.message, error.details, serviceName, methodName);
|
||||
return next(validationError);
|
||||
}
|
||||
|
||||
if (error.name === "ValidationError") {
|
||||
const validationError = this.errorService.createValidationError("Database validation failed", error.errors, serviceName, methodName);
|
||||
return next(validationError);
|
||||
}
|
||||
|
||||
if (error.name === "CastError") {
|
||||
const notFoundError = this.errorService.createNotFoundError(
|
||||
"Invalid resource identifier",
|
||||
{ field: error.path, value: error.value },
|
||||
serviceName,
|
||||
methodName
|
||||
);
|
||||
return next(notFoundError);
|
||||
}
|
||||
|
||||
if (error.code === "11000") {
|
||||
const conflictError = this.errorService.createConflictError("Resource already exists", {
|
||||
originalError: error.message,
|
||||
code: error.code,
|
||||
});
|
||||
conflictError.service = serviceName;
|
||||
conflictError.method = methodName;
|
||||
return next(conflictError);
|
||||
}
|
||||
|
||||
if (error instanceof AppError) {
|
||||
error.service = error.service || serviceName;
|
||||
error.method = error.method || methodName;
|
||||
return next(error);
|
||||
}
|
||||
|
||||
if (error.status) {
|
||||
const appError = this.errorService.createError(error.message, error.status, serviceName, methodName, {
|
||||
originalError: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
return next(appError);
|
||||
}
|
||||
|
||||
// For unknown errors, create a server error
|
||||
const appError = this.errorService.createServerError(error.message || "An unexpected error occurred", {
|
||||
originalError: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
appError.service = serviceName;
|
||||
appError.method = methodName;
|
||||
appError.stack = error.stack; // Preserve original stack
|
||||
return next(appError);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
export default BaseController;
|
||||
Executable
+360
@@ -0,0 +1,360 @@
|
||||
import BaseController from "./baseController.js";
|
||||
import {
|
||||
getChecksParamValidation,
|
||||
getChecksQueryValidation,
|
||||
getTeamChecksQueryValidation,
|
||||
deleteChecksParamValidation,
|
||||
deleteChecksByTeamIdParamValidation,
|
||||
updateChecksTTLBodyValidation,
|
||||
ackCheckBodyValidation,
|
||||
ackAllChecksParamValidation,
|
||||
ackAllChecksBodyValidation,
|
||||
} from "../validation/joi.js";
|
||||
|
||||
const SERVICE_NAME = "checkController";
|
||||
|
||||
/**
|
||||
* Check Controller
|
||||
*
|
||||
* Handles all check-related HTTP requests including retrieving checks,
|
||||
* acknowledging checks, deleting checks, and managing check TTL settings.
|
||||
*
|
||||
* @class CheckController
|
||||
* @description Manages check operations and monitoring data
|
||||
*/
|
||||
class CheckController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
/**
|
||||
* Creates an instance of CheckController.
|
||||
*
|
||||
* @param {Object} commonDependencies - Common dependencies injected into the controller
|
||||
* @param {Object} dependencies - The dependencies required by the controller
|
||||
* @param {Object} dependencies.settingsService - Service for application settings
|
||||
* @param {Object} dependencies.checkService - Check business logic service
|
||||
*/
|
||||
constructor(commonDependencies, { settingsService, checkService }) {
|
||||
super(commonDependencies);
|
||||
this.settingsService = settingsService;
|
||||
this.checkService = checkService;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return CheckController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves checks for a specific monitor with filtering and pagination.
|
||||
*
|
||||
* @async
|
||||
* @function getChecksByMonitor
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.params - URL parameters
|
||||
* @param {string} req.params.monitorId - ID of the monitor to get checks for
|
||||
* @param {Object} req.query - Query parameters for filtering and pagination
|
||||
* @param {string} [req.query.type] - Type of checks to filter by
|
||||
* @param {string} [req.query.sortOrder] - Sort order (asc/desc)
|
||||
* @param {string} [req.query.dateRange] - Date range filter
|
||||
* @param {string} [req.query.filter] - General filter string
|
||||
* @param {boolean} [req.query.ack] - Filter by acknowledgment status
|
||||
* @param {number} [req.query.page] - Page number for pagination
|
||||
* @param {number} [req.query.rowsPerPage] - Number of rows per page
|
||||
* @param {string} [req.query.status] - Filter by check status
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user.teamId - User's team ID
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with checks data
|
||||
* @throws {Error} 422 - Validation error if parameters are invalid
|
||||
* @throws {Error} 404 - Not found if monitor doesn't exist
|
||||
* @throws {Error} 403 - Forbidden if user doesn't have access to monitor
|
||||
* @example
|
||||
* GET /checks/monitor/507f1f77bcf86cd799439011?page=1&rowsPerPage=10&status=down
|
||||
* // Requires JWT authentication
|
||||
*/
|
||||
getChecksByMonitor = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getChecksParamValidation.validateAsync(req.params);
|
||||
await getChecksQueryValidation.validateAsync(req.query);
|
||||
|
||||
const result = await this.checkService.getChecksByMonitor({
|
||||
monitorId: req?.params?.monitorId,
|
||||
query: req?.query,
|
||||
teamId: req?.user?.teamId,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.checkGet,
|
||||
data: result,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getChecksByMonitor"
|
||||
);
|
||||
|
||||
/**
|
||||
* Retrieves all checks for the current user's team with filtering and pagination.
|
||||
*
|
||||
* @async
|
||||
* @function getChecksByTeam
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.query - Query parameters for filtering and pagination
|
||||
* @param {string} [req.query.sortOrder] - Sort order (asc/desc)
|
||||
* @param {string} [req.query.dateRange] - Date range filter
|
||||
* @param {string} [req.query.filter] - General filter string
|
||||
* @param {boolean} [req.query.ack] - Filter by acknowledgment status
|
||||
* @param {number} [req.query.page] - Page number for pagination
|
||||
* @param {number} [req.query.rowsPerPage] - Number of rows per page
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user.teamId - User's team ID
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with checks data
|
||||
* @throws {Error} 422 - Validation error if query parameters are invalid
|
||||
* @example
|
||||
* GET /checks/team?page=1&rowsPerPage=20&status=down&ack=false
|
||||
* // Requires JWT authentication
|
||||
*/
|
||||
getChecksByTeam = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getTeamChecksQueryValidation.validateAsync(req.query);
|
||||
const checkData = await this.checkService.getChecksByTeam({
|
||||
teamId: req?.user?.teamId,
|
||||
query: req?.query,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.checkGet,
|
||||
data: checkData,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getChecksByTeam"
|
||||
);
|
||||
|
||||
/**
|
||||
* Retrieves a summary of checks for the current user's team.
|
||||
*
|
||||
* @async
|
||||
* @function getChecksSummaryByTeamId
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user.teamId - User's team ID
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with checks summary
|
||||
* @example
|
||||
* GET /checks/summary
|
||||
* // Requires JWT authentication
|
||||
* // Response includes counts by status, time ranges, etc.
|
||||
*/
|
||||
getChecksSummaryByTeamId = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const summary = await this.checkService.getChecksSummaryByTeamId({ teamId: req?.user?.teamId });
|
||||
return res.success({
|
||||
msg: this.stringService.checkGetSummary,
|
||||
data: summary,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getChecksSummaryByTeamId"
|
||||
);
|
||||
|
||||
/**
|
||||
* Acknowledges a specific check by ID.
|
||||
*
|
||||
* @async
|
||||
* @function ackCheck
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.params - URL parameters
|
||||
* @param {string} req.params.checkId - ID of the check to acknowledge
|
||||
* @param {Object} req.body - Request body containing acknowledgment data
|
||||
* @param {boolean} req.body.ack - Acknowledgment status (true/false)
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user.teamId - User's team ID
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with updated check data
|
||||
* @throws {Error} 422 - Validation error if request body is invalid
|
||||
* @throws {Error} 404 - Not found if check doesn't exist
|
||||
* @throws {Error} 403 - Forbidden if user doesn't have access to check
|
||||
* @example
|
||||
* PUT /checks/507f1f77bcf86cd799439011/ack
|
||||
* {
|
||||
* "ack": true
|
||||
* }
|
||||
* // Requires JWT authentication
|
||||
*/
|
||||
ackCheck = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await ackCheckBodyValidation.validateAsync(req.body);
|
||||
|
||||
const updatedCheck = await this.checkService.ackCheck({
|
||||
checkId: req?.params?.checkId,
|
||||
teamId: req?.user?.teamId,
|
||||
ack: req?.body?.ack,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.checkUpdateStatus,
|
||||
data: updatedCheck,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"ackCheck"
|
||||
);
|
||||
|
||||
/**
|
||||
* Acknowledges all checks for a specific monitor or path.
|
||||
*
|
||||
* @async
|
||||
* @function ackAllChecks
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.params - URL parameters
|
||||
* @param {string} req.params.monitorId - ID of the monitor
|
||||
* @param {string} req.params.path - Path for acknowledgment (e.g., "monitor")
|
||||
* @param {Object} req.body - Request body containing acknowledgment data
|
||||
* @param {boolean} req.body.ack - Acknowledgment status (true/false)
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user.teamId - User's team ID
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with updated checks data
|
||||
* @throws {Error} 422 - Validation error if parameters or body are invalid
|
||||
* @throws {Error} 404 - Not found if monitor doesn't exist
|
||||
* @throws {Error} 403 - Forbidden if user doesn't have access to monitor
|
||||
* @example
|
||||
* PUT /checks/monitor/507f1f77bcf86cd799439011/ack
|
||||
* {
|
||||
* "ack": true
|
||||
* }
|
||||
* // Requires JWT authentication
|
||||
*/
|
||||
ackAllChecks = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await ackAllChecksParamValidation.validateAsync(req.params);
|
||||
await ackAllChecksBodyValidation.validateAsync(req.body);
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new Error("No team ID in request");
|
||||
}
|
||||
|
||||
const updatedChecks = await this.checkService.ackAllChecks({
|
||||
monitorId: req?.params?.monitorId,
|
||||
path: req?.params?.path,
|
||||
teamId: req?.user?.teamId,
|
||||
ack: req?.body?.ack,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.checkUpdateStatus,
|
||||
data: updatedChecks,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"ackAllChecks"
|
||||
);
|
||||
|
||||
/**
|
||||
* Deletes all checks for a specific monitor.
|
||||
*
|
||||
* @async
|
||||
* @function deleteChecks
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.params - URL parameters
|
||||
* @param {string} req.params.monitorId - ID of the monitor whose checks to delete
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user.teamId - User's team ID
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with deletion count
|
||||
* @throws {Error} 422 - Validation error if monitorId is invalid
|
||||
* @throws {Error} 404 - Not found if monitor doesn't exist
|
||||
* @throws {Error} 403 - Forbidden if user doesn't have access to monitor
|
||||
* @example
|
||||
* DELETE /checks/monitor/507f1f77bcf86cd799439011
|
||||
* // Requires JWT authentication
|
||||
* // Response: { "data": { "deletedCount": 150 } }
|
||||
*/
|
||||
deleteChecks = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await deleteChecksParamValidation.validateAsync(req.params);
|
||||
|
||||
const deletedCount = await this.checkService.deleteChecks({
|
||||
monitorId: req.params.monitorId,
|
||||
teamId: req?.user?.teamId,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.checkDelete,
|
||||
data: { deletedCount },
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteChecks"
|
||||
);
|
||||
|
||||
/**
|
||||
* Deletes all checks for the current user's team.
|
||||
*
|
||||
* @async
|
||||
* @function deleteChecksByTeamId
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user.teamId - User's team ID
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with deletion count
|
||||
* @throws {Error} 422 - Validation error if parameters are invalid
|
||||
* @example
|
||||
* DELETE /checks/team
|
||||
* // Requires JWT authentication
|
||||
* // Response: { "data": { "deletedCount": 1250 } }
|
||||
*/
|
||||
deleteChecksByTeamId = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await deleteChecksByTeamIdParamValidation.validateAsync(req.params);
|
||||
|
||||
const deletedCount = await this.checkService.deleteChecksByTeamId({ teamId: req?.user?.teamId });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.checkDelete,
|
||||
data: { deletedCount },
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteChecksByTeamId"
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the TTL (Time To Live) setting for checks in the current user's team.
|
||||
*
|
||||
* @async
|
||||
* @function updateChecksTTL
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing TTL data
|
||||
* @param {number} req.body.ttl - TTL value in days
|
||||
* @param {Object} req.user - Current authenticated user (from JWT)
|
||||
* @param {string} req.user.teamId - User's team ID
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response confirming TTL update
|
||||
* @throws {Error} 422 - Validation error if TTL value is invalid
|
||||
* @example
|
||||
* PUT /checks/ttl
|
||||
* {
|
||||
* "ttl": 30
|
||||
* }
|
||||
* // Requires JWT authentication
|
||||
* // Sets check TTL to 30 days
|
||||
*/
|
||||
updateChecksTTL = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await updateChecksTTLBodyValidation.validateAsync(req.body);
|
||||
|
||||
await this.checkService.updateChecksTTL({
|
||||
teamId: req?.user?.teamId,
|
||||
ttl: req?.body?.ttl,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.checkUpdateTTL,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"updateChecksTtl"
|
||||
);
|
||||
}
|
||||
|
||||
export default CheckController;
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
const fetchMonitorCertificate = async (sslChecker, monitor) => {
|
||||
const monitorUrl = new URL(monitor.url);
|
||||
const hostname = monitorUrl.hostname;
|
||||
const cert = await sslChecker(hostname);
|
||||
// Throw an error if no cert or if cert.validTo is not present
|
||||
if (cert?.validTo === null || cert?.validTo === undefined) {
|
||||
throw new Error("Certificate not found");
|
||||
}
|
||||
return cert;
|
||||
};
|
||||
|
||||
export { fetchMonitorCertificate };
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
const SERVICE_NAME = "diagnosticController";
|
||||
import BaseController from "./baseController.js";
|
||||
/**
|
||||
* Diagnostic Controller
|
||||
*
|
||||
* Handles system diagnostic and monitoring requests including system statistics,
|
||||
* performance metrics, and health checks.
|
||||
*
|
||||
* @class DiagnosticController
|
||||
* @description Manages system diagnostics and performance monitoring
|
||||
*/
|
||||
class DiagnosticController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
/**
|
||||
* Creates an instance of DiagnosticController.
|
||||
* @param {Object} commonDependencies - Common dependencies injected into the controller
|
||||
* @param {Object} dependencies - The dependencies required by the controller
|
||||
* @param {Object} dependencies.diagnosticService - Service for system diagnostics and monitoring
|
||||
*/
|
||||
constructor(commonDependencies, { diagnosticService }) {
|
||||
super(commonDependencies);
|
||||
this.diagnosticService = diagnosticService;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return DiagnosticController.SERVICE_NAME;
|
||||
}
|
||||
/**
|
||||
* Retrieves comprehensive system statistics and performance metrics.
|
||||
*
|
||||
* @async
|
||||
* @function getSystemStats
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Success response with system diagnostics data
|
||||
* @description Returns system performance metrics, memory usage, CPU statistics,
|
||||
* and other diagnostic information useful for monitoring system health.
|
||||
* @example
|
||||
* GET /diagnostics/stats
|
||||
* // Response includes:
|
||||
* // - Memory usage (heap, external, arrayBuffers)
|
||||
* // - CPU usage statistics
|
||||
* // - System uptime
|
||||
* // - Performance metrics
|
||||
* // - Database connection status
|
||||
* // - Active processes/connections
|
||||
*/
|
||||
getSystemStats = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const diagnostics = await this.diagnosticService.getSystemStats();
|
||||
return res.success({
|
||||
msg: "OK",
|
||||
data: diagnostics,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getSystemStats"
|
||||
);
|
||||
}
|
||||
|
||||
export default DiagnosticController;
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
import { inviteBodyValidation, inviteVerificationBodyValidation } from "../validation/joi.js";
|
||||
import BaseController from "./baseController.js";
|
||||
const SERVICE_NAME = "inviteController";
|
||||
|
||||
/**
|
||||
* Controller for handling user invitation operations
|
||||
* Manages invite token generation, email sending, and token verification
|
||||
*/
|
||||
class InviteController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
/**
|
||||
* Creates a new InviteController instance
|
||||
* @param {Object} commonDependencies - Common dependencies injected into the controller
|
||||
* @param {Object} dependencies.inviteService - Service for invite-related operations
|
||||
*/
|
||||
constructor(commonDependencies, { inviteService }) {
|
||||
super(commonDependencies);
|
||||
this.inviteService = inviteService;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return InviteController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an invite token for a user invitation
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing invite details
|
||||
* @param {Object} req.user - Authenticated user object
|
||||
* @param {string} req.user.teamId - Team ID of the authenticated user
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Response with invite token data
|
||||
*/
|
||||
getInviteToken = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const invite = req.body;
|
||||
const teamId = req?.user?.teamId;
|
||||
invite.teamId = teamId;
|
||||
await inviteBodyValidation.validateAsync(invite);
|
||||
const inviteToken = await this.inviteService.getInviteToken({ invite, teamId });
|
||||
return res.success({
|
||||
msg: this.stringService.inviteIssued,
|
||||
data: inviteToken,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getInviteToken"
|
||||
);
|
||||
|
||||
/**
|
||||
* Sends an invitation email to a user
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing invite details
|
||||
* @param {Object} req.user - Authenticated user object
|
||||
* @param {string} req.user.teamId - Team ID of the authenticated user
|
||||
* @param {string} req.user.firstName - First name of the authenticated user
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Response with invite token data
|
||||
*/
|
||||
sendInviteEmail = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const inviteRequest = req.body;
|
||||
inviteRequest.teamId = req?.user?.teamId;
|
||||
await inviteBodyValidation.validateAsync(inviteRequest);
|
||||
|
||||
const inviteToken = await this.inviteService.sendInviteEmail({
|
||||
inviteRequest,
|
||||
firstName: req?.user?.firstName,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.inviteIssued,
|
||||
data: inviteToken,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"sendInviteEmail"
|
||||
);
|
||||
|
||||
/**
|
||||
* Verifies an invite token and returns invite details
|
||||
* @param {Object} req - Express request object
|
||||
* @param {Object} req.body - Request body containing the invite token
|
||||
* @param {string} req.body.token - The invite token to verify
|
||||
* @param {Object} res - Express response object
|
||||
* @returns {Promise<Object>} Response with verified invite data
|
||||
*/
|
||||
verifyInviteToken = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await inviteVerificationBodyValidation.validateAsync(req.body);
|
||||
const invite = await this.inviteService.verifyInviteToken({ inviteToken: req?.body?.token });
|
||||
return res.success({
|
||||
msg: this.stringService.inviteVerified,
|
||||
data: invite,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"verifyInviteToken"
|
||||
);
|
||||
}
|
||||
|
||||
export default InviteController;
|
||||
@@ -0,0 +1,26 @@
|
||||
import BaseController from "./baseController.js";
|
||||
const SERVICE_NAME = "LogController";
|
||||
|
||||
class LogController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
constructor(commonDependencies) {
|
||||
super(commonDependencies);
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return LogController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
getLogs = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const logs = await this.logger.getLogs();
|
||||
res.success({
|
||||
msg: "Logs fetched successfully",
|
||||
data: logs,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getLogs"
|
||||
);
|
||||
}
|
||||
export default LogController;
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
import {
|
||||
createMaintenanceWindowBodyValidation,
|
||||
editMaintenanceWindowByIdParamValidation,
|
||||
editMaintenanceByIdWindowBodyValidation,
|
||||
getMaintenanceWindowByIdParamValidation,
|
||||
getMaintenanceWindowsByMonitorIdParamValidation,
|
||||
getMaintenanceWindowsByTeamIdQueryValidation,
|
||||
deleteMaintenanceWindowByIdParamValidation,
|
||||
} from "../validation/joi.js";
|
||||
import BaseController from "./baseController.js";
|
||||
|
||||
const SERVICE_NAME = "maintenanceWindowController";
|
||||
|
||||
class MaintenanceWindowController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
constructor(commonDependencies, { settingsService, maintenanceWindowService }) {
|
||||
super(commonDependencies);
|
||||
this.settingsService = settingsService;
|
||||
this.maintenanceWindowService = maintenanceWindowService;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return MaintenanceWindowController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
createMaintenanceWindows = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await createMaintenanceWindowBodyValidation.validateAsync(req.body);
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
await this.maintenanceWindowService.createMaintenanceWindow({ teamId, body: req.body });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.maintenanceWindowCreate,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"createMaintenanceWindows"
|
||||
);
|
||||
|
||||
getMaintenanceWindowById = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
|
||||
const teamId = req.user.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const maintenanceWindow = await this.maintenanceWindowService.getMaintenanceWindowById({ id: req.params.id, teamId });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.maintenanceWindowGetById,
|
||||
data: maintenanceWindow,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMaintenanceWindowById"
|
||||
);
|
||||
|
||||
getMaintenanceWindowsByTeamId = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMaintenanceWindowsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByTeamId({ teamId, query: req.query });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.maintenanceWindowGetByTeam,
|
||||
data: maintenanceWindows,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMaintenanceWindowsByTeamId"
|
||||
);
|
||||
|
||||
getMaintenanceWindowsByMonitorId = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMaintenanceWindowsByMonitorIdParamValidation.validateAsync(req.params);
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByMonitorId({ monitorId: req.params.monitorId, teamId });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.maintenanceWindowGetByUser,
|
||||
data: maintenanceWindows,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMaintenanceWindowsByMonitorId"
|
||||
);
|
||||
|
||||
deleteMaintenanceWindow = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await deleteMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
await this.maintenanceWindowService.deleteMaintenanceWindow({ id: req.params.id, teamId });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.maintenanceWindowDelete,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteMaintenanceWindow"
|
||||
);
|
||||
|
||||
editMaintenanceWindow = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await editMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
await editMaintenanceByIdWindowBodyValidation.validateAsync(req.body);
|
||||
|
||||
const teamId = req.user.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const editedMaintenanceWindow = await this.maintenanceWindowService.editMaintenanceWindow({ id: req.params.id, body: req.body, teamId });
|
||||
return res.success({
|
||||
msg: this.stringService.maintenanceWindowEdit,
|
||||
data: editedMaintenanceWindow,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"editMaintenanceWindow"
|
||||
);
|
||||
}
|
||||
|
||||
export default MaintenanceWindowController;
|
||||
Executable
+446
@@ -0,0 +1,446 @@
|
||||
import {
|
||||
getMonitorByIdParamValidation,
|
||||
getMonitorByIdQueryValidation,
|
||||
getMonitorsByTeamIdParamValidation,
|
||||
getMonitorsByTeamIdQueryValidation,
|
||||
createMonitorBodyValidation,
|
||||
editMonitorBodyValidation,
|
||||
pauseMonitorParamValidation,
|
||||
getMonitorStatsByIdParamValidation,
|
||||
getMonitorStatsByIdQueryValidation,
|
||||
getCertificateParamValidation,
|
||||
getHardwareDetailsByIdParamValidation,
|
||||
getHardwareDetailsByIdQueryValidation,
|
||||
} from "../validation/joi.js";
|
||||
import sslChecker from "ssl-checker";
|
||||
import { fetchMonitorCertificate } from "./controllerUtils.js";
|
||||
import BaseController from "./baseController.js";
|
||||
|
||||
const SERVICE_NAME = "monitorController";
|
||||
class MonitorController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
constructor(commonDependencies, { settingsService, jobQueue, emailService, monitorService }) {
|
||||
super(commonDependencies);
|
||||
this.settingsService = settingsService;
|
||||
this.jobQueue = jobQueue;
|
||||
this.emailService = emailService;
|
||||
this.monitorService = monitorService;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return MonitorController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
async verifyTeamAccess(teamId, monitorId) {
|
||||
const monitor = await this.db.getMonitorById(monitorId);
|
||||
if (!monitor.teamId.equals(teamId)) {
|
||||
throw this.errorService.createAuthorizationError();
|
||||
}
|
||||
}
|
||||
|
||||
getAllMonitors = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const monitors = await this.monitorService.getAllMonitors();
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetAll,
|
||||
data: monitors,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getAllMonitors"
|
||||
);
|
||||
|
||||
getUptimeDetailsById = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const monitorId = req?.params?.monitorId;
|
||||
const dateRange = req?.query?.dateRange;
|
||||
const normalize = req?.query?.normalize;
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const data = await this.monitorService.getUptimeDetailsById({
|
||||
teamId,
|
||||
monitorId,
|
||||
dateRange,
|
||||
normalize,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByIdSuccess,
|
||||
data: data,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getUptimeDetailsById"
|
||||
);
|
||||
|
||||
getMonitorStatsById = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMonitorStatsByIdParamValidation.validateAsync(req.params);
|
||||
await getMonitorStatsByIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query;
|
||||
const monitorId = req?.params?.monitorId;
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const monitorStats = await this.monitorService.getMonitorStatsById({
|
||||
teamId,
|
||||
monitorId,
|
||||
limit,
|
||||
sortOrder,
|
||||
dateRange,
|
||||
numToDisplay,
|
||||
normalize,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorStatsById,
|
||||
data: monitorStats,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMonitorStatsById"
|
||||
);
|
||||
|
||||
/**
|
||||
* Get hardware details for a specific monitor by ID
|
||||
* @async
|
||||
* @param {Express.Request} req - Express request object containing monitorId in params
|
||||
* @param {Express.Response} res - Express response object
|
||||
* @param {Express.NextFunction} next - Express next middleware function
|
||||
* @returns {Promise<Express.Response>}
|
||||
* @throws {Error} - Throws error if monitor not found or other database errors
|
||||
*/
|
||||
getHardwareDetailsById = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getHardwareDetailsByIdParamValidation.validateAsync(req.params);
|
||||
await getHardwareDetailsByIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
const monitorId = req?.params?.monitorId;
|
||||
const dateRange = req?.query?.dateRange;
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const monitor = await this.monitorService.getHardwareDetailsById({
|
||||
teamId,
|
||||
monitorId,
|
||||
dateRange,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByIdSuccess,
|
||||
data: monitor,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getHardwareDetailsById"
|
||||
);
|
||||
|
||||
getMonitorCertificate = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getCertificateParamValidation.validateAsync(req.params);
|
||||
|
||||
const { monitorId } = req.params;
|
||||
const monitor = await this.db.getMonitorById(monitorId);
|
||||
const certificate = await fetchMonitorCertificate(sslChecker, monitor);
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorCertificate,
|
||||
data: {
|
||||
certificateDate: new Date(certificate.validTo),
|
||||
},
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMonitorCertificate"
|
||||
);
|
||||
|
||||
getMonitorById = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMonitorByIdParamValidation.validateAsync(req.params);
|
||||
await getMonitorByIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const monitor = await this.monitorService.getMonitorById({ teamId, monitorId: req?.params?.monitorId });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByIdSuccess,
|
||||
data: monitor,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMonitorById"
|
||||
);
|
||||
|
||||
createMonitor = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await createMonitorBodyValidation.validateAsync(req.body);
|
||||
|
||||
const userId = req?.user?._id;
|
||||
const teamId = req?.user?.teamId;
|
||||
|
||||
const monitor = await this.monitorService.createMonitor({ teamId, userId, body: req.body });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorCreate,
|
||||
data: monitor,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"createMonitor"
|
||||
);
|
||||
|
||||
createBulkMonitors = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
if (!req.file) {
|
||||
throw this.errorService.createBadRequestError("No file uploaded");
|
||||
}
|
||||
|
||||
if (!req.file.mimetype.includes("csv")) {
|
||||
throw this.errorService.createBadRequestError("File is not a CSV");
|
||||
}
|
||||
|
||||
if (req.file.size === 0) {
|
||||
throw this.errorService.createBadRequestError("File is empty");
|
||||
}
|
||||
|
||||
const userId = req?.user?._id;
|
||||
const teamId = req?.user?.teamId;
|
||||
|
||||
if (!userId || !teamId) {
|
||||
throw this.errorService.createBadRequestError("Missing userId or teamId");
|
||||
}
|
||||
|
||||
const fileData = req?.file?.buffer?.toString("utf-8");
|
||||
if (!fileData) {
|
||||
throw this.errorService.createBadRequestError("Cannot get file from buffer");
|
||||
}
|
||||
|
||||
const monitors = await this.monitorService.createBulkMonitors({ fileData, userId, teamId });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.bulkMonitorsCreate,
|
||||
data: monitors,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"createBulkMonitors"
|
||||
);
|
||||
|
||||
deleteMonitor = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMonitorByIdParamValidation.validateAsync(req.params);
|
||||
const monitorId = req.params.monitorId;
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const deletedMonitor = await this.monitorService.deleteMonitor({ teamId, monitorId });
|
||||
|
||||
return res.success({ msg: this.stringService.monitorDelete, data: deletedMonitor });
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteMonitor"
|
||||
);
|
||||
|
||||
deleteAllMonitors = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const deletedCount = await this.monitorService.deleteAllMonitors({ teamId });
|
||||
|
||||
return res.success({ msg: `Deleted ${deletedCount} monitors` });
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteAllMonitors"
|
||||
);
|
||||
|
||||
editMonitor = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMonitorByIdParamValidation.validateAsync(req.params);
|
||||
await editMonitorBodyValidation.validateAsync(req.body);
|
||||
const monitorId = req?.params?.monitorId;
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const editedMonitor = await this.monitorService.editMonitor({ teamId, monitorId, body: req.body });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorEdit,
|
||||
data: editedMonitor,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"editMonitor"
|
||||
);
|
||||
|
||||
pauseMonitor = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await pauseMonitorParamValidation.validateAsync(req.params);
|
||||
|
||||
const monitorId = req.params.monitorId;
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const monitor = await this.monitorService.pauseMonitor({ teamId, monitorId });
|
||||
|
||||
return res.success({
|
||||
msg: monitor.isActive ? this.stringService.monitorResume : this.stringService.monitorPause,
|
||||
data: monitor,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"pauseMonitor"
|
||||
);
|
||||
|
||||
addDemoMonitors = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const { _id, teamId } = req.user;
|
||||
const demoMonitors = await this.monitorService.addDemoMonitors({ userId: _id, teamId });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorDemoAdded,
|
||||
data: demoMonitors?.length ?? 0,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"addDemoMonitors"
|
||||
);
|
||||
|
||||
sendTestEmail = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const { to } = req.body;
|
||||
if (!to || typeof to !== "string") {
|
||||
throw this.errorService.createBadRequestError(this.stringService.errorForValidEmailAddress);
|
||||
}
|
||||
|
||||
const messageId = await this.monitorService.sendTestEmail({ to });
|
||||
return res.success({
|
||||
msg: this.stringService.sendTestEmail,
|
||||
data: { messageId },
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"sendTestEmail"
|
||||
);
|
||||
|
||||
getMonitorsByTeamId = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
|
||||
await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
|
||||
const teamId = req?.user?.teamId;
|
||||
|
||||
const monitors = await this.monitorService.getMonitorsByTeamId({ teamId, limit, type, page, rowsPerPage, filter, field, order });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByTeamId,
|
||||
data: monitors,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMonitorsByTeamId"
|
||||
);
|
||||
|
||||
getMonitorsAndSummaryByTeamId = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
|
||||
await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
const explain = req?.query?.explain;
|
||||
const type = req?.query?.type;
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const result = await this.monitorService.getMonitorsAndSummaryByTeamId({ teamId, type, explain });
|
||||
|
||||
return res.success({
|
||||
msg: "OK", // TODO
|
||||
data: result,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMonitorsAndSummaryByTeamId"
|
||||
);
|
||||
|
||||
getMonitorsWithChecksByTeamId = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
|
||||
await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
const explain = req?.query?.explain;
|
||||
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const monitors = await this.monitorService.getMonitorsWithChecksByTeamId({
|
||||
teamId,
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
explain,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: "OK",
|
||||
data: monitors,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMonitorsWithChecksByTeamId"
|
||||
);
|
||||
|
||||
exportMonitorsToCSV = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const csv = await this.monitorService.exportMonitorsToCSV({ teamId });
|
||||
|
||||
return res.file({
|
||||
data: csv,
|
||||
headers: {
|
||||
"Content-Type": "text/csv",
|
||||
"Content-Disposition": "attachment; filename=monitors.csv",
|
||||
},
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"exportMonitorsToCSV"
|
||||
);
|
||||
}
|
||||
|
||||
export default MonitorController;
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
import { createNotificationBodyValidation } from "../validation/joi.js";
|
||||
import BaseController from "./baseController.js";
|
||||
|
||||
const SERVICE_NAME = "NotificationController";
|
||||
|
||||
class NotificationController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
constructor(commonDependencies, { notificationService, statusService }) {
|
||||
super(commonDependencies);
|
||||
this.notificationService = notificationService;
|
||||
this.statusService = statusService;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return NotificationController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
testNotification = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const notification = req.body;
|
||||
|
||||
const success = await this.notificationService.sendTestNotification(notification);
|
||||
|
||||
if (!success) {
|
||||
throw this.errorService.createServerError("Sending notification failed");
|
||||
}
|
||||
|
||||
return res.success({
|
||||
msg: "Notification sent successfully",
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"testNotification"
|
||||
);
|
||||
|
||||
createNotification = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await createNotificationBodyValidation.validateAsync(req.body, {
|
||||
abortEarly: false,
|
||||
});
|
||||
|
||||
const body = req.body;
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const userId = req?.user?._id;
|
||||
if (!userId) {
|
||||
throw this.errorService.createBadRequestError("User ID is required");
|
||||
}
|
||||
body.userId = userId;
|
||||
body.teamId = teamId;
|
||||
|
||||
const notification = await this.db.createNotification(body);
|
||||
return res.success({
|
||||
msg: "Notification created successfully",
|
||||
data: notification,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"createNotification"
|
||||
);
|
||||
|
||||
getNotificationsByTeamId = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const notifications = await this.db.getNotificationsByTeamId(teamId);
|
||||
|
||||
return res.success({
|
||||
msg: "Notifications fetched successfully",
|
||||
data: notifications,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getNotificationsByTeamId"
|
||||
);
|
||||
|
||||
deleteNotification = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const notification = await this.db.getNotificationById(req.params.id);
|
||||
if (!notification.teamId.equals(teamId)) {
|
||||
throw this.errorService.createAuthorizationError();
|
||||
}
|
||||
|
||||
await this.db.deleteNotificationById(req.params.id);
|
||||
return res.success({
|
||||
msg: "Notification deleted successfully",
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteNotification"
|
||||
);
|
||||
|
||||
getNotificationById = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const notification = await this.db.getNotificationById(req.params.id);
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
if (!notification.teamId.equals(teamId)) {
|
||||
throw this.errorService.createAuthorizationError();
|
||||
}
|
||||
return res.success({
|
||||
msg: "Notification fetched successfully",
|
||||
data: notification,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getNotificationById"
|
||||
);
|
||||
|
||||
editNotification = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await createNotificationBodyValidation.validateAsync(req.body, {
|
||||
abortEarly: false,
|
||||
});
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const notification = await this.db.getNotificationById(req.params.id);
|
||||
|
||||
if (!notification.teamId.equals(teamId)) {
|
||||
throw this.errorService.createAuthorizationError();
|
||||
}
|
||||
|
||||
const editedNotification = await this.db.editNotification(req.params.id, req.body);
|
||||
return res.success({
|
||||
msg: "Notification updated successfully",
|
||||
data: editedNotification,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"editNotification"
|
||||
);
|
||||
|
||||
testAllNotifications = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const monitorId = req.body.monitorId;
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("Team ID is required");
|
||||
}
|
||||
|
||||
const monitor = await this.db.getMonitorById(monitorId);
|
||||
|
||||
if (!monitor.teamId.equals(teamId)) {
|
||||
throw this.errorService.createAuthorizationError();
|
||||
}
|
||||
|
||||
const notifications = monitor.notifications;
|
||||
if (notifications.length === 0) throw this.errorService.createBadRequestError("No notifications");
|
||||
const result = await this.notificationService.testAllNotifications(notifications);
|
||||
if (!result) throw this.errorService.createServerError("Failed to send all notifications");
|
||||
return res.success({
|
||||
msg: "All notifications sent successfully",
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"testAllNotifications"
|
||||
);
|
||||
}
|
||||
|
||||
export default NotificationController;
|
||||
Executable
+87
@@ -0,0 +1,87 @@
|
||||
import BaseController from "./baseController.js";
|
||||
const SERVICE_NAME = "JobQueueController";
|
||||
|
||||
class JobQueueController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
constructor(commonDependencies, { jobQueue }) {
|
||||
super(commonDependencies);
|
||||
this.jobQueue = jobQueue;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return JobQueueController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
getMetrics = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const metrics = await this.jobQueue.getMetrics();
|
||||
res.success({
|
||||
msg: this.stringService.queueGetMetrics,
|
||||
data: metrics,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMetrics"
|
||||
);
|
||||
|
||||
getJobs = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const jobs = await this.jobQueue.getJobs();
|
||||
return res.success({
|
||||
msg: this.stringService.queueGetJobs,
|
||||
data: jobs,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getJobs"
|
||||
);
|
||||
|
||||
getAllMetrics = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const jobs = await this.jobQueue.getJobs();
|
||||
const metrics = await this.jobQueue.getMetrics();
|
||||
return res.success({
|
||||
msg: this.stringService.queueGetAllMetrics,
|
||||
data: { jobs, metrics },
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getAllMetrics"
|
||||
);
|
||||
|
||||
addJob = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await this.jobQueue.addJob(Math.random().toString(36).substring(7));
|
||||
return res.success({
|
||||
msg: this.stringService.queueAddJob,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"addJob"
|
||||
);
|
||||
|
||||
flushQueue = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const result = await this.jobQueue.flushQueues();
|
||||
return res.success({
|
||||
msg: this.stringService.jobQueueFlush,
|
||||
data: result,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"flushQueue"
|
||||
);
|
||||
|
||||
checkQueueHealth = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const stuckQueues = await this.jobQueue.checkQueueHealth();
|
||||
return res.success({
|
||||
msg: this.stringService.queueHealthCheck,
|
||||
data: stuckQueues,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"checkQueueHealth"
|
||||
);
|
||||
}
|
||||
export default JobQueueController;
|
||||
Executable
+122
@@ -0,0 +1,122 @@
|
||||
import { updateAppSettingsBodyValidation } from "../validation/joi.js";
|
||||
import { sendTestEmailBodyValidation } from "../validation/joi.js";
|
||||
import BaseController from "./baseController.js";
|
||||
|
||||
const SERVICE_NAME = "SettingsController";
|
||||
|
||||
class SettingsController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
constructor(commonDependencies, { settingsService, emailService }) {
|
||||
super(commonDependencies);
|
||||
this.settingsService = settingsService;
|
||||
this.emailService = emailService;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return SettingsController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
buildAppSettings = (dbSettings) => {
|
||||
const sanitizedSettings = { ...dbSettings };
|
||||
delete sanitizedSettings.version;
|
||||
|
||||
const returnSettings = {
|
||||
pagespeedKeySet: false,
|
||||
emailPasswordSet: false,
|
||||
};
|
||||
|
||||
if (typeof sanitizedSettings.pagespeedApiKey !== "undefined") {
|
||||
returnSettings.pagespeedKeySet = true;
|
||||
delete sanitizedSettings.pagespeedApiKey;
|
||||
}
|
||||
if (typeof sanitizedSettings.systemEmailPassword !== "undefined") {
|
||||
returnSettings.emailPasswordSet = true;
|
||||
delete sanitizedSettings.systemEmailPassword;
|
||||
}
|
||||
returnSettings.settings = sanitizedSettings;
|
||||
return returnSettings;
|
||||
};
|
||||
|
||||
getAppSettings = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const dbSettings = await this.settingsService.getDBSettings();
|
||||
|
||||
const returnSettings = this.buildAppSettings(dbSettings);
|
||||
return res.success({
|
||||
msg: this.stringService.getAppSettings,
|
||||
data: returnSettings,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getAppSettings"
|
||||
);
|
||||
|
||||
updateAppSettings = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await updateAppSettingsBodyValidation.validateAsync(req.body);
|
||||
|
||||
const updatedSettings = await this.db.updateAppSettings(req.body);
|
||||
const returnSettings = this.buildAppSettings(updatedSettings);
|
||||
return res.success({
|
||||
msg: this.stringService.updateAppSettings,
|
||||
data: returnSettings,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"updateAppSettings"
|
||||
);
|
||||
|
||||
sendTestEmail = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await sendTestEmailBodyValidation.validateAsync(req.body);
|
||||
|
||||
const {
|
||||
to,
|
||||
systemEmailHost,
|
||||
systemEmailPort,
|
||||
systemEmailAddress,
|
||||
systemEmailPassword,
|
||||
systemEmailUser,
|
||||
systemEmailConnectionHost,
|
||||
systemEmailSecure,
|
||||
systemEmailPool,
|
||||
systemEmailIgnoreTLS,
|
||||
systemEmailRequireTLS,
|
||||
systemEmailRejectUnauthorized,
|
||||
systemEmailTLSServername,
|
||||
} = req.body;
|
||||
|
||||
const subject = this.stringService.testEmailSubject;
|
||||
const context = { testName: "Monitoring System" };
|
||||
|
||||
const html = await this.emailService.buildEmail("testEmailTemplate", context);
|
||||
const messageId = await this.emailService.sendEmail(to, subject, html, {
|
||||
systemEmailHost,
|
||||
systemEmailPort,
|
||||
systemEmailUser,
|
||||
systemEmailAddress,
|
||||
systemEmailPassword,
|
||||
systemEmailConnectionHost,
|
||||
systemEmailSecure,
|
||||
systemEmailPool,
|
||||
systemEmailIgnoreTLS,
|
||||
systemEmailRequireTLS,
|
||||
systemEmailRejectUnauthorized,
|
||||
systemEmailTLSServername,
|
||||
});
|
||||
|
||||
if (!messageId) {
|
||||
throw this.errorService.createServerError("Failed to send test email.");
|
||||
}
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.sendTestEmail,
|
||||
data: { messageId },
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"sendTestEmail"
|
||||
);
|
||||
}
|
||||
|
||||
export default SettingsController;
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
import { createStatusPageBodyValidation, getStatusPageParamValidation, getStatusPageQueryValidation, imageValidation } from "../validation/joi.js";
|
||||
import BaseController from "./baseController.js";
|
||||
|
||||
const SERVICE_NAME = "statusPageController";
|
||||
|
||||
class StatusPageController extends BaseController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
constructor(commonDependencies) {
|
||||
super(commonDependencies);
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return StatusPageController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
createStatusPage = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await createStatusPageBodyValidation.validateAsync(req.body);
|
||||
await imageValidation.validateAsync(req.file);
|
||||
|
||||
const { _id, teamId } = req.user;
|
||||
const statusPage = await this.db.createStatusPage({
|
||||
statusPageData: req.body,
|
||||
image: req.file,
|
||||
userId: _id,
|
||||
teamId,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.statusPageCreate,
|
||||
data: statusPage,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"createStatusPage"
|
||||
);
|
||||
|
||||
updateStatusPage = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await createStatusPageBodyValidation.validateAsync(req.body);
|
||||
await imageValidation.validateAsync(req.file);
|
||||
|
||||
const statusPage = await this.db.updateStatusPage(req.body, req.file);
|
||||
if (statusPage === null) {
|
||||
throw this.errorService.createNotFoundError(this.stringService.statusPageNotFound);
|
||||
}
|
||||
return res.success({
|
||||
msg: this.stringService.statusPageUpdate,
|
||||
data: statusPage,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"updateStatusPage"
|
||||
);
|
||||
|
||||
getStatusPage = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const statusPage = await this.db.getStatusPage();
|
||||
return res.success({
|
||||
msg: this.stringService.statusPageByUrl,
|
||||
data: statusPage,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getStatusPage"
|
||||
);
|
||||
|
||||
getStatusPageByUrl = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await getStatusPageParamValidation.validateAsync(req.params);
|
||||
await getStatusPageQueryValidation.validateAsync(req.query);
|
||||
|
||||
const statusPage = await this.db.getStatusPageByUrl(req.params.url, req.query.type);
|
||||
return res.success({
|
||||
msg: this.stringService.statusPageByUrl,
|
||||
data: statusPage,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getStatusPageByUrl"
|
||||
);
|
||||
|
||||
getStatusPagesByTeamId = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
const teamId = req.user.teamId;
|
||||
const statusPages = await this.db.getStatusPagesByTeamId(teamId);
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.statusPageByTeamId,
|
||||
data: statusPages,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getStatusPagesByTeamId"
|
||||
);
|
||||
|
||||
deleteStatusPage = this.asyncHandler(
|
||||
async (req, res) => {
|
||||
await this.db.deleteStatusPage(req.params.url);
|
||||
return res.success({
|
||||
msg: this.stringService.statusPageDelete,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteStatusPage"
|
||||
);
|
||||
}
|
||||
|
||||
export default StatusPageController;
|
||||
Reference in new issue
Block a user