115 lines
3.6 KiB
TypeScript
115 lines
3.6 KiB
TypeScript
|
|
import { EmailAddress, PasswordHash, Username } from "contexts/auth/domain";
|
||
|
|
import { authUserRepository } from "contexts/auth/infraestructure/sequelize";
|
||
|
|
import { Result, UniqueID } from "contexts/common/domain";
|
||
|
|
|
||
|
|
export class AuthService {
|
||
|
|
/**
|
||
|
|
* 🔹 `registerUser`
|
||
|
|
* Registra un nuevo usuario en la base de datos bajo transacción.
|
||
|
|
*/
|
||
|
|
static async registerUser(
|
||
|
|
username: string,
|
||
|
|
email: string,
|
||
|
|
password: string
|
||
|
|
): Promise<Result<{ userId: string }, Error>> {
|
||
|
|
return await authUserRepository.executeTransaction(async (transaction) => {
|
||
|
|
const userIdResult = UniqueID.generateNewID();
|
||
|
|
const usernameResult = Username.create(username);
|
||
|
|
const emailResult = EmailAddress.create(email);
|
||
|
|
const passwordResult = await PasswordHash.create(password);
|
||
|
|
|
||
|
|
const combined = Result.combine([userIdResult, usernameResult, emailResult, passwordResult]);
|
||
|
|
if (combined.isError()) {
|
||
|
|
return Result.fail(combined.error);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Verificar si el usuario ya existe
|
||
|
|
const userExists = await authUserRepository.userExists(
|
||
|
|
emailResult.data.getValue(),
|
||
|
|
transaction
|
||
|
|
);
|
||
|
|
if (userExists) {
|
||
|
|
return Result.fail(new Error("Email is already registered"));
|
||
|
|
}
|
||
|
|
|
||
|
|
const user = await authUserRepository.createUser(
|
||
|
|
{
|
||
|
|
id: userIdResult.data.getValue(),
|
||
|
|
username: usernameResult.data.getValue(),
|
||
|
|
email: emailResult.data.getValue(),
|
||
|
|
password: passwordResult.data.getValue(),
|
||
|
|
isActive: true,
|
||
|
|
},
|
||
|
|
transaction
|
||
|
|
);
|
||
|
|
|
||
|
|
return Result.ok({ userId: user.id });
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🔹 `login`
|
||
|
|
* Autentica un usuario y genera un token JWT bajo transacción.
|
||
|
|
*/
|
||
|
|
static async login(
|
||
|
|
email: string,
|
||
|
|
password: string
|
||
|
|
): Promise<Result<{ token: string; userId: string }, Error>> {
|
||
|
|
return await authUserRepository.executeTransaction(async (transaction) => {
|
||
|
|
const emailResult = EmailAddress.create(email);
|
||
|
|
if (emailResult.isError()) {
|
||
|
|
return Result.fail(emailResult.error);
|
||
|
|
}
|
||
|
|
|
||
|
|
const user = await authUserRepository.findByEmail(emailResult.data.getValue(), transaction);
|
||
|
|
if (user.isError()) {
|
||
|
|
return Result.fail(new Error("Invalid email or password"));
|
||
|
|
}
|
||
|
|
|
||
|
|
const isValidPassword = await user.data.validatePassword(password);
|
||
|
|
if (!isValidPassword) {
|
||
|
|
return Result.fail(new Error("Invalid email or password"));
|
||
|
|
}
|
||
|
|
|
||
|
|
const token = JwtHelper.generateToken({ userId: user.data.getUserID() });
|
||
|
|
|
||
|
|
return Result.ok({ token, userId: user.data.getUserID() });
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🔹 `selectCompany`
|
||
|
|
* Permite a un usuario seleccionar una empresa activa en la sesión bajo transacción.
|
||
|
|
*/
|
||
|
|
static async selectCompany(
|
||
|
|
userId: string,
|
||
|
|
companyId: string
|
||
|
|
): Promise<Result<{ message: string }, Error>> {
|
||
|
|
return await authUserRepository.executeTransaction(async (transaction) => {
|
||
|
|
const user = await authUserRepository.findById(userId, transaction);
|
||
|
|
if (user.isError()) {
|
||
|
|
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" });
|
||
|
|
}
|
||
|
|
}
|