From ca02ed9d18b82709648b402db426038de573c348 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 29 Jul 2025 19:53:11 -0700 Subject: [PATCH] refactor invite module into class --- server/src/config/services.js | 5 +- server/src/db/mongo/MongoDB.js | 16 +-- server/src/db/mongo/modules/inviteModule.js | 133 +++++++------------ server/src/service/business/inviteService.js | 6 +- server/src/service/business/userService.js | 2 +- 5 files changed, 60 insertions(+), 102 deletions(-) diff --git a/server/src/config/services.js b/server/src/config/services.js index c2ecae200..ae3a4d27b 100644 --- a/server/src/config/services.js +++ b/server/src/config/services.js @@ -38,7 +38,9 @@ import HardwareCheck from "../db/models/HardwareCheck.js"; import PageSpeedCheck from "../db/models/PageSpeedCheck.js"; import Monitor from "../db/models/Monitor.js"; import User from "../db/models/User.js"; +import InviteToken from "../db/models/InviteToken.js"; +import InviteModule from "../db/mongo/modules/inviteModule.js"; import CheckModule from "../db/mongo/modules/checkModule.js"; export const initializeServices = async ({ logger, envSettings, settingsService }) => { @@ -52,7 +54,8 @@ export const initializeServices = async ({ logger, envSettings, settingsService // Create DB const checkModule = new CheckModule({ logger, Check, HardwareCheck, PageSpeedCheck, Monitor, User }); - const db = new MongoDB({ logger, envSettings, checkModule }); + const inviteModule = new InviteModule({ InviteToken, crypto, stringService }); + const db = new MongoDB({ logger, envSettings, checkModule, inviteModule }); await db.connect(); const networkService = new NetworkService(axios, ping, logger, http, Docker, net, stringService, settingsService); diff --git a/server/src/db/mongo/MongoDB.js b/server/src/db/mongo/MongoDB.js index ef7179d35..1126b5ca6 100755 --- a/server/src/db/mongo/MongoDB.js +++ b/server/src/db/mongo/MongoDB.js @@ -7,12 +7,6 @@ import AppSettings from "../models/AppSettings.js"; import * as userModule from "./modules/userModule.js"; -//**************************************** -// Invite Token Operations -//**************************************** - -import * as inviteModule from "./modules/inviteModule.js"; - //**************************************** // Recovery Operations //**************************************** @@ -35,12 +29,6 @@ import * as pageSpeedCheckModule from "./modules/pageSpeedCheckModule.js"; //**************************************** import * as hardwareCheckModule from "./modules/hardwareCheckModule.js"; -//**************************************** -// Checks -//**************************************** - -import * as checkModule from "./modules/checkModule.js"; - //**************************************** // Maintenance Window //**************************************** @@ -69,11 +57,11 @@ import * as diagnosticModule from "./modules/diagnosticModule.js"; class MongoDB { static SERVICE_NAME = "MongoDB"; - constructor({ logger, envSettings, checkModule }) { + constructor({ logger, envSettings, checkModule, inviteModule }) { this.logger = logger; this.envSettings = envSettings; Object.assign(this, userModule); - Object.assign(this, inviteModule); + this.inviteModule = inviteModule; Object.assign(this, recoveryModule); Object.assign(this, monitorModule); Object.assign(this, pageSpeedCheckModule); diff --git a/server/src/db/mongo/modules/inviteModule.js b/server/src/db/mongo/modules/inviteModule.js index 89d8ad8d7..444e51efd 100755 --- a/server/src/db/mongo/modules/inviteModule.js +++ b/server/src/db/mongo/modules/inviteModule.js @@ -1,89 +1,56 @@ -import InviteToken from "../../models/InviteToken.js"; -import crypto from "crypto"; -import ServiceRegistry from "../../../service/system/serviceRegistry.js"; -import StringService from "../../../service/system/stringService.js"; - const SERVICE_NAME = "inviteModule"; -/** - * Request an invite token for a user. - * - * This function deletes any existing invite tokens for the user's email, - * generates a new token, saves it, and then returns the new token. - * - * @param {Object} userData - The user data. - * @param {string} userData.email - The user's email. - * @param {mongoose.Schema.Types.ObjectId} userData.teamId - The ID of the team. - * @param {Array} userData.role - The user's role(s). - * @param {Date} [userData.expiry=Date.now] - The expiry date of the token. Defaults to the current date and time. - * @returns {Promise} The invite token. - * @throws {Error} If there is an error. - */ -const requestInviteToken = async (userData) => { - try { - await InviteToken.deleteMany({ email: userData.email }); - userData.token = crypto.randomBytes(32).toString("hex"); - let inviteToken = new InviteToken(userData); - await inviteToken.save(); - return inviteToken; - } catch (error) { - error.service = SERVICE_NAME; - error.method = "requestInviteToken"; - throw error; - } -}; -/** - * Retrieves an invite token - * - * This function searches for an invite token in the database and deletes it. - * If the invite token is not found, it throws an error. - * - * @param {string} token - The invite token to search for. - * @returns {Promise} The invite token data. - * @throws {Error} If the invite token is not found or there is another error. - */ -const getInviteToken = async (token) => { - const stringService = ServiceRegistry.get(StringService.SERVICE_NAME); - try { - const invite = await InviteToken.findOne({ - token, - }); - if (invite === null) { - throw new Error(stringService.authInviteNotFound); +class InviteModule { + constructor({ InviteToken, crypto, stringService }) { + this.InviteToken = InviteToken; + this.crypto = crypto; + this.stringService = stringService; + } + + requestInviteToken = async (userData) => { + try { + await this.InviteToken.deleteMany({ email: userData.email }); + userData.token = this.crypto.randomBytes(32).toString("hex"); + let inviteToken = new this.InviteToken(userData); + await inviteToken.save(); + return inviteToken; + } catch (error) { + error.service = SERVICE_NAME; + error.method = "requestInviteToken"; + throw error; } - return invite; - } catch (error) { - error.service = SERVICE_NAME; - error.method = "getInviteToken"; - throw error; - } -}; + }; -/** - * Retrieves and deletes an invite token - * - * This function searches for an invite token in the database and deletes it. - * If the invite token is not found, it throws an error. - * - * @param {string} token - The invite token to search for. - * @returns {Promise} The invite token data. - * @throws {Error} If the invite token is not found or there is another error. - */ -const getInviteTokenAndDelete = async (token) => { - const stringService = ServiceRegistry.get(StringService.SERVICE_NAME); - try { - const invite = await InviteToken.findOneAndDelete({ - token, - }); - if (invite === null) { - throw new Error(stringService.authInviteNotFound); + getInviteToken = async (token) => { + try { + const invite = await this.InviteToken.findOne({ + token, + }); + if (invite === null) { + throw new Error(this.stringService.authInviteNotFound); + } + return invite; + } catch (error) { + error.service = SERVICE_NAME; + error.method = "getInviteToken"; + throw error; } - return invite; - } catch (error) { - error.service = SERVICE_NAME; - error.method = "getInviteTokenAndDelete"; - throw error; - } -}; + }; + getInviteTokenAndDelete = async (token) => { + try { + const invite = await this.InviteToken.findOneAndDelete({ + token, + }); + if (invite === null) { + throw new Error(this.stringService.authInviteNotFound); + } + return invite; + } catch (error) { + error.service = SERVICE_NAME; + error.method = "getInviteTokenAndDelete"; + throw error; + } + }; +} -export { requestInviteToken, getInviteToken, getInviteTokenAndDelete }; +export default InviteModule; diff --git a/server/src/service/business/inviteService.js b/server/src/service/business/inviteService.js index 161045971..369ed195a 100644 --- a/server/src/service/business/inviteService.js +++ b/server/src/service/business/inviteService.js @@ -17,12 +17,12 @@ class InviteService { getInviteToken = async ({ invite, teamId }) => { invite.teamId = teamId; - const inviteToken = await this.db.requestInviteToken(invite); + const inviteToken = await this.db.inviteModule.requestInviteToken(invite); return inviteToken; }; sendInviteEmail = async ({ inviteRequest, firstName }) => { - const inviteToken = await this.db.requestInviteToken({ ...inviteRequest }); + const inviteToken = await this.db.inviteModule.requestInviteToken({ ...inviteRequest }); const { clientHost } = this.settingsService.getSettings(); const html = await this.emailService.buildEmail("employeeActivationTemplate", { @@ -36,7 +36,7 @@ class InviteService { }; verifyInviteToken = async ({ inviteToken }) => { - const invite = await this.db.getInviteToken(inviteToken); + const invite = await this.db.inviteModule.getInviteToken(inviteToken); return invite; }; } diff --git a/server/src/service/business/userService.js b/server/src/service/business/userService.js index d0d1a1205..5eb776376 100644 --- a/server/src/service/business/userService.js +++ b/server/src/service/business/userService.js @@ -31,7 +31,7 @@ class UserService { // If superAdmin exists, a token should be attached to all further register requests const superAdminExists = await this.db.checkSuperadmin(); if (superAdminExists) { - const invitedUser = await this.db.getInviteTokenAndDelete(user.inviteToken); + const invitedUser = await this.db.inviteModule.getInviteTokenAndDelete(user.inviteToken); user.role = invitedUser.role; user.teamId = invitedUser.teamId; } else {