Uecko_ERP/apps/server/src/contexts/auth/application/auth.service.ts

162 lines
4.8 KiB
TypeScript
Raw Normal View History

2025-02-01 21:48:13 +00:00
import { Result, UniqueID } from "@common/domain";
import { ITransactionManager } from "@common/infrastructure/database";
import {
2025-02-03 13:12:36 +00:00
AuthenticatedUser,
2025-02-01 21:48:13 +00:00
EmailAddress,
IAuthenticatedUserRepository,
PasswordHash,
Username,
} from "@contexts/auth/domain";
2025-02-03 13:12:36 +00:00
import { IAuthProvider } from "./auth-provider.interface";
2025-02-01 21:48:13 +00:00
import { IAuthService } from "./auth-service.interface";
export class AuthService implements IAuthService {
2025-02-03 18:03:23 +00:00
private readonly _respository!: IAuthenticatedUserRepository;
2025-02-01 21:48:13 +00:00
private readonly _transactionManager!: ITransactionManager;
2025-02-03 13:12:36 +00:00
private readonly _authProvider: IAuthProvider;
2025-02-01 21:48:13 +00:00
2025-02-03 13:12:36 +00:00
constructor(
repository: IAuthenticatedUserRepository,
transactionManager: ITransactionManager,
authProvider: IAuthProvider
) {
2025-02-01 21:48:13 +00:00
this._respository = repository;
this._transactionManager = transactionManager;
2025-02-03 13:12:36 +00:00
this._authProvider = authProvider;
2025-02-01 21:48:13 +00:00
}
2025-01-30 10:45:31 +00:00
/**
2025-02-03 21:54:51 +00:00
*
2025-01-30 10:45:31 +00:00
* Registra un nuevo usuario en la base de datos bajo transacción.
*/
2025-02-01 21:48:13 +00:00
async registerUser(params: {
username: Username;
email: EmailAddress;
2025-02-03 13:12:36 +00:00
passwordHash: PasswordHash;
}): Promise<Result<AuthenticatedUser, Error>> {
try {
return await this._transactionManager.complete(async (transaction) => {
const { username, email, passwordHash } = params;
2025-01-30 10:45:31 +00:00
2025-02-03 13:12:36 +00:00
// 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"));
}
2025-01-30 10:45:31 +00:00
2025-02-03 13:12:36 +00:00
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);
}
2025-01-30 10:45:31 +00:00
}
/**
2025-02-03 21:54:51 +00:00
*
* Autentica a un usuario validando su email y contraseña.
2025-01-30 10:45:31 +00:00
*/
2025-02-03 21:54:51 +00:00
async loginUser(params: {
email: EmailAddress;
passwordHash: PasswordHash;
}): Promise<Result<AuthenticatedUser, Error>> {
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);
}
}
2025-01-30 10:45:31 +00:00
/**
* 🔹 `selectCompany`
* Permite a un usuario seleccionar una empresa activa en la sesión bajo transacción.
*/
2025-02-03 13:12:36 +00:00
/*static async selectCompany(
2025-01-30 10:45:31 +00:00
userId: string,
companyId: string
): Promise<Result<{ message: string }, Error>> {
return await authUserRepository.executeTransaction(async (transaction) => {
const user = await authUserRepository.findById(userId, transaction);
2025-02-03 13:12:36 +00:00
if (user.isFailure) {
2025-01-30 10:45:31 +00:00
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" });
});
2025-02-03 13:12:36 +00:00
}*/
2025-01-30 10:45:31 +00:00
/**
* 🔹 `logout`
* Simula el cierre de sesión de un usuario. No requiere transacción.
*/
2025-02-03 13:12:36 +00:00
/*static logout(): Result<{ message: string }, never> {
2025-01-30 10:45:31 +00:00
return Result.ok({ message: "Logged out successfully" });
2025-02-03 13:12:36 +00:00
}*/
2025-01-30 10:45:31 +00:00
}