import { Result, UniqueID } from "@common/domain"; import { ITransactionManager } from "@common/infrastructure/database"; import { AuthenticatedUser, EmailAddress, IAuthenticatedUserRepository, PasswordHash, Username, } from "@contexts/auth/domain"; import { IAuthProvider } from "./auth-provider.interface"; import { IAuthService } from "./auth-service.interface"; export class AuthService implements IAuthService { private readonly _respository!: IAuthenticatedUserRepository; private readonly _transactionManager!: ITransactionManager; private readonly _authProvider: IAuthProvider; constructor( repository: IAuthenticatedUserRepository, transactionManager: ITransactionManager, authProvider: IAuthProvider ) { this._respository = repository; this._transactionManager = transactionManager; this._authProvider = authProvider; } /** * * Registra un nuevo usuario en la base de datos bajo transacci贸n. */ async registerUser(params: { username: Username; email: EmailAddress; passwordHash: PasswordHash; }): Promise> { try { return await this._transactionManager.complete(async (transaction) => { const { username, email, passwordHash } = params; // Verificar si el usuario ya existe const userExists = await this._respository.findUserByEmail(email, transaction); if (userExists.isSuccess && userExists.data) { return Result.fail(new Error("Email is already registered")); } if (userExists.isFailure) { return Result.fail(userExists.error); } const newUserId = UniqueID.generateNewID().data; const userOrError = AuthenticatedUser.create( { username, email, passwordHash, roles: ["USER"], }, newUserId ); if (userOrError.isFailure) { return Result.fail(userOrError.error); } const createdResult = await this._respository.createUser(userOrError.data, transaction); if (createdResult.isFailure) { return Result.fail(createdResult.error); } return Result.ok(userOrError.data); }); } catch (error: unknown) { return Result.fail(error as Error); } } /** * * Autentica a un usuario validando su email y contrase帽a. */ async loginUser(params: { email: EmailAddress; passwordHash: PasswordHash; }): Promise> { try { return await this._transactionManager.complete(async (transaction) => { const { email, passwordHash } = params; // 馃敼 Verificar si el usuario existe en la base de datos const userResult = await this._respository.findUserByEmail(email, transaction); if (userResult.isFailure) { return Result.fail(new Error("Invalid email or password")); } const user = userResult.data; if (!user) { return Result.fail(new Error("Invalid email or password")); } // 馃敼 Verificar que la contrase帽a sea correcta const isValidPassword = await user.comparePassword(passwordHash); if (!isValidPassword) { return Result.fail(new Error("Invalid email or password")); } // 馃敼 Generar Access Token y Refresh Token user.accessToken = this._authProvider.generateAccessToken({ userId: user.id.toString(), email: email.toString(), roles: ["USER"], }); user.refreshToken = this._authProvider.generateRefreshToken({ userId: user.id.toString(), }); return Result.ok(user); }); } catch (error: unknown) { return Result.fail(error as Error); } } /** * 馃敼 `selectCompany` * Permite a un usuario seleccionar una empresa activa en la sesi贸n bajo transacci贸n. */ /*static async selectCompany( userId: string, companyId: string ): Promise> { return await authUserRepository.executeTransaction(async (transaction) => { const user = await authUserRepository.findById(userId, transaction); if (user.isFailure) { return Result.fail(new Error("User not found")); } const isAssociated = await authUserRepository.isUserAssociatedWithCompany( userId, companyId, transaction ); if (!isAssociated) { return Result.fail(new Error("User does not have access to this company")); } return Result.ok({ message: "Company selected successfully" }); }); }*/ /** * 馃敼 `logout` * Simula el cierre de sesi贸n de un usuario. No requiere transacci贸n. */ /*static logout(): Result<{ message: string }, never> { return Result.ok({ message: "Logged out successfully" }); }*/ }