diff --git a/.gitignore b/.gitignore index ebf2039ec..a0420fec9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vite .vscode *.sh -!uptime.sh \ No newline at end of file +!uptime.sh +*.idea \ No newline at end of file diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 8d41f916b..f3ad6fba4 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -1,459 +1,371 @@ -const express = require("express"); const { - registrationBodyValidation, - loginValidation, - editUserParamValidation, - editUserBodyValidation, - recoveryValidation, - recoveryTokenValidation, - newPasswordValidation, - deleteUserParamValidation, - inviteRoleValidation, - inviteBodyValidation, - inviteVerifciationBodyValidation, + registrationBodyValidation, + loginValidation, + editUserParamValidation, + editUserBodyValidation, + recoveryValidation, + recoveryTokenValidation, + newPasswordValidation, } = require("../validation/joi"); const logger = require("../utils/logger"); require("dotenv").config(); -const { errorMessages, successMessages } = require("../utils/messages"); -var jwt = require("jsonwebtoken"); +const {errorMessages, successMessages} = require("../utils/messages"); +const jwt = require("jsonwebtoken"); const SERVICE_NAME = "AuthController"; -const { getTokenFromHeaders } = require("../utils/utils"); +const {getTokenFromHeaders} = require("../utils/utils"); const crypto = require("crypto"); /** * Creates and returns JWT token with an arbitrary payload * @function * @param {Object} payload + * @param {Object} appSettings * @returns {String} + * @throws {Error} */ const issueToken = (payload, appSettings) => { - try { - const tokenTTL = appSettings.jwtTTL ? appSettings.jwtTTL : "2h"; - return jwt.sign(payload, appSettings.jwtSecret, { expiresIn: tokenTTL }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "issueToken") : null; - next(error); - } -}; - -/** - * @function - * @param {express.Request} req - * @param {express.Response} res - * @returns {{success: Boolean, msg: String}} - */ -const registerController = async (req, res, next) => { - // joi validation - try { - await registrationBodyValidation.validateAsync(req.body); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - // Create a new user - try { - const { inviteToken } = req.body; - // If superAdmin exists, a token should be attached to all further register requests - const superAdminExists = await req.db.checkSuperadmin(req, res); - if (superAdminExists) { - await req.db.getInviteTokenAndDelete(inviteToken); - } else { - // This is the first account, create JWT secret to use if one is not supplied by env - const jwtSecret = crypto.randomBytes(64).toString("hex"); - await req.db.updateAppSettings({ jwtSecret }); - } - - const newUser = await req.db.insertUser({ ...req.body }, req.file); - logger.info(successMessages.AUTH_CREATE_USER, { - service: SERVICE_NAME, - userId: newUser._id, - }); - - const userForToken = { ...newUser._doc }; - delete userForToken.profileImage; - delete userForToken.avatarImage; - - const appSettings = await req.settingsService.getSettings(); - const token = issueToken(userForToken, appSettings); - req.emailService - .buildAndSendEmail( - "welcomeEmailTemplate", - { name: newUser.firstName }, - newUser.email, - "Welcome to Uptime Monitor" - ) - .catch((error) => { - logger.error("Error sending welcome email", { - service: SERVICE_NAME, - error: error.message, - }); - }); - - return res.status(200).json({ - success: true, - msg: successMessages.AUTH_CREATE_USER, - data: { user: newUser, token: token }, - }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "registerController") : null; - next(error); - } -}; - -/** - * Returns JWT with User info - * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - */ -const loginController = async (req, res, next) => { - try { - await loginValidation.validateAsync(req.body); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - try { - const { email, password } = req.body; - // Check if user exists - const user = await req.db.getUserByEmail(email); - - // Compare password - const match = await user.comparePassword(password); - if (match !== true) { - throw new Error(errorMessages.AUTH_INCORRECT_PASSWORD); - } - - // Remove password from user object. Should this be abstracted to DB layer? - const userWithoutPassword = { ...user._doc }; - delete userWithoutPassword.password; - delete userWithoutPassword.avatarImage; - - // Happy path, return token - const appSettings = req.settingsService.getSettings(); - const token = issueToken(userWithoutPassword, appSettings); - // reset avatar image - userWithoutPassword.avatarImage = user.avatarImage; - - return res.status(200).json({ - success: true, - msg: successMessages.AUTH_LOGIN_USER, - data: { user: userWithoutPassword, token: token }, - }); - } catch (error) { - error.status = 500; - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "loginController") : null; - next(error); - } -}; - -const userEditController = async (req, res, next) => { - try { - await editUserParamValidation.validateAsync(req.params); - await editUserBodyValidation.validateAsync(req.body); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - - // TODO is this neccessary any longer? Verify ownership middleware should handle this - if (req.params.userId !== req.user._id.toString()) { - const error = new Error(errorMessages.AUTH_UNAUTHORIZED); - error.status = 401; - error.service = SERVICE_NAME; - next(error); - return; - } - - try { - // Change Password check - if (req.body.password && req.body.newPassword) { - const newPassword = req.body.newPassword; - const password = req.body.password; - - // Compare password - // Get token from headers - const token = getTokenFromHeaders(req.headers); - // Get email from token - const { jwtSecret } = req.settingsService.getSettings(); - const { email } = jwt.verify(token, jwtSecret); - // Add user email to body for DB operation - req.body.email = email; - // Get user - const user = await req.db.getUserByEmail(email); - // Compare passwords - const match = await user.comparePassword(req.body.password); - // If not a match, throw a 403 - if (!match) { - const error = new Error(errorMessages.AUTH_INCORRECT_PASSWORD); - error.status = 403; - throw error; - } - // If a match, update the password - req.body.password = req.body.newPassword; - } - - const updatedUser = await req.db.updateUser(req, res); - return res.status(200).json({ - success: true, - msg: successMessages.AUTH_UPDATE_USER, - data: updatedUser, - }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "userEditController") : null; - next(error); - return; - } -}; - -const inviteController = async (req, res, next) => { - try { - // Only admins can invite - const token = getTokenFromHeaders(req.headers); - const { role, firstname, teamId } = jwt.decode(token); - req.body.teamId = teamId; try { - await inviteRoleValidation.validateAsync({ roles: role }); - await inviteBodyValidation.validateAsync(req.body); + const tokenTTL = appSettings.jwtTTL ? appSettings.jwtTTL : "2h"; + return jwt.sign(payload, appSettings.jwtSecret, {expiresIn: tokenTTL}); } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "issueToken") : null; + throw error; } +}; - const inviteToken = await req.db.requestInviteToken(req, res); - const { clientHost } = req.settingsService.getSettings(); - req.emailService - .buildAndSendEmail( - "employeeActivationTemplate", - { - name: firstname, - link: `${clientHost}/register/${inviteToken.token}`, - }, - req.body.email, - "Welcome to Uptime Monitor" - ) - .catch((error) => { - logger.error("Error sending invite email", { - service: SERVICE_NAME, - error: error.message, +/** + * Registers a new user. If the user is the first account, a JWT secret is created. If not, an invite token is required. + * @async + * @param {Object} req - The Express request object. + * @property {Object} req.body - The body of the request. + * @property {string} req.body.inviteToken - The invite token for registration. + * @property {Object} req.file - The file object for the user's profile image. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the creation of the user, the created user data, and a JWT token. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422). + */ +const registerUser = async (req, res, next) => { + // joi validation + try { + await registrationBodyValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } + // Create a new user + try { + const {inviteToken} = req.body; + // If superAdmin exists, a token should be attached to all further register requests + const superAdminExists = await req.db.checkSuperadmin(req, res); + if (superAdminExists) { + await req.db.getInviteTokenAndDelete(inviteToken); + } else { + // This is the first account, create JWT secret to use if one is not supplied by env + const jwtSecret = crypto.randomBytes(64).toString("hex"); + await req.db.updateAppSettings({jwtSecret}); + } + + const newUser = await req.db.insertUser({...req.body}, req.file); + logger.info(successMessages.AUTH_CREATE_USER, { + service: SERVICE_NAME, userId: newUser._id, }); - }); - return res - .status(200) - .json({ success: true, msg: "Invite sent", data: inviteToken }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "inviteController") : null; - next(error); - return; - } -}; + const userForToken = {...newUser._doc}; + delete userForToken.profileImage; + delete userForToken.avatarImage; -const inviteVerifyController = async (req, res, next) => { - try { - await inviteVerifciationBodyValidation.validateAsync(req.body); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } + const appSettings = await req.settingsService.getSettings(); + const token = issueToken(userForToken, appSettings); + req.emailService + .buildAndSendEmail("welcomeEmailTemplate", {name: newUser.firstName}, newUser.email, "Welcome to Uptime Monitor") + .catch((error) => { + logger.error("Error sending welcome email", { + service: SERVICE_NAME, error: error.message, + }); + }); - try { - const invite = await req.db.getInviteToken(req, res); - res - .status(200) - .json({ status: "success", msg: "Invite verified", data: invite }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined - ? (error.method = "inviteVerifyController") - : null; - next(error); - return; - } -}; - -/** - * Checks to see if an admin account exists - * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - */ - -const checkSuperadminController = async (req, res) => { - try { - const superAdminExists = await req.db.checkSuperadmin(req, res); - return res.status(200).json({ - success: true, - msg: successMessages.AUTH_ADMIN_EXISTS, - data: superAdminExists, - }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined - ? (error.method = "checkSuperadminController") - : null; - next(error); - return; - } -}; - -/** - * Returns a recovery token - * @async - * @param {Express.Request} req - * @property {Object} req.body - * @property {string} req.body.email - * @property {EmailService} req.body.emailService - * @returns {Promise} - */ -const recoveryRequestController = async (req, res, next) => { - try { - await recoveryValidation.validateAsync(req.body); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - - try { - const { email } = req.body; - const user = await req.db.getUserByEmail(email); - if (user) { - const recoveryToken = await req.db.requestRecoveryToken(req, res); - const name = user.firstName; - const email = req.body.email; - const { clientHost } = req.settingsService.getSettings(); - const url = `${clientHost}/set-new-password/${recoveryToken.token}`; - - const msgId = await req.emailService.buildAndSendEmail( - "passwordResetTemplate", - { name, email, url }, - email, - "Bluewaves Uptime Password Resest" - ); - - return res.status(200).json({ - success: true, - msg: successMessages.AUTH_CREATE_RECOVERY_TOKEN, - data: msgId, - }); + return res.status(200).json({ + success: true, msg: successMessages.AUTH_CREATE_USER, data: {user: newUser, token: token}, + }); + } catch (error) { + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "registerController") : null; + next(error); } - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined - ? (error.method = "recoveryRequestController") - : null; - next(error); - return; - } }; /** - * Returns a recovery token + * Logs in a user by validating the user's credentials and issuing a JWT token. * @async - * @param {Express.Request} req - * @property {Object} req.body - * @property {string} req.body.token - * @param {Express.Response} res - * @returns {Promise} + * @param {Object} req - The Express request object. + * @property {Object} req.body - The body of the request. + * @property {string} req.body.email - The email of the user. + * @property {string} req.body.password - The password of the user. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the login of the user, the user data (without password and avatar image), and a JWT token. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422) or the password is incorrect. */ -const validateRecoveryTokenController = async (req, res, next) => { - try { - await recoveryTokenValidation.validateAsync(req.body); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } +const loginUser = async (req, res, next) => { + try { + await loginValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } + try { + const {email, password} = req.body; + // Check if user exists + const user = await req.db.getUserByEmail(email); - try { - await req.db.validateRecoveryToken(req, res); - // TODO Redirect user to reset password after validating token - return res.status(200).json({ - success: true, - msg: successMessages.AUTH_VERIFY_RECOVERY_TOKEN, - }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined - ? (error.method = "validateRecoveryTokenController") - : null; - next(error); - return; - } + // Compare password + const match = await user.comparePassword(password); + if (match !== true) { + next(new Error(errorMessages.AUTH_INCORRECT_PASSWORD)); + return; + } + + // Remove password from user object. Should this be abstracted to DB layer? + const userWithoutPassword = {...user._doc}; + delete userWithoutPassword.password; + delete userWithoutPassword.avatarImage; + + // Happy path, return token + const appSettings = req.settingsService.getSettings(); + const token = issueToken(userWithoutPassword, appSettings); + // reset avatar image + userWithoutPassword.avatarImage = user.avatarImage; + + return res.status(200).json({ + success: true, msg: successMessages.AUTH_LOGIN_USER, data: {user: userWithoutPassword, token: token}, + }); + } catch (error) { + error.status = 500; + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "loginController") : null; + next(error); + } }; /** - * Returns an updated user + * Edits a user's information. If the user wants to change their password, the current password is checked before updating to the new password. * @async - * @param {Express.Request} req - * @property {Object} req.body - * @property {string} req.body.token - * @property {string} req.body.password - * @param {Express.Response} res - * @returns {Promise} + * @param {Object} req - The Express request object. + * @property {Object} req.params - The parameters of the request. + * @property {string} req.params.userId - The ID of the user to be edited. + * @property {Object} req.body - The body of the request. + * @property {string} req.body.password - The current password of the user. + * @property {string} req.body.newPassword - The new password of the user. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the update of the user, and the updated user data. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422), the user is unauthorized (401), or the password is incorrect (403). */ -const resetPasswordController = async (req, res, next) => { - try { - await newPasswordValidation.validateAsync(req.body); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - try { - const user = await req.db.resetPassword(req, res); +const editUser = async (req, res, next) => { + try { + await editUserParamValidation.validateAsync(req.params); + await editUserBodyValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } - const appSettings = await req.settingsService.getSettings(); - const token = issueToken(user._doc, appSettings); - res.status(200).json({ - success: true, - msg: successMessages.AUTH_RESET_PASSWORD, - data: { user, token }, - }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined - ? (error.method = "resetPasswordController") - : null; - next(error); - } + // TODO is this neccessary any longer? Verify ownership middleware should handle this + if (req.params.userId !== req.user._id.toString()) { + const error = new Error(errorMessages.AUTH_UNAUTHORIZED); + error.status = 401; + error.service = SERVICE_NAME; + next(error); + return; + } + + try { + // Change Password check + if (req.body.password && req.body.newPassword) { + // Get token from headers + const token = getTokenFromHeaders(req.headers); + // Get email from token + const {jwtSecret} = req.settingsService.getSettings(); + const {email} = jwt.verify(token, jwtSecret); + // Add user email to body for DB operation + req.body.email = email; + // Get user + const user = await req.db.getUserByEmail(email); + // Compare passwords + const match = await user.comparePassword(req.body.password); + // If not a match, throw a 403 + if (!match) { + const error = new Error(errorMessages.AUTH_INCORRECT_PASSWORD); + error.status = 403; + next(error) + return; + } + // If a match, update the password + req.body.password = req.body.newPassword; + } + + const updatedUser = await req.db.updateUser(req, res); + return res.status(200).json({ + success: true, msg: successMessages.AUTH_UPDATE_USER, data: updatedUser, + }); + } catch (error) { + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "userEditController") : null; + next(error); + } +}; + +/** + * Checks if a superadmin account exists in the database. + * @async + * @param {Object} req - The Express request object. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the existence of a superadmin, and a boolean indicating the existence of a superadmin. + * @throws {Error} If there is an error during the process. + */ +const checkSuperAdminExists = async (req, res, next) => { + try { + const superAdminExists = await req.db.checkSuperadmin(req, res); + return res.status(200).json({ + success: true, msg: successMessages.AUTH_ADMIN_EXISTS, data: superAdminExists, + }); + } catch (error) { + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "checkSuperadminController") : null; + next(error); + } +}; + +/** + * Requests a recovery token for a user. The user's email is validated and a recovery token is created and sent via email. + * @async + * @param {Object} req - The Express request object. + * @property {Object} req.body - The body of the request. + * @property {string} req.body.email - The email of the user requesting recovery. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the creation of the recovery token, and the message ID of the sent email. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422). + */ +const requestRecovery = async (req, res, next) => { + try { + await recoveryValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } + + try { + const {email} = req.body; + const user = await req.db.getUserByEmail(email); + if (user) { + const recoveryToken = await req.db.requestRecoveryToken(req, res); + const name = user.firstName; + const email = req.body.email; + const {clientHost} = req.settingsService.getSettings(); + const url = `${clientHost}/set-new-password/${recoveryToken.token}`; + + const msgId = await req.emailService.buildAndSendEmail("passwordResetTemplate", { + name, + email, + url + }, email, "Bluewave Uptime Password Reset"); + + return res.status(200).json({ + success: true, msg: successMessages.AUTH_CREATE_RECOVERY_TOKEN, data: msgId, + }); + } + } catch (error) { + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "recoveryRequestController") : null; + next(error); + } +}; + +/** + * Validates a recovery token. The recovery token is validated and if valid, a success message is returned. + * @async + * @param {Object} req - The Express request object. + * @property {Object} req.body - The body of the request. + * @property {string} req.body.token - The recovery token to be validated. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status and a message indicating the validation of the recovery token. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422). + */ +const validateRecovery = async (req, res, next) => { + try { + await recoveryTokenValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } + + try { + await req.db.validateRecoveryToken(req, res); + return res.status(200).json({ + success: true, msg: successMessages.AUTH_VERIFY_RECOVERY_TOKEN, + }); + } catch (error) { + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "validateRecoveryTokenController") : null; + next(error); + } +}; + +/** + * Resets a user's password. The new password is validated and if valid, the user's password is updated in the database and a new JWT token is issued. + * @async + * @param {Object} req - The Express request object. + * @property {Object} req.body - The body of the request. + * @property {string} req.body.token - The recovery token. + * @property {string} req.body.password - The new password of the user. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the reset of the password, the updated user data (without password and avatar image), and a new JWT token. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422). + */ +const resetPassword = async (req, res, next) => { + try { + await newPasswordValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } + try { + const user = await req.db.resetPassword(req, res); + + const appSettings = await req.settingsService.getSettings(); + const token = issueToken(user._doc, appSettings); + res.status(200).json({ + success: true, msg: successMessages.AUTH_RESET_PASSWORD, data: {user, token}, + }); + } catch (error) { + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "resetPasswordController") : null; + next(error); + } }; /** @@ -465,81 +377,74 @@ const resetPasswordController = async (req, res, next) => { * @returns {Object} The response object with success status and message. * @throws {Error} If user validation fails or user is not found in the database. */ -const deleteUserController = async (req, res, next) => { - try { - const token = getTokenFromHeaders(req.headers); - const decodedToken = jwt.decode(token); - const { _id, email } = decodedToken; +const deleteUser = async (req, res, next) => { + try { + const token = getTokenFromHeaders(req.headers); + const decodedToken = jwt.decode(token); + const {email} = decodedToken; - // Check if the user exists - const user = await req.db.getUserByEmail(email); - if (!user) { - throw new Error(errorMessages.DB_USER_NOT_FOUND); + // Check if the user exists + const user = await req.db.getUserByEmail(email); + if (!user) { + next(new Error(errorMessages.DB_USER_NOT_FOUND)); + return; + } + + // 1. Find all the monitors associated with the team ID if superadmin + + const result = await req.db.getMonitorsByTeamId({ + params: {teamId: user.teamId}, + }); + if (user.role.includes("superadmin")) { + //2. Remove all jobs, delete checks and alerts + result?.monitors.length > 0 && (await Promise.all(result.monitors.map(async (monitor) => { + await req.jobQueue.deleteJob(monitor); + await req.db.deleteChecks(monitor._id); + await req.db.deletePageSpeedChecksByMonitorId(monitor._id); + await req.db.deleteNotificationsByMonitorId(monitor._id); + }))); + + // 3. Delete team + await req.db.deleteTeam(user.teamId); + // 4. Delete all other team members + await req.db.deleteAllOtherUsers(); + // 5. Delete each monitor + await req.db.deleteMonitorsByUserId(user._id); + } + // 6. Delete the user by id + await req.db.deleteUser(user._id); + + return res.status(200).json({ + success: true, msg: successMessages.AUTH_DELETE_USER, + }); + } catch (error) { + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "deleteUserController") : null; + next(error); } - - // 1. Find all the monitors associated with the team ID if superadmin - - const result = await req.db.getMonitorsByTeamId({ - params: { teamId: user.teamId }, - }); - if (user.role.includes("superadmin")) { - //2. Remove all jobs, delete checks and alerts - result?.monitors.length > 0 && - (await Promise.all( - result.monitors.map(async (monitor) => { - await req.jobQueue.deleteJob(monitor); - await req.db.deleteChecks(monitor._id); - await req.db.deletePageSpeedChecksByMonitorId(monitor._id); - await req.db.deleteNotificationsByMonitorId(monitor._id); - }) - )); - - // 3. Delete team - await req.db.deleteTeam(user.teamId); - // 4. Delete all other team members - await req.db.deleteAllOtherUsers(); - // 5. Delete each monitor - await req.db.deleteMonitorsByUserId(user._id); - } - // 6. Delete the user by id - await req.db.deleteUser(user._id); - - return res.status(200).json({ - success: true, - msg: successMessages.AUTH_DELETE_USER, - }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "deleteUserController") : null; - next(error); - } }; -const getAllUsersController = async (req, res) => { - try { - const allUsers = await req.db.getAllUsers(req, res); - res - .status(200) - .json({ success: true, msg: "Got all users", data: allUsers }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined - ? (error.method = "getAllUsersController") - : null; - next(error); - } +const getAllUsers = async (req, res) => { + try { + const allUsers = await req.db.getAllUsers(req, res); + res + .status(200) + .json({success: true, msg: "Got all users", data: allUsers}); + } catch (error) { + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "getAllUsersController") : null; + next(error); + } }; module.exports = { - registerController, - loginController, - userEditController, - inviteController, - inviteVerifyController, - checkSuperadminController, - recoveryRequestController, - validateRecoveryTokenController, - resetPasswordController, - deleteUserController, - getAllUsersController, + registerUser, + loginUser, + editUser, + checkSuperadminExists: checkSuperAdminExists, + requestRecovery, + validateRecovery, + resetPassword, + deleteUser, + getAllUsers, }; diff --git a/Server/controllers/inviteController.js b/Server/controllers/inviteController.js index da9b2496a..9863f9666 100644 --- a/Server/controllers/inviteController.js +++ b/Server/controllers/inviteController.js @@ -1,101 +1,111 @@ const { - inviteRoleValidation, - inviteBodyValidation, - inviteVerifciationBodyValidation, + inviteRoleValidation, + inviteBodyValidation, + inviteVerificationBodyValidation, } = require("../validation/joi"); const logger = require("../utils/logger"); require("dotenv").config(); -const { errorMessages, successMessages } = require("../utils/messages"); -var jwt = require("jsonwebtoken"); +const jwt = require("jsonwebtoken"); const SERVICE_NAME = "inviteController"; const getTokenFromHeaders = (headers) => { - const authorizationHeader = headers.authorization; - if (!authorizationHeader) throw new Error("No auth headers"); + const authorizationHeader = headers.authorization; + if (!authorizationHeader) throw new Error("No auth headers"); - const parts = authorizationHeader.split(" "); - if (parts.length !== 2 || parts[0] !== "Bearer") - throw new Error("Invalid auth headers"); + const parts = authorizationHeader.split(" "); + if (parts.length !== 2 || parts[0] !== "Bearer") + throw new Error("Invalid auth headers"); - return parts[1]; + return parts[1]; }; -const inviteController = async (req, res, next) => { - try { - // Only admins can invite - const token = getTokenFromHeaders(req.headers); - const { role, firstname, teamId } = jwt.decode(token); - req.body.teamId = teamId; +/** + * Issues an invitation to a new user. Only admins can invite new users. An invitation token is created and sent via email. + * @async + * @param {Object} req - The Express request object. + * @property {Object} req.headers - The headers of the request. + * @property {string} req.headers.authorization - The authorization header containing the JWT token. + * @property {Object} req.body - The body of the request. + * @property {string} req.body.email - The email of the user to be invited. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the sending of the invitation, and the invitation token. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422). + */ +const issueInvitation = async (req, res, next) => { try { - await inviteRoleValidation.validateAsync({ roles: role }); - await inviteBodyValidation.validateAsync(req.body); + // Only admins can invite + const token = getTokenFromHeaders(req.headers); + const {role, firstname, teamId} = jwt.decode(token); + req.body.teamId = teamId; + try { + await inviteRoleValidation.validateAsync({roles: role}); + await inviteBodyValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = + error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } + + const inviteToken = await req.db.requestInviteToken({...req.body}); + const {clientHost} = req.settingsService.getSettings(); + req.emailService + .buildAndSendEmail( + "employeeActivationTemplate", + { + name: firstname, + link: `${clientHost}/register/${inviteToken.token}`, + }, + req.body.email, + "Welcome to Uptime Monitor" + ) + .catch((error) => { + logger.error("Error sending invite email", { + service: SERVICE_NAME, + error: error.message, + }); + }); + + return res + .status(200) + .json({success: true, msg: "Invite sent", data: inviteToken}); } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined ? (error.method = "inviteController") : null; + next(error); } - - const inviteToken = await req.db.requestInviteToken({ ...req.body }); - const { clientHost } = req.settingsService.getSettings(); - req.emailService - .buildAndSendEmail( - "employeeActivationTemplate", - { - name: firstname, - link: `${clientHost}/register/${inviteToken.token}`, - }, - req.body.email, - "Welcome to Uptime Monitor" - ) - .catch((error) => { - logger.error("Error sending invite email", { - service: SERVICE_NAME, - error: error.message, - }); - }); - - return res - .status(200) - .json({ success: true, msg: "Invite sent", data: inviteToken }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "inviteController") : null; - next(error); - return; - } }; const inviteVerifyController = async (req, res, next) => { - try { - await inviteVerifciationBodyValidation.validateAsync(req.body); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } + try { + await inviteVerificationBodyValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = + error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } - try { - const invite = await req.db.getInviteToken(req.body.token); - res - .status(200) - .json({ status: "success", msg: "Invite verified", data: invite }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined - ? (error.method = "inviteVerifyController") - : null; - next(error); - return; - } + try { + const invite = await req.db.getInviteToken(req.body.token); + res + .status(200) + .json({status: "success", msg: "Invite verified", data: invite}); + } catch (error) { + error.service === undefined ? (error.service = SERVICE_NAME) : null; + error.method === undefined + ? (error.method = "inviteVerifyController") + : null; + next(error); + } }; module.exports = { - inviteController, - inviteVerifyController, + inviteController: issueInvitation, + inviteVerifyController, }; diff --git a/Server/controllers/maintenanceWindowController.js b/Server/controllers/maintenanceWindowController.js index 755d4c5bb..775c04728 100644 --- a/Server/controllers/maintenanceWindowController.js +++ b/Server/controllers/maintenanceWindowController.js @@ -5,8 +5,9 @@ const { getMaintenanceWindowsByMonitorIdParamValidation, } = require("../validation/joi"); +const {successMessages} = require("../utils/messages") + const SERVICE_NAME = "maintenanceWindowController"; -const { errorMessages, successMessages } = require("../utils/messages"); const createMaintenanceWindow = async (req, res, next) => { try { @@ -67,7 +68,7 @@ const getMaintenanceWindowsByUserId = async (req, res, next) => { return res.status(201).json({ success: true, - msg: successMessages.MAINTEANCE_WINDOW_GET_BY_USER, + msg: successMessages.MAINTENANCE_WINDOW_GET_BY_USER, data: maintenanceWindows, }); } catch (error) { @@ -100,7 +101,7 @@ const getMaintenanceWindowsByMonitorId = async (req, res, next) => { return res.status(201).json({ success: true, - msg: successMessages.MAINTEANCE_WINDOW_GET_BY_USER, + msg: successMessages.MAINTENANCE_WINDOW_GET_BY_USER, data: maintenanceWindows, }); } catch (error) { diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js index 5cda56634..3f77a412e 100644 --- a/Server/controllers/monitorController.js +++ b/Server/controllers/monitorController.js @@ -11,8 +11,6 @@ const { getMonitorStatsByIdParamValidation, getMonitorStatsByIdQueryValidation, getCertificateParamValidation, - getMonitorAggregateStatsParamValidation, - getMonitorAggregateStatsQueryValidation, } = require("../validation/joi"); const sslChecker = require("ssl-checker"); @@ -27,6 +25,7 @@ const logger = require("../utils/logger"); * @async * @param {Express.Request} req * @param {Express.Response} res + * @param {function} next * @returns {Promise} * @throws {Error} */ @@ -50,6 +49,7 @@ const getAllMonitors = async (req, res, next) => { * @async * @param {Express.Request} req * @param {Express.Response} res + * @param {function} next * @returns {Promise} * @throws {Error} */ @@ -69,7 +69,7 @@ const getMonitorStatsById = async (req, res, next) => { const monitorStats = await req.db.getMonitorStatsById(req); return res.json({ success: true, - msg: successMessages.MONTIOR_STATS_BY_ID, + msg: successMessages.MONITOR_STATS_BY_ID, data: monitorStats, }); } catch (error) { @@ -119,12 +119,15 @@ const getMonitorCertificate = async (req, res, next) => { }; /** - * Returns monitor with matching ID + * Retrieves a monitor by its ID. * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - * @throws {Error} + * @param {Object} req - The Express request object. + * @property {Object} req.params - The parameters of the request. + * @property {string} req.params.monitorId - The ID of the monitor to be retrieved. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message, and the retrieved monitor data. + * @throws {Error} If there is an error during the process, especially if the monitor is not found (404) or if there is a validation error (422). */ const getMonitorById = async (req, res, next) => { try { @@ -143,12 +146,11 @@ const getMonitorById = async (req, res, next) => { if (!monitor) { const error = new Error(errorMessages.MONITOR_GET_BY_ID); error.status = 404; - throw error; } return res.json({ success: true, - msg: successMessages.MONTIOR_GET_BY_ID, + msg: successMessages.MONITOR_GET_BY_ID, data: monitor, }); } catch (error) { @@ -159,14 +161,18 @@ const getMonitorById = async (req, res, next) => { }; /** - * Returns all monitors and a sumamry for a team with TeamID + * Retrieves all monitors and a summary for a team based on the team ID. * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - * @throws {Error} + * @param {Object} req - The Express request object. + * @property {Object} req.params - The parameters of the request. + * @property {string} req.params.teamId - The ID of the team. + * @property {Object} req.query - The query parameters of the request. + * @property {string} req.query.type - The type of the request. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message, and the data containing the monitors and summary for the team. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422). */ - const getMonitorsAndSummaryByTeamId = async (req, res, next) => { try { await getMonitorsAndSummaryByTeamIdParamValidation.validateAsync( @@ -177,8 +183,7 @@ const getMonitorsAndSummaryByTeamId = async (req, res, next) => { } catch (error) { error.status = 422; error.service = SERVICE_NAME; - error.method === undefined && - error.method === "getMonitorsAndSummaryByTeamId"; + error.method === undefined? error.method = "getMonitorsAndSummaryByTeamId": null; error.message = error.details?.[0]?.message || error.message || "Validation Error"; next(error); @@ -207,12 +212,16 @@ const getMonitorsAndSummaryByTeamId = async (req, res, next) => { }; /** - * Returns all monitors belong to team with TeamID + * Retrieves all monitors associated with a team by the team's ID. * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - * @throws {Error} + * @param {Object} req - The Express request object. + * @property {Object} req.params - The parameters of the request. + * @property {string} req.params.teamId - The ID of the team. + * @property {Object} req.query - The query parameters of the request. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message, and the data containing the monitors for the team. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422). */ const getMonitorsByTeamId = async (req, res, next) => { try { @@ -243,14 +252,16 @@ const getMonitorsByTeamId = async (req, res, next) => { }; /** - * Creates a new monitor + * Creates a new monitor and adds it to the job queue. * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - * @throws {Error} + * @param {Object} req - The Express request object. + * @property {Object} req.body - The body of the request. + * @property {Array} req.body.notifications - The notifications associated with the monitor. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the creation of the monitor, and the created monitor data. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422). */ - const createMonitor = async (req, res, next) => { try { await createMonitorBodyValidation.validateAsync(req.body); @@ -269,13 +280,12 @@ const createMonitor = async (req, res, next) => { const monitor = await req.db.createMonitor(req, res); if (notifications && notifications.length !== 0) { - const setNotifications = await Promise.all( - notifications.map(async (notification) => { - notification.monitorId = monitor._id; - await req.db.createNotification(notification); - }) + monitor.notifications = await Promise.all( + notifications.map(async (notification) => { + notification.monitorId = monitor._id; + await req.db.createNotification(notification); + }) ); - monitor.notifications = setNotifications; await monitor.save(); } // Add monitor to job queue @@ -293,14 +303,16 @@ const createMonitor = async (req, res, next) => { }; /** - * Delete a monitor by ID + * Deletes a monitor by its ID and also deletes associated checks, alerts, and notifications. * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - * @throws {Error} + * @param {Object} req - The Express request object. + * @property {Object} req.params - The parameters of the request. + * @property {string} req.params.monitorId - The ID of the monitor to be deleted. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status and a message indicating the deletion of the monitor. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422) or an error in deleting associated records. */ - const deleteMonitor = async (req, res, next) => { try { await getMonitorByIdParamValidation.validateAsync(req.params); @@ -331,7 +343,6 @@ const deleteMonitor = async (req, res, next) => { } ); } - return res .status(200) .json({ success: true, msg: successMessages.MONITOR_DELETE }); @@ -342,7 +353,18 @@ const deleteMonitor = async (req, res, next) => { } }; -const deleteAllMonitors = async (req, res) => { +/** + * Deletes all monitors associated with a team. + * @async + * @param {Object} req - The Express request object. + * @property {Object} req.headers - The headers of the request. + * @property {string} req.headers.authorization - The authorization header containing the JWT token. + * @param {Object} res - The Express response object. + * @param {function} next + * @returns {Object} The response object with a success status and a message indicating the number of deleted monitors. + * @throws {Error} If there is an error during the deletion process. + */ +const deleteAllMonitors = async (req, res, next) => { try { const token = getTokenFromHeaders(req.headers); const { jwtSecret } = req.settingsService.getSettings(); @@ -367,12 +389,17 @@ const deleteAllMonitors = async (req, res) => { }; /** - * Edit a monitor by ID + * Edits a monitor by its ID, updates its notifications, and updates its job in the job queue. * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - * @throws {Error} + * @param {Object} req - The Express request object. + * @property {Object} req.params - The parameters of the request. + * @property {string} req.params.monitorId - The ID of the monitor to be edited. + * @property {Object} req.body - The body of the request. + * @property {Array} req.body.notifications - The notifications to be associated with the monitor. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the editing of the monitor, and the edited monitor data. + * @throws {Error} If there is an error during the process, especially if there is a validation error (422). */ const editMonitor = async (req, res, next) => { try { @@ -423,6 +450,17 @@ const editMonitor = async (req, res, next) => { } }; +/** + * Pauses or resumes a monitor based on its current state. + * @async + * @param {Object} req - The Express request object. + * @property {Object} req.params - The parameters of the request. + * @property {string} req.params.monitorId - The ID of the monitor to be paused or resumed. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the new state of the monitor, and the updated monitor data. + * @throws {Error} If there is an error during the process. + */ const pauseMonitor = async (req, res, next) => { try { await pauseMonitorParamValidation.validateAsync(req.params); @@ -458,6 +496,17 @@ const pauseMonitor = async (req, res, next) => { } }; +/** + * Adds demo monitors for a team. + * @async + * @param {Object} req - The Express request object. + * @property {Object} req.headers - The headers of the request. + * @property {string} req.headers.authorization - The authorization header containing the JWT token. + * @param {Object} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating the addition of demo monitors, and the number of demo monitors added. + * @throws {Error} If there is an error during the process. + */ const addDemoMonitors = async (req, res, next) => { try { const token = getTokenFromHeaders(req.headers); diff --git a/Server/db/FakeDb.js b/Server/db/FakeDb.js index e4f36d001..a7c8bf4ee 100644 --- a/Server/db/FakeDb.js +++ b/Server/db/FakeDb.js @@ -20,8 +20,8 @@ // The rest of the code is the same, as all the `db` methods are standardized. // ************************** -const Monitor = require("../models/Monitor"); -const UserModel = require("../models/User"); +const Monitor = require("./models/Monitor"); +const UserModel = require("./models/User"); const bcrypt = require("bcrypt"); let FAKE_MONITOR_DATA = []; diff --git a/Server/models/AppSettings.js b/Server/db/models/AppSettings.js similarity index 100% rename from Server/models/AppSettings.js rename to Server/db/models/AppSettings.js diff --git a/Server/models/Check.js b/Server/db/models/Check.js similarity index 93% rename from Server/models/Check.js rename to Server/db/models/Check.js index acb20dfb9..7705ba3fd 100644 --- a/Server/models/Check.js +++ b/Server/db/models/Check.js @@ -1,6 +1,6 @@ const mongoose = require("mongoose"); -const EmailService = require("../service/emailService"); -const Notification = require("../models/Notification"); +const EmailService = require("../../service/emailService"); +const Notification = require("./Notification"); /** * Check Schema for MongoDB collection. diff --git a/Server/models/InviteToken.js b/Server/db/models/InviteToken.js similarity index 100% rename from Server/models/InviteToken.js rename to Server/db/models/InviteToken.js diff --git a/Server/models/MaintenanceWindow.js b/Server/db/models/MaintenanceWindow.js similarity index 100% rename from Server/models/MaintenanceWindow.js rename to Server/db/models/MaintenanceWindow.js diff --git a/Server/models/Monitor.js b/Server/db/models/Monitor.js similarity index 100% rename from Server/models/Monitor.js rename to Server/db/models/Monitor.js diff --git a/Server/models/Notification.js b/Server/db/models/Notification.js similarity index 100% rename from Server/models/Notification.js rename to Server/db/models/Notification.js diff --git a/Server/models/PageSpeedCheck.js b/Server/db/models/PageSpeedCheck.js similarity index 100% rename from Server/models/PageSpeedCheck.js rename to Server/db/models/PageSpeedCheck.js diff --git a/Server/models/RecoveryToken.js b/Server/db/models/RecoveryToken.js similarity index 100% rename from Server/models/RecoveryToken.js rename to Server/db/models/RecoveryToken.js diff --git a/Server/models/Team.js b/Server/db/models/Team.js similarity index 100% rename from Server/models/Team.js rename to Server/db/models/Team.js diff --git a/Server/models/User.js b/Server/db/models/User.js similarity index 100% rename from Server/models/User.js rename to Server/db/models/User.js diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index 268e62798..aeb993433 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -1,6 +1,6 @@ const mongoose = require("mongoose"); -const UserModel = require("../../models/User"); -const AppSettings = require("../../models/AppSettings"); +const UserModel = require("../models/User"); +const AppSettings = require("../models/AppSettings"); //**************************************** // DB Connection diff --git a/Server/db/mongo/modules/checkModule.js b/Server/db/mongo/modules/checkModule.js index c18491021..193d793c6 100644 --- a/Server/db/mongo/modules/checkModule.js +++ b/Server/db/mongo/modules/checkModule.js @@ -1,6 +1,6 @@ -const Check = require("../../../models/Check"); -const Monitor = require("../../../models/Monitor"); -const User = require("../../../models/User"); +const Check = require("../../models/Check"); +const Monitor = require("../../models/Monitor"); +const User = require("../../models/User"); const logger = require("../../../utils/logger"); const SERVICE_NAME = "checkModule"; const dateRangeLookup = { diff --git a/Server/db/mongo/modules/inviteModule.js b/Server/db/mongo/modules/inviteModule.js index 9a0d35621..8152941d7 100644 --- a/Server/db/mongo/modules/inviteModule.js +++ b/Server/db/mongo/modules/inviteModule.js @@ -1,4 +1,4 @@ -const InviteToken = require("../../../models/InviteToken"); +const InviteToken = require("../../models/InviteToken"); const crypto = require("crypto"); const { errorMessages } = require("../../../utils/messages"); const SERVICE_NAME = "inviteModule"; diff --git a/Server/db/mongo/modules/maintenaceWindowModule.js b/Server/db/mongo/modules/maintenaceWindowModule.js index bcb11e816..f49c9dca4 100644 --- a/Server/db/mongo/modules/maintenaceWindowModule.js +++ b/Server/db/mongo/modules/maintenaceWindowModule.js @@ -1,4 +1,4 @@ -const MaintenanceWindow = require("../../../models/MaintenanceWindow"); +const MaintenanceWindow = require("../../models/MaintenanceWindow"); const SERVICE_NAME = "maintenanceWindowModule"; /** diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js index 002bf9c41..bac2e146b 100644 --- a/Server/db/mongo/modules/monitorModule.js +++ b/Server/db/mongo/modules/monitorModule.js @@ -1,8 +1,8 @@ -const Monitor = require("../../../models/Monitor"); -const Check = require("../../../models/Check"); -const PageSpeedCheck = require("../../../models/PageSpeedCheck"); +const Monitor = require("../../models/Monitor"); +const Check = require("../../models/Check"); +const PageSpeedCheck = require("../../models/PageSpeedCheck"); const { errorMessages } = require("../../../utils/messages"); -const Notification = require("../../../models/Notification"); +const Notification = require("../../models/Notification"); const { NormalizeData } = require("../../../utils/dataUtils"); const demoMonitors = require("../../../utils/demoMonitors.json"); const SERVICE_NAME = "monitorModule"; @@ -147,7 +147,7 @@ const getMonitorStatsById = async (req) => { let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query; const monitor = await Monitor.findById(monitorId); if (monitor === null || monitor === undefined) { - throw new Error(errorMessages.DB_FIND_MONTIOR_BY_ID(monitorId)); + throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId)); } // This effectively removes limit, returning all checks if (limit === undefined) limit = 0; @@ -283,7 +283,7 @@ const getMonitorById = async (monitorId) => { try { const monitor = await Monitor.findById(monitorId); if (monitor === null || monitor === undefined) { - throw new Error(errorMessages.DB_FIND_MONTIOR_BY_ID(monitorId)); + throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId)); } // Get notifications const notifications = await Notification.find({ @@ -481,7 +481,7 @@ const deleteMonitor = async (req, res) => { try { const monitor = await Monitor.findByIdAndDelete(monitorId); if (!monitor) { - throw new Error(errorMessages.DB_FIND_MONTIOR_BY_ID(monitorId)); + throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId)); } return monitor; } catch (error) { diff --git a/Server/db/mongo/modules/notificationModule.js b/Server/db/mongo/modules/notificationModule.js index 89df2130b..ecc52644d 100644 --- a/Server/db/mongo/modules/notificationModule.js +++ b/Server/db/mongo/modules/notificationModule.js @@ -1,4 +1,4 @@ -const Notification = require("../../../models/Notification"); +const Notification = require("../../models/Notification"); const SERVICE_NAME = "notificationModule"; /** * Creates a new notification. diff --git a/Server/db/mongo/modules/pageSpeedCheckModule.js b/Server/db/mongo/modules/pageSpeedCheckModule.js index 8b76555c5..a0c7694c8 100644 --- a/Server/db/mongo/modules/pageSpeedCheckModule.js +++ b/Server/db/mongo/modules/pageSpeedCheckModule.js @@ -1,4 +1,4 @@ -const PageSpeedCheck = require("../../../models/PageSpeedCheck"); +const PageSpeedCheck = require("../../models/PageSpeedCheck"); const SERVICE_NAME = "pageSpeedCheckModule"; /** * Create a PageSpeed check for a monitor diff --git a/Server/db/mongo/modules/recoveryModule.js b/Server/db/mongo/modules/recoveryModule.js index 469954cef..4649fa084 100644 --- a/Server/db/mongo/modules/recoveryModule.js +++ b/Server/db/mongo/modules/recoveryModule.js @@ -1,5 +1,5 @@ -const UserModel = require("../../../models/User"); -const RecoveryToken = require("../../../models/RecoveryToken"); +const UserModel = require("../../models/User"); +const RecoveryToken = require("../../models/RecoveryToken"); const crypto = require("crypto"); const { errorMessages } = require("../../../utils/messages"); const SERVICE_NAME = "recoveryModule"; diff --git a/Server/db/mongo/modules/settingsModule.js b/Server/db/mongo/modules/settingsModule.js index b7e6b765d..f7cfc9ce1 100644 --- a/Server/db/mongo/modules/settingsModule.js +++ b/Server/db/mongo/modules/settingsModule.js @@ -1,4 +1,4 @@ -const AppSettings = require("../../../models/AppSettings"); +const AppSettings = require("../../models/AppSettings"); const SERVICE_NAME = "SettingsModule"; const getAppSettings = async () => { diff --git a/Server/db/mongo/modules/userModule.js b/Server/db/mongo/modules/userModule.js index bfdd54a4c..c72bd7c5d 100644 --- a/Server/db/mongo/modules/userModule.js +++ b/Server/db/mongo/modules/userModule.js @@ -1,5 +1,5 @@ -const UserModel = require("../../../models/User"); -const TeamModel = require("../../../models/Team"); +const UserModel = require("../../models/User"); +const TeamModel = require("../../models/Team"); const { errorMessages } = require("../../../utils/messages"); const { GenerateAvatarImage } = require("../../../utils/imageProcessing"); diff --git a/Server/middleware/verifyJWT.js b/Server/middleware/verifyJWT.js index 0007bad39..8e2e88b6f 100644 --- a/Server/middleware/verifyJWT.js +++ b/Server/middleware/verifyJWT.js @@ -4,7 +4,7 @@ const SERVICE_NAME = "verifyJWT"; const TOKEN_PREFIX = "Bearer "; const { errorMessages } = require("../utils/messages"); const { parse } = require("path"); -const User = require("../models/User"); +const User = require("../db/models/User"); /** * Verifies the JWT token * @function diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index 362f6a5a2..ce6ec440e 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -4,47 +4,46 @@ const { verifyOwnership } = require("../middleware/verifyOwnership"); const { isAllowed } = require("../middleware/isAllowed"); const multer = require("multer"); const upload = multer(); -const User = require("../models/User"); +const User = require("../db/models/User"); const { - registerController, - loginController, - logoutController, - userEditController, - recoveryRequestController, - validateRecoveryTokenController, - resetPasswordController, - checkSuperadminController, - getAllUsersController, - deleteUserController, + registerUser, + loginUser, + editUser, + requestRecovery, + validateRecovery, + resetPassword, + checkSuperadminExists, + getAllUsers, + deleteUser, } = require("../controllers/authController"); //Auth routes -router.post("/register", upload.single("profileImage"), registerController); -router.post("/login", loginController); +router.post("/register", upload.single("profileImage"), registerUser); +router.post("/login", loginUser); router.put( "/user/:userId", upload.single("profileImage"), verifyJWT, - userEditController + editUser ); -router.get("/users/superadmin", checkSuperadminController); +router.get("/users/superadmin", checkSuperadminExists); router.get( "/users", verifyJWT, isAllowed(["admin", "superadmin"]), - getAllUsersController + getAllUsers ); router.delete( "/user/:userId", verifyJWT, verifyOwnership(User, "userId"), - deleteUserController + deleteUser ); //Recovery routes -router.post("/recovery/request", recoveryRequestController); -router.post("/recovery/validate", validateRecoveryTokenController); -router.post("/recovery/reset/", resetPasswordController); +router.post("/recovery/request", requestRecovery); +router.post("/recovery/validate", validateRecovery); +router.post("/recovery/reset/", resetPassword); module.exports = router; diff --git a/Server/routes/checkRoute.js b/Server/routes/checkRoute.js index fe99e7271..47b48809d 100644 --- a/Server/routes/checkRoute.js +++ b/Server/routes/checkRoute.js @@ -2,7 +2,7 @@ const router = require("express").Router(); const checkController = require("../controllers/checkController"); const { verifyOwnership } = require("../middleware/verifyOwnership"); const { isAllowed } = require("../middleware/isAllowed"); -const Monitor = require("../models/Monitor"); +const Monitor = require("../db/models/Monitor"); router.get("/:monitorId", checkController.getChecks); router.post( diff --git a/Server/routes/maintenanceWindowRoute.js b/Server/routes/maintenanceWindowRoute.js index c357df76b..8ed15b609 100644 --- a/Server/routes/maintenanceWindowRoute.js +++ b/Server/routes/maintenanceWindowRoute.js @@ -1,7 +1,7 @@ const router = require("express").Router(); const maintenanceWindowController = require("../controllers/maintenanceWindowController"); const { verifyOwnership } = require("../middleware/verifyOwnership"); -const Monitor = require("../models/Monitor"); +const Monitor = require("../db/models/Monitor"); router.get( "/monitor/:monitorId", diff --git a/Server/routes/settingsRoute.js b/Server/routes/settingsRoute.js index 3cbfff2b8..521987aec 100644 --- a/Server/routes/settingsRoute.js +++ b/Server/routes/settingsRoute.js @@ -1,7 +1,7 @@ const router = require("express").Router(); const settingsController = require("../controllers/settingsController"); const { isAllowed } = require("../middleware/isAllowed"); -const Monitor = require("../models/Monitor"); +const Monitor = require("../db/models/Monitor"); router.get("/", settingsController.getAppSettings); router.put( diff --git a/Server/service/settingsService.js b/Server/service/settingsService.js index b4769d043..1b86ab89f 100644 --- a/Server/service/settingsService.js +++ b/Server/service/settingsService.js @@ -1,7 +1,6 @@ +const { env } = require("process"); const AppSettings = require("../models/AppSettings"); const SERVICE_NAME = "SettingsService"; - -// Load settings from environment variables const envConfig = { logLevel: undefined, apiBaseUrl: undefined, diff --git a/Server/utils/messages.js b/Server/utils/messages.js index 59fa53f49..c1e4d887b 100644 --- a/Server/utils/messages.js +++ b/Server/utils/messages.js @@ -13,7 +13,7 @@ const errorMessages = { NO_AUTH_TOKEN: "No auth token provided", INVALID_AUTH_TOKEN: "Invalid auth token", - //Onwership Middleware + //Ownership Middleware VERIFY_OWNER_NOT_FOUND: "Document not found", VERIFY_OWNER_UNAUTHORIZED: "Unauthorized access", @@ -26,17 +26,16 @@ const errorMessages = { DB_TOKEN_NOT_FOUND: "Token not found", DB_RESET_PASSWORD_BAD_MATCH: "New password must be different from old password", - DB_FIND_MONTIOR_BY_ID: (monitorId) => + DB_FIND_MONITOR_BY_ID: (monitorId) => `Monitor with id ${monitorId} not found`, DB_DELETE_CHECKS: (monitorId) => `No checks found for monitor with id ${monitorId}`, - DB_DELETE_ALERT: (alertId) => `Alert with id ${alertId} not found`, //Auth errors AUTH_INCORRECT_PASSWORD: "Incorrect password", AUTH_UNAUTHORIZED: "Unauthorized access", - // Monitor Errros + // Monitor Errors MONITOR_GET_BY_ID: "Monitor not found", MONITOR_GET_BY_USER_ID: "No monitors found for user", @@ -77,8 +76,8 @@ const successMessages = { //Monitor Controller MONITOR_GET_ALL: "Got all monitors successfully", - MONTIOR_STATS_BY_ID: "Got monitor stats by Id successfully", - MONTIOR_GET_BY_ID: "Got monitor by Id successfully", + MONITOR_STATS_BY_ID: "Got monitor stats by Id successfully", + MONITOR_GET_BY_ID: "Got monitor by Id successfully", MONITOR_GET_BY_USER_ID: (userId) => `Got monitor for ${userId} successfully"`, MONITOR_CREATE: "Monitor created successfully", MONITOR_DELETE: "Monitor deleted successfully", @@ -94,7 +93,7 @@ const successMessages = { //Maintenance Window Controller MAINTENANCE_WINDOW_CREATE: "Maintenance Window created successfully", - MAINTEANCE_WINDOW_GET_BY_USER: "Got Maintenance Windows by User successfully", + MAINTENANCE_WINDOW_GET_BY_USER: "Got Maintenance Windows by User successfully", //Ping Operations PING_SUCCESS: "Success", diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 91ba53b94..1af324008 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -410,7 +410,7 @@ module.exports = { newPasswordValidation, inviteRoleValidation, inviteBodyValidation, - inviteVerifciationBodyValidation, + inviteVerificationBodyValidation: inviteVerifciationBodyValidation, createMonitorBodyValidation, getMonitorByIdParamValidation, getMonitorByIdQueryValidation,