refactor invite module into class

This commit is contained in:
Alex Holliday
2025-07-29 19:53:11 -07:00
parent f934bbf829
commit ca02ed9d18
5 changed files with 60 additions and 102 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<InviteToken>} 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<InviteToken>} 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<InviteToken>} 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;

View File

@@ -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;
};
}

View File

@@ -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 {