From 3e8d4cb49bb47123ee4390feec240cc12863d26e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 18 Jan 2026 05:38:50 +0000 Subject: [PATCH] convert to ts --- server/src/config/services.ts | 3 +- .../invites/IInvitesRepository.ts | 2 + .../invites/MongoInviteRepository.ts | 18 ++++++ server/src/service/business/inviteService.ts | 60 +++++++++++++++++++ 4 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 server/src/service/business/inviteService.ts diff --git a/server/src/config/services.ts b/server/src/config/services.ts index 6b91bcf63..bbb42984e 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -260,10 +260,9 @@ export const initializeServices = async ({ const diagnosticService = new DiagnosticService(); const inviteService = new InviteService({ - db, + invitesRepository, settingsService, emailService, - stringService, errorService, }); const maintenanceWindowService = new MaintenanceWindowService({ diff --git a/server/src/repositories/invites/IInvitesRepository.ts b/server/src/repositories/invites/IInvitesRepository.ts index 066a51a0f..74a7ad68c 100644 --- a/server/src/repositories/invites/IInvitesRepository.ts +++ b/server/src/repositories/invites/IInvitesRepository.ts @@ -2,7 +2,9 @@ import type { Invite } from "@/types/index.js"; export interface IInvitesRepository { // create + create(invite: Partial): Promise; // fetch + findByToken(token: string): Promise; findByTokenAndDelete(token: string): Promise; // update diff --git a/server/src/repositories/invites/MongoInviteRepository.ts b/server/src/repositories/invites/MongoInviteRepository.ts index 16e56440b..e9243e96e 100644 --- a/server/src/repositories/invites/MongoInviteRepository.ts +++ b/server/src/repositories/invites/MongoInviteRepository.ts @@ -3,6 +3,7 @@ import type { Invite } from "@/types/index.js"; import { type InviteDocument, InviteModel } from "@/db/models/index.js"; import { AppError } from "@/utils/AppError.js"; import mongoose from "mongoose"; +import crypto from "crypto"; class MongoInvitesRepository implements IInvitesRepository { private toStringId = (value?: mongoose.Types.ObjectId | string | null): string => { @@ -32,6 +33,23 @@ class MongoInvitesRepository implements IInvitesRepository { }; }; + create = async (invite: Partial) => { + await InviteModel.deleteMany({ email: invite.email }); + invite.token = crypto.randomBytes(32).toString("hex"); + let inviteToken = await InviteModel.create(invite); + return this.toEntity(inviteToken); + }; + + findByToken = async (token: string) => { + const invite = await InviteModel.findOne({ + token, + }); + if (invite === null) { + throw new AppError({ message: "Invite not found", status: 404 }); + } + return this.toEntity(invite); + }; + findByTokenAndDelete = async (token: string) => { const invite = await InviteModel.findOneAndDelete({ token, diff --git a/server/src/service/business/inviteService.ts b/server/src/service/business/inviteService.ts new file mode 100644 index 000000000..cdb860fba --- /dev/null +++ b/server/src/service/business/inviteService.ts @@ -0,0 +1,60 @@ +import type { Invite } from "@/types/index.js"; +import type { IInvitesRepository } from "@/repositories/index.js"; + +const SERVICE_NAME = "inviteService"; + +class InviteService { + static SERVICE_NAME = SERVICE_NAME; + + private settingsService: any; + private emailService: any; + private errorService: any; + private invitesRepository: IInvitesRepository; + + constructor({ + invitesRepository, + settingsService, + emailService, + errorService, + }: { + invitesRepository: IInvitesRepository; + settingsService: any; + emailService: any; + errorService: any; + }) { + this.invitesRepository = invitesRepository; + this.settingsService = settingsService; + this.emailService = emailService; + this.errorService = errorService; + } + + get serviceName() { + return InviteService.SERVICE_NAME; + } + + getInviteToken = async ({ invite, teamId }: { invite: Partial; teamId: string }) => { + invite.teamId = teamId; + const inviteToken = await this.invitesRepository.create(invite); + return inviteToken; + }; + + sendInviteEmail = async ({ invite, firstName }: { invite: Partial; firstName: any }) => { + const inviteToken = await this.invitesRepository.create(invite); + const { clientHost } = this.settingsService.getSettings(); + + const html = await this.emailService.buildEmail("employeeActivationTemplate", { + name: firstName, + link: `${clientHost}/register/${inviteToken.token}`, + }); + const result = await this.emailService.sendEmail(invite.email, "Welcome to Uptime Monitor", html); + if (!result) { + throw this.errorService.createServerError("Failed to send invite e-mail... Please verify your settings."); + } + }; + + verifyInviteToken = async ({ inviteToken }: { inviteToken: string }) => { + return await this.invitesRepository.findByToken(inviteToken); + }; +} + +export default InviteService;